*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* METEOR-2-Designsystem (Markenblau #26336a von weger.com): technische,
   datenblattartige Optik mit feinem Raster, dünnen Linien, Montserrat
   für Text und Monospace für Zahlen/Eingaben. Die Variablennamen bleiben
   unverändert, damit alle bestehenden Regeln weiter greifen. */
:root {
    --bg: #eef1f7;
    --bg-grid: #e2e7f1;
    --surface: #ffffff;
    --border: #ccd4e6;
    --border-soft: #e6eaf3;
    --primary: #26336a;
    --primary-dark: #3d54ac;
    --ink-deep: #0f1530;
    --glow: #5b7cf0;
    --success: #1f7a54;
    --warning: #b3541e;
    --danger: #a11f3c;
    --inferred: #6b3fa0;
    --edited: #12715a;
    --text: #131a2e;
    --muted: #4a5673;
    --radius: 2px;
    --shadow: 0 1px 2px rgba(15, 21, 48, .06), 0 8px 24px rgba(15, 21, 48, .06);
    --sans: Montserrat, "Segoe UI", system-ui, sans-serif;
    --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono",
            Consolas, "Liberation Mono", monospace;
}

html {
    height: 100%;
}

body {
    font-family: var(--sans);
    background-color: var(--bg);
    background-image:
        linear-gradient(var(--bg-grid) 1px, transparent 1px),
        linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
    background-size: 32px 32px;
    -webkit-font-smoothing: antialiased;
    color: var(--text);
    line-height: 1.6;
    display: flex;
    flex-direction: column;
    /* Grundfall: min-height, damit lange Seiten ganz normal über das
       Dokument scrollen – nur so bleibt die per position:sticky
       fixierte Nav (Regel weiter unten) auch über die volle Seitenhöhe
       oben kleben (ihr Containing Block ist der Body und muss dafür so
       hoch wie der Inhalt sein). */
    min-height: 100vh;
}

/* Bei geöffnetem PDF-Panel dagegen eine definite Viewport-Höhe: erst
   damit begrenzt .page-shell per Flex-Shrink die innere Spalte
   (.container) wirklich auf die Resthöhe und scrollt sie eigenständig
   – mit reinem min-height würde der Flex-Algorithmus sie bei langem
   Inhalt einfach mitwachsen lassen (CSS-Flexbox-Spec: definite vs.
   min sizes). Die Nav bleibt hier ohnehin oben, weil der Body nicht
   mitscrollt. */
body:has(#pdf-panel.pdf-panel-open) {
    height: 100vh;
}

.container {
    max-width: 960px;
    margin: 0 auto;
    padding: 1.5rem;
    transition: padding-right .25s ease;
}

/* Überschriften in der Markenschrift, technisch eng gesetzt. */
h1, h2, h3, h4, h5 {
    font-family: var(--sans);
    font-weight: 600;
    letter-spacing: -.01em;
    color: var(--text);
}

/* Nav: dunkler Markenbalken (METEOR-Kopfzone), bleibt beim Scrollen oben. */
nav {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--ink-deep);
    color: #fff;
    padding: .75rem 1.5rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
    font-size: .82rem;
    letter-spacing: .04em;
}

nav a {
    color: rgba(255, 255, 255, .82);
    text-decoration: none;
    font-weight: 500;
}

nav a:hover {
    color: #fff;
}

nav .brand {
    font-family: var(--mono);
    font-size: .95rem;
    font-weight: 700;
    letter-spacing: .14em;
    color: #fff;
    display: inline-flex;
    align-items: center;
    gap: .6rem;
}

/* Card */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.5rem;
    box-shadow: var(--shadow);
    margin-bottom: 1rem;
}

.card-title {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: .75rem;
}

/* Parse-Vorschau: abgewählte Positionen ausgegraut, bleiben interaktiv */
.position-card-deselected {
    opacity: .55;
    filter: grayscale(60%);
}

/* Ausgewählte Geräte-Karte: weißer Grund, der Analyse-Zustand zeigt sich
   über die Farbe des linken Balkens (dazu Status-Badge und Button-Farbe).
   Blau = ausgewählt/angefangen, grün = fertig, rot = Fehler. */
.position-card-device {
    border-left: 6px solid var(--primary);
}
.position-card-device.pos-done {
    border-left-color: var(--success);
}
.position-card-device.pos-error {
    border-left-color: var(--danger);
}

/* Zugehörigkeits-Schalter einer Folgeposition (an/aus, ändert NICHT
   die Baumstruktur – nur ob sie im Gerätetext an die KI geht). Bewusst
   als runder Toggle statt Checkbox, damit er nicht mit der
   "ist RLT-Gerät"-Checkbox der Top-Level-Positionen verwechselt wird. */
.lv-toggle {
    position: relative;
    flex: 0 0 auto;
    width: 2.1rem;
    height: 1.2rem;
    border-radius: 999px;
    border: none;
    padding: 0;
    cursor: pointer;
    background: var(--border);
    transition: background .15s;
}
.lv-toggle::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: calc(1.2rem - 4px);
    height: calc(1.2rem - 4px);
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
    transition: transform .15s;
}
.lv-toggle[aria-pressed="true"] {
    background: var(--primary);
}
.lv-toggle[aria-pressed="true"]::after {
    transform: translateX(.9rem);
}

/* Strukturelle Aktion: Folgeposition aus dem Gerät herauslösen und zum
   eigenen RLT-Gerät machen (ändert die Baumgliederung). Als eckiger
   Outline-Akzent-Button klar von Schalter und PDF-Ghost abgesetzt. */
.lv-split-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .25rem .6rem;
    font-size: .72rem;
    font-weight: 600;
    white-space: nowrap;
    color: var(--primary);
    background: transparent;
    border: 1px solid var(--primary);
    border-radius: var(--radius);
    cursor: pointer;
    transition: background .15s, color .15s;
}
.lv-split-btn:hover {
    background: var(--primary);
    color: #fff;
}

/* Verhindert, dass Alpine-gesteuerte Elemente (x-show) vor der
   Initialisierung kurz unstyled aufblitzen. */
[x-cloak] {
    display: none !important;
}

/* Aktiver Scope-Button (Textvorschau: Hauptposition vs. ganzer Abschnitt,
   siehe position_card.html). */
.lv-scope-btn.is-active {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}

/* Badges / Status */
.badge {
    display: inline-block;
    padding: .2rem .6rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 600;
}

.badge-pending,
.badge-not_started {
    background: #e0e7ff;
    color: #3730a3;
}

.badge-parsing,
.badge-detecting,
.badge-identifying,
.badge-extracting,
.badge-warning {
    background: #fef3c7;
    color: #92400e;
}

/* Warteschlange: neutrales Grau, klar abgesetzt vom amberfarbenen
   "wird extrahiert" (aktiv läuft nur eine Komponente, der Rest wartet).
   "Kein RLT-Gerät" ist ebenfalls ein neutraler Sachstand (kein Fehler). */
.badge-queued,
.badge-not_rlt {
    background: #e5e7eb;
    color: #4b5563;
}

.badge-parse_preview,
.badge-detect_preview,
.badge-identify_preview,
.badge-extract_preview {
    background: #dbeafe;
    color: #1e40af;
}

.badge-complete {
    background: #d1fae5;
    color: #065f46;
}

.badge-error,
.badge-detect_error,
.badge-identify_error,
.badge-extract_error {
    background: #fee2e2;
    color: #991b1b;
}

/* Luftseiten: Zuluft rot, Abluft blau. */
.badge-zuluft {
    background: #fee2e2;
    color: #b91c1c;
}

.badge-abluft {
    background: #dbeafe;
    color: #1d4ed8;
}

/* Buttons */
.btn {
    display: inline-block;
    padding: .5rem 1.1rem;
    border-radius: var(--radius);
    border: none;
    cursor: pointer;
    font-size: .9rem;
    font-weight: 500;
    text-decoration: none;
    transition: background .15s, border-color .15s, color .15s;
}

.btn-primary {
    background: var(--primary);
    color: #fff;
}

.btn-primary:hover {
    background: var(--primary-dark);
}

.btn-success {
    background: var(--success);
    color: #fff;
}

.btn-warning {
    background: var(--warning);
    color: #fff;
}

.btn-danger {
    background: var(--danger);
    color: #fff;
}

/* Sekundäre Aktion (z. B. Zurück/Weiter im Seitenkopf): weiße Fläche
   mit blauer Schrift, damit sie sich klar vom Raster-Hintergrund
   abhebt und als anklickbar erkennbar ist. */
.btn-ghost {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--primary);
    font-weight: 600;
    box-shadow: var(--shadow);
}

.btn-ghost:hover {
    border-color: var(--primary);
    color: var(--primary-dark);
}

/* Abmelden-Button im blauen Nav-Balken: weiße Schrift/Rahmen,
   gefüllt beim Hover. Kleiner als Standard-Buttons. */
.nav-logout {
    padding: .25rem .7rem;
    font-size: .8rem;
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .7);
    color: #fff;
}

.nav-logout:hover {
    background: #fff;
    color: var(--primary);
}

.btn:disabled {
    opacity: .5;
    cursor: not-allowed;
}

/* Primäre Positions-Aktion: füllt die volle Höhe ihrer Spalte
   (siehe .flex-stretch) und fällt durch Farbe/Pfeil sofort auf. */
.btn-full {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .3rem;
    width: 100%;
    border: none;
    border-radius: var(--radius);
    cursor: pointer;
    color: #fff;
    text-decoration: none;
    text-align: center;
    padding: .75rem .6rem;
    transition: filter .15s, transform .1s;
}

.btn-full:hover {
    filter: brightness(1.08);
}

.btn-full:active {
    transform: scale(.98);
}

.btn-full:disabled {
    opacity: .5;
    cursor: not-allowed;
    filter: none;
    transform: none;
}

.btn-full-warning {
    background: var(--warning);
}

.btn-full-success {
    background: var(--success);
}

/* Start-Aktion für noch nicht analysierte Geräte: Markenblau als klare
   Primäraktion („das ist zu tun"), deutlich abgesetzt vom grünen
   „Öffnen" bereits analysierter Geräte. */
.btn-full-primary {
    background: var(--primary);
}

/* Vollbreiter, aber neutraler Button – gleichwertige Alternative neben
   einer farbigen Primäraktion (z. B. „Trotzdem als PDF"). */
.btn-full-outline {
    background: #fff;
    color: var(--text);
    border: 1px solid var(--border);
}

.btn-full-outline:hover {
    filter: none;
    background: #f8fafc;
}

.btn-full-label {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .95rem;
    font-weight: 600;
}

.btn-full-arrow {
    font-size: 1.2rem;
    line-height: 1;
}

.btn-full-caption {
    font-size: .68rem;
    font-weight: 400;
    opacity: .9;
}

/* Hebt im "Erkennung → Identifikation"-Mini-Fortschritt hervor, auf
   welcher der beiden Seiten man sich gerade befindet (siehe
   geraet_progress.html). Rahmen ist immer reserviert (nur die Farbe
   wechselt), damit das Hervorheben keinen Layout-Sprung verursacht. */
.geraet-step {
    padding: .1rem .4rem;
    border-radius: var(--radius);
    border: 1px dashed transparent;
}

.geraet-step-current {
    border-color: var(--primary);
}

/* Eigene, immer vorhandene Spalte links vom Wert: reserviert Platz,
   damit alle Werte einer Liste unabhängig von der Feldnamen-Länge
   auf derselben Position beginnen. Nur bei berechneten Feldern
   gefüllt. */
.param-row-calc-flag {
    flex: 0 0 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
}

.param-row-calc-flag.is-calculated {
    border-radius: 50%;
    background: #dbeafe;
    color: #1d4ed8;
    font-size: .65rem;
    font-weight: 700;
    cursor: help;
}

/* Erklärtext zu einem Parameter: kein eigenes Icon, Cursor zeigt
   an, dass Hover einen Hilfetext einblendet. */
.param-row-label-text[data-tip] {
    cursor: help;
}

/* Feldname fett + etwas größer: Wert muss manuell in der
   Kalkulationssoftware eingetragen werden. Das Gegenstück
   (.param-row-label-calculated) tritt bewusst kleiner/blasser
   zurück, damit der Unterschied auch ohne Farbe klar auffällt. */
.param-row-label-text.param-row-label-input {
    font-weight: 800;
    font-size: 1.05rem;
}

.param-row-label-text.param-row-label-calculated {
    font-weight: 400;
    font-size: .82rem;
    color: var(--muted);
}

/* Info-Tooltip: kleines "i"-Icon, Erklärtext erscheint sofort beim
   Hover (kein Warten wie beim nativen title-Attribut). */
.info-tip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    border-radius: 50%;
    background: var(--border);
    color: var(--muted);
    font-size: .65rem;
    font-weight: 700;
    font-style: italic;
    line-height: 1;
    cursor: help;
    vertical-align: middle;
}

/* Der Erklärtext wird per JS als einziges, an <body> gehängtes
   Element (position:fixed) dargestellt statt als ::after des Icons.
   Nur so kann ihn kein Vorfahre mit overflow (z. B. .container bei
   offenem PDF-Panel) abschneiden; der hohe z-index hält ihn über
   allem anderen. */
.info-tip-pop {
    position: fixed;
    z-index: 1000;
    width: max-content;
    max-width: 520px;
    background: var(--text);
    color: #fff;
    padding: .45rem .65rem;
    border-radius: 6px;
    font-size: .72rem;
    font-weight: 400;
    font-style: normal;
    line-height: 1.4;
    text-align: left;
    white-space: pre-line;
    box-shadow: var(--shadow);
    opacity: 0;
    visibility: hidden;
    transition: opacity .1s ease;
    pointer-events: none;
}

.info-tip-pop.is-visible {
    opacity: 1;
    visibility: visible;
}

/* Startseite: zwei Upload-Modi (Einzelschritte / Autonom) */
.upload-modi { display: grid; gap: .6rem; }
.upload-modus {
    display: grid;
    grid-template-columns: 11rem minmax(0, 1fr);
    gap: .75rem;
    align-items: center;
}
.upload-modus .btn { width: 100%; }
@media (max-width: 600px) {
    .upload-modus { grid-template-columns: minmax(0, 1fr); gap: .3rem; }
}
.btn-autonom {
    background: var(--success);
    color: #fff;
}
.btn-autonom:hover:not(:disabled) { filter: brightness(1.1); }
.upload-modus .btn:disabled { opacity: .5; cursor: not-allowed; }

/* Autonomer Modus: Fortschritt auf der Job-Seite */
.autonom-kopf { display: flex; align-items: center; gap: .5rem; margin-bottom: .6rem; }
.autonom-titel { font-weight: 600; }
.autonom-balken {
    height: 6px;
    background: var(--border-soft);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: .6rem;
}
.autonom-balken > div { height: 100%; background: var(--success); transition: width .4s; }
.autonom-liste { list-style: none; margin-top: .6rem; display: grid; gap: .25rem; font-size: .85rem; }
.autonom-zustand {
    display: inline-block;
    min-width: 7.5rem;
    font-size: .75rem;
    font-weight: 600;
}
.autonom-laeuft { color: var(--primary-dark); }
.autonom-fertig { color: var(--success); }
.autonom-fehler { color: var(--danger); }
.autonom-kein_rlt, .autonom-offen { color: var(--muted); }

/* Startseite: Upload + Jobs links, Neuigkeiten rechts */
.container:has(> .start-layout) {
    max-width: 1280px;
}
.start-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 1.5rem;
    align-items: start;
}
.start-aside {
    position: sticky;
    top: 1rem;
    margin-top: 1.5rem;
}
@media (max-width: 1000px) {
    .start-layout { grid-template-columns: minmax(0, 1fr); }
    .start-aside { position: static; margin-top: 0; }
}
.neuigkeiten { font-size: .85rem; }
.neuigkeiten-version {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .4rem;
    padding-bottom: .6rem;
    margin-bottom: .6rem;
    border-bottom: 1px solid var(--border-soft);
}
.neuigkeiten-label {
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
}
.neuigkeiten-nummer {
    font-family: var(--mono);
    font-weight: 700;
    color: var(--primary);
}
.neuigkeiten-neu {
    margin-left: auto;
    padding: 0 .45rem;
    border-radius: 999px;
    background: var(--warning);
    color: #fff;
    font-size: .7rem;
    font-weight: 700;
}
.neuigkeiten-titel { font-weight: 600; margin-bottom: .4rem; }
.neuigkeiten-liste {
    margin: 0 0 .6rem 1.1rem;
    display: grid;
    gap: .35rem;
    line-height: 1.4;
}
.neuigkeiten-frueher > summary {
    cursor: pointer;
    color: var(--primary-dark);
    font-weight: 500;
}
.neuigkeiten-datum {
    margin: .7rem 0 .3rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--muted);
}

/* Projektkarte (Job-Seite) */
.project-card details > summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}
.project-card details > summary::-webkit-details-marker { display: none; }
.project-label {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--muted);
}
.project-name {
    font-weight: 600;
    min-width: 0;
    overflow-wrap: anywhere;
}
.project-chip {
    font-size: .78rem;
    padding: .1rem .5rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--muted);
    white-space: nowrap;
}
.project-chip-date {
    border-color: var(--primary);
    color: var(--primary);
    font-weight: 600;
}
.project-edit {
    margin-left: auto;
    font-size: .8rem;
    color: var(--primary-dark);
}
.project-card details[open] .project-edit { visibility: hidden; }
.project-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
    gap: 0 1rem;
    margin-top: 1rem;
}
.project-form .form-group { margin-bottom: .75rem; }
.project-form-wide { grid-column: 1 / -1; }
.project-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}
.ki-badge {
    display: inline-block;
    margin-left: .3rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: #e0e7ff;
    color: var(--primary-dark);
    font-size: .65rem;
    font-weight: 700;
    vertical-align: middle;
    cursor: help;
}

/* Form */
.form-group {
    margin-bottom: 1rem;
}

label {
    display: block;
    font-weight: 500;
    margin-bottom: .3rem;
}

input[type="text"],
input[type="password"],
input[type="date"],
input[type="file"],
select,
textarea {
    width: 100%;
    padding: .5rem .75rem;
    border: 1px solid var(--border);
    border-bottom-width: 2px;
    border-radius: var(--radius);
    font-family: var(--mono);
    font-size: .9rem;
    transition: border-color .12s, box-shadow .12s;
}

textarea {
    font-family: var(--sans);
}

input[type="text"]:focus,
input[type="password"]:focus,
input[type="date"]:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--primary);
    border-bottom-color: var(--primary-dark);
    box-shadow: 0 0 0 3px rgba(61, 84, 172, .18);
}

input[type="file"] {
    padding: .4rem;
}

/* Alert */
.alert {
    padding: .75rem 1rem;
    border-radius: var(--radius);
    margin-bottom: 1rem;
}

.alert-error {
    background: #fee2e2;
    color: #991b1b;
    border: 1px solid #fca5a5;
}

.alert-info {
    background: #dbeafe;
    color: #1e40af;
    border: 1px solid #93c5fd;
}

.alert-success {
    background: #d1fae5;
    color: #065f46;
    border: 1px solid #6ee7b7;
}

.alert-warning {
    background: #fef3c7;
    color: #78350f;
    border: 1px solid #fcd34d;
}

/* Blau getönter Block für die gemeinsame Vorbemerkung. Der linke Balken
   ist bewusst hellgrau (nicht in einer Zustandsfarbe), damit sich der
   Kontext-Block von den Geräte-Karten abhebt (siehe
   partials/preamble_block.html). */
.seg-preamble { border-left: 6px solid #7b869f; background: #eff6ff; }

/* Progress */
.progress-bar {
    height: 6px;
    background: var(--border);
    border-radius: 99px;
    overflow: hidden;
    margin: .5rem 0;
}

.progress-fill {
    height: 100%;
    background: var(--primary);
    border-radius: 99px;
    transition: width .3s;
}

/* Breiten-Raster in 5%-Schritten (siehe lv_extras.width_class) statt
   dynamischem style="width:...%", das Editor-CSS-Linter an
   Django-Template-Syntax in style-Attributen scheitern lässt. */
.w-0 { width: 0%; }
.w-5 { width: 5%; }
.w-10 { width: 10%; }
.w-15 { width: 15%; }
.w-20 { width: 20%; }
.w-25 { width: 25%; }
.w-30 { width: 30%; }
.w-35 { width: 35%; }
.w-40 { width: 40%; }
.w-45 { width: 45%; }
.w-50 { width: 50%; }
.w-55 { width: 55%; }
.w-60 { width: 60%; }
.w-65 { width: 65%; }
.w-70 { width: 70%; }
.w-75 { width: 75%; }
.w-80 { width: 80%; }
.w-85 { width: 85%; }
.w-90 { width: 90%; }
.w-95 { width: 95%; }
.w-100 { width: 100%; }

/* Upload Zone */
.upload-zone {
    border: 2px dashed var(--border);
    border-radius: var(--radius);
    padding: 2.5rem;
    text-align: center;
    cursor: pointer;
    transition: border-color .2s, background .2s;
}

.upload-zone:hover,
.upload-zone.drag-over {
    border-color: var(--primary);
    background: #eff6ff;
}

.upload-zone input[type="file"] {
    display: none;
}

/* Table */
table {
    width: 100%;
    border-collapse: collapse;
    font-size: .85rem;
}

th,
td {
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--border);
    text-align: left;
}

th {
    font-family: var(--mono);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    background: var(--bg);
}

/* Code */
pre,
code {
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: .82rem;
}

pre {
    background: #1e293b;
    color: #e2e8f0;
    padding: 1rem;
    border-radius: var(--radius);
    overflow: auto;
    max-height: 300px;
}

/* Log */
.log-list {
    list-style: none;
    font-size: .8rem;
    color: var(--muted);
    max-height: 200px;
    overflow-y: auto;
}

.log-list li::before {
    content: "▸ ";
}

/* Utils */
.flex {
    display: flex;
    gap: .75rem;
    align-items: center;
    flex-wrap: wrap;
}

.flex-between {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
}

/* Zweispaltiges Karten-Layout: rechte Spalte (primäre Aktion) nimmt
   per align-items:stretch immer die volle Höhe der linken Spalte
   ein, unabhängig vom Inhalt (siehe openspec design.md D3 der
   Change parse-preview-status-redesign). Bewusst kein
   align-items:center wie bei .flex-between. */
.flex-stretch {
    display: flex;
    align-items: stretch;
    gap: .75rem;
}

.mt-1 {
    margin-top: .5rem;
}

.mt-2 {
    margin-top: 1rem;
}

.mt-3 {
    margin-top: 1.5rem;
}

.text-muted {
    color: var(--muted);
}

.text-sm {
    font-size: .85rem;
}

.text-success {
    color: var(--success);
}

.text-warning {
    color: var(--warning);
}

.text-danger {
    color: var(--danger);
}

/* Eigene Farbe für hergeleitete (inferred) Werte statt warning/orange */
.text-inferred {
    color: var(--inferred);
}

/* Manuell bearbeiteter Wert: eigener, etwas anderer Grünton als das
   Standard-Grün (success), signalisiert "vom Menschen bestätigt". */
.text-edited {
    color: var(--edited);
}

/* Wert per Klick bearbeitbar: dezente Affordanz. Der Stift sitzt in
   einer links davor reservierten, fest breiten Spur und wird nur beim
   Hover sichtbar – so verschieben sich weder der Wert noch die Tooltips
   rechts davon, wenn der Stift erscheint. */
.js-param-edit {
    cursor: text;
    border-radius: 3px;
    padding: 0 .1rem;
    transition: background .1s ease;
}
.js-param-edit::before {
    content: "✎";
    display: inline-block;
    width: 1em;
    margin-right: .1rem;
    font-size: .8em;
    text-decoration: none;
    opacity: 0;
    transition: opacity .1s ease;
}
.js-param-edit:hover {
    background: #eef2ff;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
}
.js-param-edit:hover::before {
    opacity: .55;
}
.param-edit-input {
    font: inherit;
    font-weight: 600;
    padding: .1rem .35rem;
    border: 1px solid var(--primary);
    border-radius: 4px;
    min-width: 5rem;
    max-width: 100%;
}

/* Komponententyp per Klick umbenennbar (komponente_card.html) –
   gleiche Affordanz wie .js-param-edit oben, eigener Selektor, da
   Aufruf/Ziel-Element abweichen. */
.js-komptype-edit {
    cursor: text;
    border-radius: 3px;
    padding: 0 .1rem;
    transition: background .1s ease;
}
.js-komptype-edit::before {
    content: "✎";
    display: inline-block;
    width: 1em;
    margin-right: .1rem;
    font-size: .8em;
    text-decoration: none;
    opacity: 0;
    transition: opacity .1s ease;
}
.js-komptype-edit:hover {
    background: #eef2ff;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
}
.js-komptype-edit:hover::before {
    opacity: .55;
}

.bg-success {
    background: var(--success);
}

.bg-warning {
    background: var(--warning);
}

.bg-danger {
    background: var(--danger);
}

.htmx-indicator {
    display: none;
}

.htmx-request .htmx-indicator {
    display: inline;
}

/* PDF-Viewer: ausklappbare zweite Spalte (Change pdf-viewer-geraete-
   abschnitt). .page-shell umschließt den bestehenden .container
   unverändert plus das neue #pdf-panel; Breite/Transition regeln
   allein .pdf-panel-open (Auf-/Zu-Zustand), der Rest des Layouts
   bleibt von dieser Erweiterung unberührt.

   :has() statt einer zusätzlichen JS-getoggelten Klasse: erspart
   eine zweite Stelle, die mit .pdf-panel-open synchron gehalten
   werden müsste. */
.page-shell {
    display: flex;
    align-items: stretch;
}

/* Nur bei GEÖFFNETEM Panel an den Viewport gebunden, damit
   Hauptinhalt und PDF-Panel unabhängig voneinander scrollen können.
   Bewusst nicht schon bei bloßer Anwesenheit von #pdf-panel (auch
   im eingeklappten Zustand, wo das Panel nur unsichtbar/Breite 0
   im Markup steht): sonst würde die Scrollbar der zentrierten
   960px-Spalte statt der ganzen Seite gehören, und Scrollen
   außerhalb dieser Spalte (im leeren Rand links/rechts) täte
   nichts mehr – eingeklappt soll die Seite ganz normal als
   Dokument scrollen, wie vor dieser Änderung. */
.page-shell:has(>#pdf-panel.pdf-panel-open) {
    flex: 1 1 auto;
    min-height: 0;
}

.page-shell>.container {
    flex: 1 1 auto;
    min-width: 0;
}

.page-shell:has(>#pdf-panel.pdf-panel-open)>.container {
    overflow-y: auto;
    /* overflow-x explizit hidden: ohne das erzwingt die Spec bei
       gesetztem overflow-y (≠ visible) automatisch overflow-x:auto
       auf der anderen Achse – dadurch entstand hier dauerhaft eine
       waagrechte Scrollleiste, sobald Tabelleninhalt die (bei
       geöffnetem Panel auf max-width:960px gedeckelte) Spalte auch
       nur um Subpixel überragte. Eine echte waagrechte Scrollbar
       ist für diese Spalte nie gewollt. */
    overflow-x: hidden;
    padding-right: .5rem;
}

/* max-width bewusst NICHT bei geöffnetem Panel aufgehoben (frühere
   Fassung: `max-width:none`/ein großer Ersatzwert): das ließ sich
   nur unsauber synchron zur wachsenden Panel-Breite animieren –
   `max-width` und die verfügbare Restbreite laufen unabhängig
   voneinander, jede eigene CSS-Transition folgt ihrer eigenen
   Start-Ziel-Kurve statt sich am jeweils anderen Wert zu
   orientieren. Ergebnis war ein kurzes Verbreitern der Tabelle
   beim Öffnen, bevor die wachsende Panel-Breite sie wieder
   schmaler drückt (genau das gemeldete Problem). In der Praxis
   bleibt die verfügbare Restbreite bei geöffnetem Panel (~breite
   * 0,52) meist ohnehin unter 960px – der Cap greift dann gar
   nicht erst, kein zusätzliches "luft" durch Zentrierung. Nur bei
   sehr breiten Fenstern (Restbreite > 960px) bleibt die Spalte
   weiterhin zentriert; als Kompromiss für eine ruckelfreie
   Animation akzeptiert. */

.pdf-panel-toggle {
    position: fixed;
    top: 5.5rem;
    right: 0;
    z-index: 30;
    border: none;
    border-radius: var(--radius) 0 0 var(--radius);
    background: var(--primary);
    color: #fff;
    box-shadow: var(--shadow);
    padding: .5rem .6rem;
    cursor: pointer;
    font-size: 1.3rem;
    line-height: 1;
    transition: background .15s;
}

.pdf-panel-toggle:hover {
    background: var(--primary-dark);
}

/* Der schwebende 📄-Button dient nur zum ÖFFNEN. Bei geöffnetem Panel
   übernimmt der "Einklappen"-Button in der Panel-Kopfzeile das
   Schließen; der schwebende Button entfällt dann, damit zwischen
   Hauptinhalt und Panel kein Platz verloren geht und die Spalten
   direkt aneinander anschließen. */
.page-shell:has(>#pdf-panel.pdf-panel-open) .pdf-panel-toggle {
    display: none;
}

#pdf-panel {
    position: relative;
    flex: 0 0 0;
    width: 0;
    min-width: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-left: 0 solid var(--border);
    transition: width .25s ease, flex-basis .25s ease;
}

/* Während des Ziehens keine Breiten-Transition, sonst hinkt das Panel
   dem Mauszeiger hinterher. */
#pdf-panel.pdf-panel-resizing {
    transition: none;
}

/* Geschlossenes Panel auf Höhe 0 zwingen: der PDF-Inhalt bleibt nach
   dem Schließen im DOM. Bei geschlossenem Panel ist .page-shell NICHT
   an die Viewport-Höhe gebunden (siehe :has()-Regel oben), also würde
   der (nur horizontal per width:0/overflow:hidden geklippte, vertikal
   weiterhin volle) Inhalt über align-items:stretch die Höhe der
   Flex-Zeile und damit die gesamte Seitenhöhe auf die PDF-Länge
   aufblähen – man könnte weit ins Leere scrollen. Height 0 nimmt den
   geklippten Inhalt aus der Höhenberechnung; im geöffneten Zustand
   greift die Regel dank :not() nicht. */
#pdf-panel:not(.pdf-panel-open) {
    height: 0;
}

#pdf-panel.pdf-panel-open {
    flex: 0 0 var(--pdf-panel-width, 48%);
    width: var(--pdf-panel-width, 48%);
    min-width: 380px;
    border-left-width: 1px;
}

/* Ziehgriff an der linken Panel-Kante zum Einstellen der Breite.
   Absolut positioniert, verändert das Flex-Layout nicht; nur bei
   geöffnetem Panel (Breite > 0) sichtbar/erreichbar. Breite
   Grifffläche für leichtes Treffen mit der Maus. */
.pdf-panel-resizer {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 12px;
    z-index: 5;
    cursor: col-resize;
    touch-action: none;
}

/* Durchgehende, dezent sichtbare Kantenlinie als Hinweis, dass hier
   die Grenze zwischen den Spalten liegt. */
.pdf-panel-resizer::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--border);
    transition: background .15s;
}

/* Zentraler Greifer, damit sofort klar ist, dass die Kante ziehbar
   ist (dauerhaft dezent sichtbar, beim Hover/Ziehen hervorgehoben). */
.pdf-panel-resizer::after {
    content: "";
    position: absolute;
    left: 1px;
    top: 50%;
    transform: translateY(-50%);
    width: 5px;
    height: 34px;
    border-radius: 3px;
    background: var(--border);
    transition: background .15s;
}

.pdf-panel-resizer:hover::before,
#pdf-panel.pdf-panel-resizing .pdf-panel-resizer::before,
.pdf-panel-resizer:hover::after,
#pdf-panel.pdf-panel-resizing .pdf-panel-resizer::after {
    background: var(--primary);
}

/* Während des Ziehens dokumentweit Textauswahl unterbinden und den
   col-resize-Cursor erzwingen. */
body.pdf-resizing,
body.pdf-resizing * {
    user-select: none !important;
    cursor: col-resize !important;
}

.pdf-panel-header {
    flex: 0 0 auto;
    padding: .5rem 1rem;
    border-bottom: 1px solid var(--border);
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem 1.25rem;
    flex-wrap: wrap;
}

.pdf-panel-note {
    min-width: 0;
}

.pdf-panel-header-actions {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem .85rem;
    flex: 0 0 auto;
}

.pdf-zoom {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    flex: 0 0 auto;
}

.pdf-page-indicator {
    flex: 0 0 auto;
    font-size: .8rem;
    font-weight: 500;
    color: var(--muted);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.pdf-page-indicator:empty {
    display: none;
}

/* Einklapp-Schaltfläche in der Kopfzeile: mit Text beschriftet, damit
   klar ist, dass sie die PDF-Spalte schließt. Der Doppelpfeil zeigt
   nach rechts – in die Richtung, in die das Panel verschwindet. */
.pdf-panel-collapse {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    height: 1.9rem;
    padding: 0 .6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: .8rem;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
}

.pdf-panel-collapse:hover {
    border-color: var(--muted);
    background: var(--card);
}

.pdf-panel-collapse-icon {
    font-size: 1rem;
    line-height: 1;
}

/* Pin-Nadel neben „Einklappen“: ausgegraut = nicht angeheftet (PDF bleibt beim
   Seitenwechsel zu), farbig = angeheftet (öffnet sich auf jeder Seite) */
.pdf-panel-pin { padding: 0 .5rem; filter: grayscale(1); opacity: .55; }
.pdf-panel-pin:hover { opacity: .85; }
.pdf-panel-pin.pdf-panel-pin-an { filter: none; opacity: 1; border-color: var(--accent, #1e3a8a);
    background: rgba(30, 58, 138, .08); }

/* Öffnet die reine Extraktions-PDF (ohne Markierungen) in einem neuen
   Tab; per JS auf die aktuell betrachtete Seite (#page=N) gesetzt. */
.pdf-open-tab {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    height: 1.9rem;
    padding: 0 .6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: .8rem;
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
}

.pdf-open-tab:hover {
    border-color: var(--muted);
    background: var(--card);
}

.pdf-open-tab-icon {
    font-size: 1rem;
    line-height: 1;
}

.pdf-zoom-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.9rem;
    height: 1.9rem;
    padding: 0 .5rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.pdf-zoom-btn:hover {
    border-color: var(--muted);
}

.pdf-zoom-fit {
    font-size: .8rem;
    font-weight: 500;
}

.pdf-zoom-level {
    min-width: 3rem;
    text-align: center;
    font-weight: 500;
    font-size: .85rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.pdf-panel-message {
    flex: 0 0 auto;
}

.pdf-panel-message .alert {
    margin: .75rem 1rem 0;
}

.pdf-quote-fallback {
    margin-top: .4rem;
    font-style: italic;
    white-space: pre-wrap;
}

/* Komponenten-Annotation: Farb-Swatch als Ein/Aus-Toggle. */
.ann-toggle {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    padding: .2rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--card);
    cursor: pointer;
}

.ann-toggle:hover {
    border-color: var(--muted);
}

.ann-swatch {
    display: inline-block;
    width: .95rem;
    height: .95rem;
    border-radius: 3px;
    border: 1px solid var(--border);
}

/* Ausgeblendet: leeres (nur umrandetes) Kästchen statt Farbe. */
.ann-toggle.ann-off {
    opacity: .6;
}

.ann-toggle.ann-off .ann-swatch {
    background-image: none !important;
    background-color: var(--bg) !important;
}

.pdf-panel-body {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: auto;
    /* Reserviert die Breite der vertikalen Scrollbar von Anfang an
       fest, statt sie erst beim tatsächlichen Überlaufen
       einzublenden. Ohne das misst loader.js (mount(), Skalierung
       über container.clientWidth) die Breite BEVOR die Scrollbar
       erscheint – das Ergebnis wird dann ein paar Pixel zu breit
       gerendert, sobald die Scrollbar nachträglich doch auftaucht
       (z. B. weil mehrseitige PDFs die Panel-Höhe überschreiten).
       Anders als bei .container oben ist hier overflow-x:hidden
       keine Option: Bei kleinem Fenster/MIN_SCALE-Untergrenze
       braucht die Seite dann echt eine waagrechte Scrollbar,
       statt rechts einfach abgeschnitten zu werden. */
    scrollbar-gutter: stable;
    position: relative;
    padding: .5rem;
}

/* Eine gerenderte PDF-Seite (Platzhalter in loader.js, Höhe/Breite
   werden dort inline aus page.getViewport() gesetzt). --scale-factor
   wird pro Seite inline auf die aktuelle Zoom-Skala gesetzt; der
   Text-Layer skaliert seine Spans darüber (siehe .textLayer). */
.pdf-page {
    position: relative;
    margin: 0 auto .75rem;
    background: #fff;
    box-shadow: var(--shadow);
    --scale-factor: 1;
    --user-unit: 1;
    --total-scale-factor: calc(var(--scale-factor) * var(--user-unit));
}

/* Stapelreihenfolge einer Seite: Canvas (Bild) unten, die
   Hervorhebungen darüber (tönen den Text im Bild), der selektierbare
   Text-Layer ganz oben (fängt die Maus für Markieren/Kopieren ab,
   seine Spans sind transparent). */
.pdf-page > canvas {
    display: block;
    width: 100%;
    height: 100%;
    position: relative;
    z-index: 1;
}

/* Hervorhebung des vom Parser verwendeten Textbereichs
   (highlights.js setzt nur Position/Größe inline). */
/* mix-blend-mode: multiply statt einer flachen Alpha-Fläche: eine
   normale halbtransparente Fläche aufgehellt/verwaschen auch den
   schwarzen Text darunter (schwerer lesbar, siehe Nutzer-Feedback).
   Multiply lässt dunkle Textpixel praktisch unverändert (Schwarz ×
   irgendetwas bleibt Schwarz) und tönt nur den hellen Hintergrund –
   genau der "Textmarker"-Effekt, den echte Hervorhebungsstifte auf
   Papier auch haben. */
.pdf-highlight {
    position: absolute;
    background: rgba(250, 204, 21, .55);
    mix-blend-mode: multiply;
    border-radius: 2px;
    pointer-events: none;
    z-index: 2;
}

/* Grenzlinie für Anfang/Ende des Geräteabschnitts (Identifikations-
   Ansicht). Neutrales, kräftiges Dunkelgrau, damit sie sich klar von
   den bunten, halbtransparenten Komponenten-Markierungen absetzt und
   nicht selbst wie eine Komponente wirkt. highlights.js setzt nur die
   y-Position inline. Über dem Text-Layer, aber pointer-events:none –
   stört Markieren/Kopieren nicht. */
.pdf-marker {
    position: absolute;
    left: 0;
    width: 100%;
    height: 0;
    border-top: 2px solid #334155;
    pointer-events: none;
    z-index: 4;
}

.pdf-marker-label {
    position: absolute;
    left: 0;
    top: 0;
    transform: translateY(-50%);
    background: #334155;
    color: #fff;
    font-size: .7rem;
    font-weight: 600;
    line-height: 1;
    padding: .15rem .4rem;
    border-radius: 0 3px 3px 0;
    white-space: nowrap;
}

/* Selektierbarer Text-Layer (pdf.js). Übernommen aus dem offiziellen
   pdf_viewer.css von pdfjs-dist 5.6.205, auf den eigenen Viewer
   beschränkt. Die Spans sind transparent und liegen über dem Canvas;
   sichtbar wird nur die Selektion. */
.pdf-panel-body .textLayer {
    position: absolute;
    text-align: initial;
    inset: 0;
    overflow: clip;
    opacity: 1;
    line-height: 1;
    text-size-adjust: none;
    forced-color-adjust: none;
    transform-origin: 0 0;
    caret-color: CanvasText;
    z-index: 3;
    --min-font-size: 1;
    --text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));
    --min-font-size-inv: calc(1 / var(--min-font-size));
}

.pdf-panel-body .textLayer :is(span, br) {
    color: transparent;
    position: absolute;
    white-space: pre;
    cursor: text;
    transform-origin: 0% 0%;
    user-select: text;
}

.pdf-panel-body .textLayer > :not(.markedContent),
.pdf-panel-body .textLayer .markedContent span:not(.markedContent) {
    z-index: 1;
    --font-height: 0;
    font-size: calc(var(--text-scale-factor) * var(--font-height));
    --scale-x: 1;
    --rotate: 0deg;
    transform: rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
}

.pdf-panel-body .textLayer .markedContent {
    display: contents;
}

.pdf-panel-body .textLayer span[role="img"] {
    user-select: none;
    cursor: default;
}

.pdf-panel-body .textLayer ::selection {
    background: rgba(0, 0, 255, .25);
    background: color-mix(in srgb, AccentColor, transparent 50%);
    color: transparent;
}

.pdf-panel-body .textLayer br::selection {
    background: transparent;
}

.pdf-panel-body .textLayer .endOfContent {
    display: block;
    position: absolute;
    inset: 100% 0 0;
    z-index: 0;
    cursor: default;
    user-select: none;
}

.pdf-panel-body .textLayer.selecting .endOfContent {
    top: 0;
}

/* Parameterzeilen (Komponenten-Detailseite, Change
   komponenten-parameter-darstellung). flex-basis statt fester
   Breiten (Vorbereitung für ein künftiges 2-Spalten-Layout, siehe
   design.md), bricht bei schmalen Fensterbreiten um. */
.param-list {
    display: flex;
    flex-direction: column;
}

.param-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .3rem .75rem;
    padding: .4rem 0;
    border-bottom: 1px solid var(--border);
}

.param-row:last-child {
    border-bottom: none;
}


.param-row-label {
    /* 11.5rem statt 13rem: das längste Katalog-Label ("Umluftklappe -
       Öffnungsgröße Breite") braucht nach der ALL-CAPS-Bereinigung
       (HEIZBETRIEB/KÜHLBETRIEB/SOMMER/WINTER → Heizen/Kühlen/Sommer/
       Winter) spürbar weniger Breite; die Wertspalte rückt dadurch
       etwas weiter nach links. */
    flex: 1 1 11.5rem;
    min-width: 0;
    color: #0f172a;
    font-weight: 600;
    font-size: .85rem;
}

/* Kleiner Zusatz unter dem Parameternamen (z. B. zugehörige Komponente). */
.param-row-sublabel {
    display: block;
    margin-top: .1rem;
    font-weight: 400;
    font-size: .78rem;
    color: var(--muted);
}

.param-row-value {
    flex: 1.7 1 12rem;
    min-width: 0;
    word-break: break-word;
}

/* Sprung zur PDF-Fundstelle. Aktiv (Zitat vorhanden): blau gefüllt +
   Rahmen, lädt sichtbar zum Klick ein. Deaktiviert (kein Zitat / nicht
   extrahiert): blass, gestrichelter Rahmen – klar als nicht anklickbar
   erkennbar, nicht nur halbtransparent. */
/* Rechtsbündiger Aktionsblock einer Parameterzeile: Bestätigen/
   Verwerfen (oder dessen unsichtbarer Platzhalter) + Melde-Flagge +
   PDF-Sprung. FESTE Breite statt "auto": Der Block sitzt VOR der
   Wert-Spalte im Flex-Fluss (flex-grow verteilt freien Platz auf
   Label+Wert), eine inhaltsabhängige Breite hier würde deshalb bei
   jeder kleinen Content-Änderung (Bestätigen-Button vs. Platzhalter,
   Schriftart noch nicht geladen o.ä.) die Wert-Spalte aller Zeilen
   nach links/rechts verschieben – genau das beobachtete Alignment-
   Problem. Mit fester Breite kann das nicht mehr passieren. Breite
   großzügig bemessen (drei Buttons + 2 Gaps passen komfortabel
   hinein); margin-left:auto bleibt als Absicherung, falls doch mal
   weniger Inhalt vorkommt. */
.param-row-actions {
    flex: 0 0 7.5rem;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: .35rem;
}

.param-row-jump {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: .12rem .5rem;
    font-size: .85rem;
    line-height: 1.5;
    border-radius: var(--radius);
    cursor: pointer;
    background: #dbeafe;
    color: var(--primary-dark);
    border: 1px solid var(--primary-dark);
    transition: background .15s;
}

/* Melde-Flagge je Parameterzeile: dezent, wird beim Hover rot. */
.param-row-flag {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: .12rem .5rem;
    font-size: .85rem;
    line-height: 1.5;
    border-radius: var(--radius);
    cursor: pointer;
    background: transparent;
    color: var(--muted);
    border: 1px solid var(--border);
    transition: background .15s, color .15s, border-color .15s;
}

.param-row-flag:hover {
    background: #fee2e2;
    color: var(--danger);
    border-color: var(--danger);
}

/* Bestätigen-Umschalter je Parameterzeile: hohl = "bestätigen", beim
   Hover grün; .is-confirmed = bestätigt (gefüllt grün, Klick hebt auf). */
.param-row-confirm {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: .12rem .5rem;
    font-size: .85rem;
    line-height: 1.5;
    border-radius: var(--radius);
    cursor: pointer;
    background: transparent;
    color: var(--muted);
    border: 1px solid var(--border);
    transition: background .15s, color .15s, border-color .15s;
}
.param-row-confirm:hover {
    background: #dcfce7;
    color: var(--edited);
    border-color: var(--edited);
}
.param-row-confirm.is-confirmed {
    background: var(--edited);
    color: #fff;
    border-color: var(--edited);
}
.param-row-confirm.is-confirmed:hover {
    background: #047857;
    border-color: #047857;
}
/* Verwerfen-Umschalter (✗) für „Manuell prüfen": neutral/grau statt
   grün – verworfen heißt „nicht extrahiert", kein bestätigter Wert. */
.param-row-dismiss:hover {
    background: #f1f5f9;
    color: var(--text);
    border-color: var(--muted);
}
.param-row-dismiss.is-dismissed {
    background: var(--muted);
    color: #fff;
    border-color: var(--muted);
}
.param-row-dismiss.is-dismissed:hover {
    background: #475569;
    border-color: #475569;
}
/* Unsicher-Prüfung auf der Geräte-Zusammenfassung: Banner mit Zähler
   und „nur Unsichere"-Filter. Steht oben und scrollt mit dem Inhalt
   weg (nicht sticky). */
.uncertain-banner .uncertain-open {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.uncertain-banner .uncertain-msg {
    color: var(--warning);
    font-weight: 600;
}
.uncertain-banner .uncertain-done {
    display: none;
    align-items: center;
    gap: .4rem;
    color: var(--edited);
    font-weight: 600;
}
.uncertain-banner[data-done="1"] .uncertain-open {
    display: none;
}
.uncertain-banner[data-done="1"] .uncertain-done {
    display: flex;
}
.uncertain-show-all {
    background: none;
    border: none;
    padding: 0;
    margin-left: .25rem;
    color: var(--primary);
    font-weight: 600;
    font-size: .85rem;
    text-decoration: underline;
    cursor: pointer;
}
.uncertain-show-all:hover { color: var(--primary-dark); }
.uncertain-filter {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-weight: 400;
}
/* „Nur Unsichere anzeigen": Beim Aktivieren markiert das JS alles, was
   ausgeblendet werden soll, mit .is-filtered-out (nicht-unsichere Zeilen
   sowie Karten/Abschnitte ohne unsicheren Wert – auch „Nicht extrahierte
   Parameter" und „Weitere Angaben"). Die sichtbaren, unsicheren Zeilen
   bleiben unmarkiert und damit sichtbar – auch nachdem sie bestätigt/
   bearbeitet und per HTMX neu gerendert wurden. Die Liste baut sich erst
   beim erneuten Ab-/Anwählen des Filters neu auf.

   Bewusst nicht auf #geraet-results beschränkt: Die Auswertungsseite
   zeigt ein Prüf-Banner je Gerät in je einem eigenen Container
   (geraet-results-<id>, siehe partials/uncertain_filter.html), nicht in
   der immer gleichen #geraet-results von geraet_results.html. */
.is-filtered-out { display: none; }
/* Geräte-Cockpit: Pipeline-Stepper Erkennung → Identifikation → Extraktion. */
.cockpit-stepper {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin: .5rem 0 1.25rem;
}
.cockpit-step {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .45rem .9rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: #fff;
    color: var(--muted);
    font-weight: 600;
    font-size: .92rem;
    white-space: nowrap;
}
.cockpit-step small { font-weight: 400; opacity: .8; }
.cockpit-step-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.15rem;
    height: 1.15rem;
    border-radius: 50%;
    background: var(--border);
    color: #fff;
    font-size: .72rem;
    font-weight: 700;
}
.cockpit-step.is-done { color: var(--success); border-color: var(--success); background: #f0fdf4; }
.cockpit-step.is-done .cockpit-step-icon { background: var(--success); }
.cockpit-step.is-running { color: var(--primary-dark); border-color: var(--primary); background: #eff6ff; }
.cockpit-step.is-running .cockpit-step-icon { background: transparent; }
.cockpit-step.is-error { color: var(--danger); border-color: var(--danger); background: #fef2f2; }
.cockpit-step.is-error .cockpit-step-icon { background: var(--danger); }
.cockpit-step.is-locked { opacity: .5; }
.cockpit-step.is-skip { opacity: .45; text-decoration: line-through; }
.cockpit-step-line { flex: 1 1 1.5rem; min-width: 1rem; height: 2px; background: var(--border); }
.cockpit-actions { display: flex; flex-direction: column; gap: .7rem; max-width: 34rem; margin: 1.25rem auto 0; }

/* Kompakte Variante desselben Steppers für die Positions-Karte der
   Parse-Vorschau (geraet_progress.html) – gleicher Zustands-Automat,
   nur platzsparender für den Listen-Kontext. */
.cockpit-stepper-sm { gap: .3rem; margin: .75rem 0 0; }
.cockpit-stepper-sm .cockpit-step { padding: .2rem .5rem; gap: .3rem; font-size: .72rem; }
.cockpit-stepper-sm .cockpit-step-icon { width: .95rem; height: .95rem; font-size: .6rem; }
.cockpit-stepper-sm .cockpit-step-line { flex: 1 1 .75rem; min-width: .5rem; }

/* Fertig-Zustand: sekundäre Aktionen (PDF, Schritt-für-Schritt)
   nebeneinander unter der Primäraktion – vollwertige, nicht winzige
   Buttons, damit sie unter der großen Übersicht nicht verloren wirken. */
.cockpit-secondary { display: flex; gap: .7rem; }
.cockpit-secondary > * { flex: 1 1 0; }
.cockpit-secondary .btn {
    display: flex; align-items: center; justify-content: center; gap: .45rem;
    min-height: 2.9rem; padding: .7rem 1rem;
    font-size: .95rem; font-weight: 600;
    background: #fff;
}
.cockpit-secondary .btn:hover { background: #f8fafc; }
@media (max-width: 480px) { .cockpit-secondary { flex-direction: column; } }

/* Dezenter Abbrechen-Link unter einer Zwischenfrage (kein Button-Gewicht). */
.cockpit-cancel {
    align-self: center; margin-top: .1rem;
    background: none; border: none; cursor: pointer;
    color: var(--muted); font-size: .85rem; text-decoration: underline;
    padding: .35rem .5rem;
}
.cockpit-cancel:hover { color: var(--text); }

/* Fertig-Zustand: Parameter je Komponente/Grunddaten plus Gesamtzeile.
   Name links (flexibel), Kennzahl rechtsbündig, Button ganz rechts mit
   fester Breite – dadurch fluchten die Buttons und die Kennzahl steht
   unabhängig von der Unsicher-Pille immer an derselben Kante. */
.cockpit-param-row {
    display: flex; align-items: center; gap: .75rem;
    padding: .5rem 0; border-bottom: 1px solid var(--border);
}
.cockpit-param-name { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: .4rem; }
.cockpit-param-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.comp-name-badges { display: inline-flex; align-items: center; gap: .4rem; }
.cockpit-param-meta { flex: 0 0 auto; color: var(--muted); font-size: .85rem; white-space: nowrap; }
.cockpit-param-btn, .cockpit-param-btn--spacer { flex: 0 0 auto; width: 5.5rem; }
.cockpit-param-btn { padding: .28rem 0; font-size: .8rem; text-align: center; }
.cockpit-param-btn--spacer { visibility: hidden; }
.cockpit-param-total { display: flex; align-items: center; gap: .75rem; padding: .7rem 0 .1rem; font-weight: 600; }
.cockpit-param-total .cockpit-param-name { font-weight: 600; }
.cockpit-param-total .cockpit-param-meta { color: var(--text); font-size: .9rem; }
.chip-warn {
    display: inline-flex; align-items: center;
    background: #fff7ed; color: var(--warning);
    border: 1px solid #fed7aa; border-radius: 999px;
    font-size: .7rem; font-weight: 600;
    padding: .1rem .5rem; margin-left: .45rem;
}

/* Cockpit-Startauswahl: kurzer Erklärtext plus die beiden Wege als
   nebeneinanderliegende Karten, mittig statt linksbündig. */
.cockpit-intro {
    max-width: 46rem;
    margin: .5rem auto 1.5rem;
    text-align: center;
}
.cockpit-intro-title { font-size: 1.15rem; font-weight: 700; margin: 0 0 .35rem; }
.cockpit-intro-text { color: var(--muted); font-size: .9rem; margin: 0; }
.cockpit-choice {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
    max-width: 46rem;
    margin: 0 auto;
    align-items: stretch;
}
@media (max-width: 620px) { .cockpit-choice { grid-template-columns: 1fr; } }
.choice-card {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.5rem 1.25rem;
    text-align: center;
}
/* Standard-Weg (Komplett-Verarbeitung) optisch hervorgehoben. */
.choice-card.is-primary { border-color: var(--warning); box-shadow: 0 1px 6px rgba(217, 119, 6, .12); }
.choice-icon { font-size: 1.9rem; line-height: 1; }
.choice-title { font-size: 1.05rem; font-weight: 700; margin: .6rem 0 .3rem; }
.choice-desc { color: var(--muted); font-size: .84rem; line-height: 1.45; margin: 0 0 1rem; flex: 1 1 auto; }
.choice-cost {
    display: inline-flex; align-items: center; gap: .3rem;
    align-self: center;
    background: #fff7ed; color: var(--warning);
    border: 1px solid #fed7aa; border-radius: 999px;
    font-size: .68rem; font-weight: 600;
    padding: .15rem .55rem; margin-bottom: .85rem;
}

/* Reserviert den ✓-Slot auf Zeilen ohne Bestätigen-Umschalter, damit
   die Wertspalte nicht springt (gleiche Box wie .param-row-confirm). */
.param-row-confirm-spacer {
    flex: 0 0 auto;
    padding: .12rem .5rem;
    font-size: .85rem;
    line-height: 1.5;
    border: 1px solid transparent;
    visibility: hidden;
    pointer-events: none;
}

.param-row-jump:hover {
    background: var(--primary);
}

.param-row-jump:disabled,
.param-row-jump[aria-disabled="true"] {
    background: transparent;
    color: var(--muted);
    border: 1px dashed var(--border);
    opacity: .45;
    cursor: not-allowed;
}

/* Spinner */
.spinner {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    border: 2px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin .6s linear infinite;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

/* Feedback-Popup (feedback_modal.html), natives <dialog>. `margin:auto`
   zentriert es im Viewport – nötig, weil der globale `* { margin:0 }`
   Reset die Standard-Zentrierung des <dialog> sonst aushebelt. */
.fb-modal {
    margin: auto;
    border: none;
    border-radius: var(--radius);
    padding: 0;
    width: min(30rem, 92vw);
    color: var(--text);
    background: var(--surface);
    box-shadow: 0 12px 40px rgba(15, 23, 42, .28);
}

.fb-modal::backdrop {
    background: rgba(15, 23, 42, .45);
}

.fb-modal form {
    padding: 1.25rem 1.4rem 1.4rem;
}

.fb-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: .3rem;
}

.fb-modal-title {
    font-size: 1.05rem;
    font-weight: 700;
}

.fb-modal-close {
    flex: 0 0 auto;
    background: none;
    border: none;
    font-size: 1.1rem;
    line-height: 1;
    padding: .2rem;
    cursor: pointer;
    color: var(--muted);
}

.fb-modal-close:hover {
    color: var(--text);
}

.fb-modal-subject {
    margin-bottom: .9rem;
}

.fb-modal-error {
    margin-bottom: 1rem;
}

.fb-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: .6rem;
    margin-top: .25rem;
}

/* Kurze Bestätigung nach dem Absenden. */
.lv-toast {
    position: fixed;
    bottom: 1.25rem;
    left: 50%;
    transform: translateX(-50%) translateY(1rem);
    background: var(--text);
    color: #fff;
    padding: .7rem 1.1rem;
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    font-size: .9rem;
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s, transform .2s, visibility .2s;
    z-index: 2000;
}

.lv-toast.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}

/* Einheitlicher Seitenkopf aller job-gebundenen Seiten (base.html):
   links Zurück, mittig Dateiname-Eyebrow + Überschrift + Meta,
   rechts die laufenden Job-Kosten und optionale Weiter-Aktion. */
.page-header {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
    margin: 1rem 0 1.25rem;
    padding: 1rem 1.25rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}
.page-header-back {
    display: flex;
}
.page-header-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: .6rem;
}
.page-header-main {
    text-align: center;
    min-width: 0;
}
.page-header-eyebrow {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: .1rem .6rem;
    font-size: .85rem;
    color: var(--muted);
    overflow-wrap: anywhere;
}
.page-header-file {
    color: var(--text);
    font-weight: 500;
}
.page-header-title {
    margin: .2rem 0 0;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.01em;
    overflow-wrap: anywhere;
}
/* Meta-Zeile als technisches Mono-Label (METEOR-Eyebrow). */
.page-header-meta {
    margin-top: .4rem;
    font-family: var(--mono);
    font-size: .72rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
}

/* ── Filter der Jobliste (index.html) ──────────────────────────────────── */
.jobs-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1rem;
    margin-bottom: .75rem;
    font-size: .85rem;
    color: var(--muted, #64748b);
}
.jobs-filter input[type="search"] { flex: 1 1 18rem; min-width: 12rem; }
.jobs-filter label { display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap; }
.jobs-filter input { padding: .3rem .5rem; font-size: .85rem; }

/* Geräte-Auswahl als Chips (Auswertung, WGK-Seite): je Gerät ein Chip mit Position
   und Name; der aktive ist gefüllt. Steuerung über Alpine (x-data aktiv). */
.geraete-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.25rem; }
.geraet-chip { display: inline-flex; align-items: center; gap: .5rem; max-width: 100%;
    padding: .4rem .9rem .4rem .45rem; border: 1px solid var(--border, #cbd5e1); border-radius: 999px;
    background: var(--surface, #fff); color: var(--text, #0f172a); font-size: .85rem; cursor: pointer;
    transition: background .15s, border-color .15s, box-shadow .15s; }
.geraet-chip:hover { border-color: #1e3a8a; box-shadow: 0 1px 4px rgba(15, 23, 42, .08); }
.geraet-chip .geraet-chip-pos { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .72rem;
    padding: .15rem .45rem; border-radius: 999px; background: #e2e8f0; color: #334155; white-space: nowrap; }
.geraet-chip .geraet-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.geraet-chip .geraet-chip-status { width: .55rem; height: .55rem; border-radius: 999px; background: #cbd5e1; flex: none; }
.geraet-chip .geraet-chip-status.ok { background: #059669; }
.geraet-chip .geraet-chip-status.teilweise { background: #d97706; }
.geraet-chip .geraet-chip-status.fehler { background: #dc2626; }
.geraet-chip.aktiv { background: #1e3a8a; border-color: #1e3a8a; color: #fff; }
.geraet-chip.aktiv .geraet-chip-pos { background: rgba(255, 255, 255, .18); color: #fff; }

/* Werkzeugzeile unter dem Seitenkopf (Downloads, Testdateien) – der Kopf selbst trägt
   rechts nur den nächsten Pipeline-Schritt */
.seiten-werkzeuge { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; margin: -.25rem 0 1rem; }
.seiten-werkzeuge .btn { white-space: nowrap; }

/* ── Inhaltsverzeichnis rechts neben dem PDF und Herkunftszeile (pdf_viewer/inhalt.js) ── */
.pdf-panel-main {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
}
.pdf-panel-main > .pdf-panel-body {
    min-width: 0;
}
.pdf-toc {
    display: block;
    position: static;
    flex: 0 0 var(--pdf-toc-width, 17rem);
    width: var(--pdf-toc-width, 17rem);
    min-width: 9rem;
    max-width: 75%;
    overflow-y: auto;
    background: var(--surface);
    color: var(--text);
    font-size: .8rem;
    letter-spacing: normal;
    padding: .4rem .25rem .8rem;
}
.pdf-toc[hidden],
.pdf-toc-resizer[hidden] {
    display: none;
}
/* Ziehgriff zwischen PDF und Inhaltsverzeichnis (pdf_viewer/inhalt.js) */
.pdf-toc-resizer {
    flex: 0 0 8px;
    position: relative;
    cursor: col-resize;
    touch-action: none;
}
.pdf-toc-resizer::before {
    content: "";
    position: absolute;
    left: 3px;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--border);
}
.pdf-toc-resizer::after {
    content: "";
    position: absolute;
    left: 1px;
    top: 50%;
    transform: translateY(-50%);
    width: 5px;
    height: 34px;
    border-radius: 3px;
    background: var(--border);
}
.pdf-toc-resizer:hover::before,
.pdf-toc-resizer:hover::after,
.pdf-toc-resizer.ziehen::before,
.pdf-toc-resizer.ziehen::after {
    background: var(--primary);
}
.pdf-toc-kopf {
    font-weight: 600;
    padding: .2rem .4rem .4rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .03em;
    font-size: .7rem;
}
.pdf-toc-hinweis {
    padding: .5rem;
    color: var(--muted);
}
.pdf-toc-liste {
    list-style: none;
    margin: 0;
    padding: 0;
}
.pdf-toc-kinder > .pdf-toc-liste {
    padding-left: .85rem;
}
.pdf-toc-zeile {
    display: flex;
    align-items: flex-start;
    border-radius: 4px;
}
.pdf-toc-auf {
    flex: 0 0 1.1rem;
    width: 1.1rem;
    border: 0;
    background: none;
    color: var(--muted);
    cursor: pointer;
    padding: .15rem 0;
    line-height: 1.2;
}
.pdf-toc-leer {
    cursor: default;
}
.pdf-toc-link {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    gap: .3rem;
    align-items: baseline;
    border: 0;
    background: none;
    text-align: left;
    padding: .15rem .3rem;
    cursor: pointer;
    color: inherit;
    border-radius: 4px;
    font: inherit;
}
.pdf-toc-link:hover {
    background: var(--bg);
}
.pdf-toc-symbol {
    flex: 0 0 auto;
    width: 1rem;
    text-align: center;
    opacity: .75;
}
.pdf-toc-titel {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pdf-toc-seite {
    flex: 0 0 auto;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    font-size: .7rem;
}
.pdf-toc-position > .pdf-toc-zeile .pdf-toc-titel {
    font-weight: 600;
}
.pdf-toc-aktiv > .pdf-toc-zeile .pdf-toc-link {
    background: #fef3c7;
    box-shadow: inset 3px 0 0 #f59e0b;
}
.pdf-toc-vorbemerkung.pdf-toc-aktiv > .pdf-toc-zeile .pdf-toc-link,
.pdf-toc-vorbemerkung .pdf-toc-aktiv > .pdf-toc-zeile .pdf-toc-link {
    background: #dbeafe;
    box-shadow: inset 3px 0 0 #3b82f6;
}
.pdf-herkunft {
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .2rem .5rem;
    margin: .5rem .75rem 0;
    padding: .35rem .6rem;
    border-radius: 6px;
    border: 1px solid #fcd34d;
    background: #fffbeb;
    font-size: .82rem;
}
.pdf-herkunft[hidden] {
    display: none;
}
.pdf-herkunft-art {
    font-weight: 600;
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    padding: .05rem .4rem;
    border-radius: 999px;
    background: #f59e0b;
    color: #fff;
}
.pdf-herkunft-pfad {
    min-width: 0;
}
.pdf-herkunft-seite {
    margin-left: auto;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}
.pdf-herkunft-vorbemerkung {
    border-color: #93c5fd;
    background: #eff6ff;
}
.pdf-herkunft-vorbemerkung .pdf-herkunft-art {
    background: #3b82f6;
}
.pdf-herkunft-komponente {
    border-color: #86efac;
    background: #f0fdf4;
}
.pdf-herkunft-komponente .pdf-herkunft-art {
    background: #16a34a;
}
.pdf-toc-toggle[aria-pressed="true"] {
    background: var(--bg);
    font-weight: 600;
}
/* Knöpfe im Baum: globale Button-Optik (weiße Schrift, Hintergrund, Großbuchstaben) zurücksetzen */
.pdf-toc button.pdf-toc-link,
.pdf-toc button.pdf-toc-auf {
    color: var(--text);
    background: none;
    border: 0;
    box-shadow: none;
    text-transform: none;
    letter-spacing: normal;
    font-weight: inherit;
    font-size: inherit;
    min-height: 0;
    height: auto;
    margin: 0;
}
.pdf-toc button.pdf-toc-auf {
    color: var(--muted);
    padding: .15rem 0;
}
.pdf-toc button.pdf-toc-link {
    width: 100%;
    overflow: hidden;
    padding: .15rem .3rem;
}
.pdf-toc button.pdf-toc-link:hover {
    background: var(--bg);
}
.pdf-toc-aktiv > .pdf-toc-zeile button.pdf-toc-link {
    background: #fef3c7;
}
.pdf-toc-vorbemerkung .pdf-toc-aktiv > .pdf-toc-zeile button.pdf-toc-link,
.pdf-toc-vorbemerkung.pdf-toc-aktiv > .pdf-toc-zeile button.pdf-toc-link {
    background: #dbeafe;
}
.pdf-toc {
    overflow-x: hidden;
}
.pdf-toc-zeile {
    min-width: 0;
}
.pdf-toc button.pdf-toc-link {
    flex: 1 1 0;
    width: auto;
}
.pdf-toc-titel {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    line-height: 1.25;
}

/* ── Parameterlisten im Tabellenstil (Scan, Auswertung, WGK) ──────────────
   Vorbild: die Tabellen der WGK-Seite (globales table/th/td): .85rem,
   feine Trennlinien, Kopfzeile in Mono-Großbuchstaben auf --bg. */
.param-list {
    border-top: 1px solid var(--border);
}
.param-row {
    padding: .45rem .75rem;
    font-size: .85rem;
}
.param-row:last-child {
    border-bottom: 1px solid var(--border);
}
.param-row:not(.param-list-kopf):hover {
    background: color-mix(in srgb, var(--bg) 60%, transparent);
}
.param-row-label {
    font-weight: 400;
    color: var(--text);
}
.param-row-value {
    font-weight: 500;
}
.param-list-kopf,
.param-list-titel {
    font-family: var(--mono);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    background: var(--bg);
}
.param-list-kopf {
    padding-top: .4rem;
    padding-bottom: .4rem;
}
.param-list-kopf .param-row-label,
.param-list-kopf .param-row-value {
    font-size: inherit;
    font-weight: inherit;
    color: inherit;
}
.param-list-titel {
    padding: .4rem .75rem;
    border-top: 1px solid var(--border);
    margin: 0;
}
.param-list-titel + .param-list {
    border-top: 0;
}

/* WGK-Seite: Parameter LV ↔ WGK (partials/wgk_param_tabelle.html) */
.wgk-param-tabelle {
    table-layout: fixed;
}
/* Hinweis bekommt den Rest (gut ein Drittel) – sonst brechen lange Hinweise in viele Zeilen um */
.wgk-param-tabelle th:nth-child(1) { width: 19%; }
.wgk-param-tabelle th:nth-child(2) { width: 16%; }
.wgk-param-tabelle th:nth-child(3) { width: 16%; }
.wgk-param-tabelle th:nth-child(4) { width: 7.5rem; }
.wgk-param-tabelle th:nth-child(6) { width: 2.6rem; }
.wgk-param-tabelle td {
    padding: .45rem .75rem;
    vertical-align: top;
    word-break: break-word;
}
.wgk-param-tabelle td.wgk-wert {
    font-weight: 500;
}
.wgk-param-tabelle tr.wgk-abweichung td {
    background: #fef2f2;
}
.wgk-param-tabelle .wgk-hinweis {
    font-size: .75rem;
    color: var(--muted);
    line-height: 1.3;
}
/* höchstens zwei Zeilen, voller Text als Tooltip (title) */
.wgk-param-tabelle .wgk-hinweis > span {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.wgk-param-tabelle .wgk-leer {
    color: var(--muted);
}
.wgk-param-tabelle .wgk-status-ok { color: #047857; }
.wgk-param-tabelle .wgk-status-abweichung { color: #b91c1c; font-weight: 600; }
.wgk-param-tabelle .wgk-status-nur_wgk,
.wgk-param-tabelle .wgk-status-nur_lv,
.wgk-param-tabelle .wgk-status-info { color: var(--muted); }
.wgk-param-tabelle td:last-child { text-align: right; padding-left: 0; }
.wgk-param-abschnitt {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    margin-top: .6rem;
}
.wgk-param-abschnitt > .param-list-titel:first-child {
    border-top: 0;
}
.wgk-param-abschnitt table {
    margin: 0;
}
.wgk-param-abschnitt tr:last-child td {
    border-bottom: 0;
}
/* Filter „nur Abweichungen“ der WGK-Parameter */
.wgk-parameter.nur-abw .result-card:not(.hat-abw),
.wgk-parameter.nur-abw .wgk-param-abschnitt:not(.hat-abw),
.wgk-parameter.nur-abw .wgk-param-tabelle tbody tr:not(.wgk-abweichung),
.wgk-parameter.nur-abw details.missing-params {
    display: none;
}
/* Tabellenstil: Eingabe- vs. berechnete Felder weiter unterscheidbar, aber in Tabellengröße */
.param-row .param-row-label-text.param-row-label-input {
    font-weight: 600;
    font-size: .85rem;
}
.param-row .param-row-label-text.param-row-label-calculated {
    font-size: .85rem;
}
