/* ════════════════════════════════════════════════════════════════════════════
   SCHRIFT: IBM PLEX, selbst ausgeliefert
   ════════════════════════════════════════════════════════════════════════════
   Drei Schnitte, wie im Flight-Importer: SANS fuer alles Laufende, CONDENSED
   fuer Spaltenkoepfe, Statuspillen und Ueberschriften (sie stehen in
   Grossbuchstaben und sparen dort Breite, ohne enger zu wirken), MONO fuer
   Zahlen, Nummern und Kennungen.

   Vorher war es Inter in EINER variablen Datei je Zeichenbereich. IBM Plex
   liegt bei Google nur in festen Schnitten vor, deshalb 14 Dateien statt 2:
   drei Gewichte Sans, zwei Condensed, zwei Mono — jeweils `latin` und
   `latin-ext`. Der Browser laedt nur, was auf der Seite vorkommt: eine
   deutsche Maske ohne Zahlenkolonne holt drei Dateien (Sans 400/500/600 latin,
   118 KB), die tuerkischen und polnischen Buchstaben kommen erst mit
   `latin-ext` dazu.

   SELBST AUSGELIEFERT und nicht von Google verlinkt — derselbe Grund wie bei
   Inter: die Anwendung traegt Kundendaten, und jeder Seitenaufruf waere sonst
   ein Aufruf bei einem Dritten. Ausserdem laeuft sie damit ohne Netz nach
   draussen, und genau so steht der Server.

   IBM Plex steht unter der SIL Open Font License 1.1; Weitergabe mit der
   Anwendung ist ausdruecklich erlaubt.

   font-display: swap — bis die Datei da ist, steht der Text in der
   Systemschrift. Nicht unsichtbar: eine Buchungsmaske darf nicht leer bleiben,
   weil eine Schrift noch laedt.
   ════════════════════════════════════════════════════════════════════════════ */

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/plex-sans-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/plex-sans-400-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/plex-sans-500-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/plex-sans-500-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/plex-sans-600-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/plex-sans-600-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Sans Condensed';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/plex-cond-500-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans Condensed';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/plex-cond-500-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Sans Condensed';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/plex-cond-600-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans Condensed';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/plex-cond-600-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/plex-mono-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/plex-mono-400-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/plex-mono-500-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/plex-mono-500-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    /* Feste Breiten fuer Datums- und Zeitfelder in den Leistungsbloecken: ein
       Datumsfeld traegt "20.08.2026" und das Kalendersymbol, ein Zeitfeld "14:00"
       und die Uhr. Hier zentral, damit sie in allen Bloecken gleich sind. */
    --feld-datum: 9rem;
    --feld-zeit: 8rem;
    /* Zaehlfelder (Erw/Kinder/Babys): zwei Stellen plus die Pfeilchen. */
    --feld-zahl: 5.5rem;
    /* Breiten der Anmelder-Anschrift. Sie stehen HIER und nicht in der Regel,
       damit "Anmelder" und "Anrede" denselben Wert benutzen — die Kanten der
       Zeilen liegen dadurch uebereinander, und eine Aenderung wirkt auf beide. */
    --feld-anrede: 9rem;
    --feld-land: 6rem;
    --feld-plz: 7rem;
    --feld-telefon: 12rem;
    /* Reisedaten: Status ("Buchung"/"Option"), Optionsfrist mit Datum UND Uhrzeit. */
    --feld-status: 10rem;
    --feld-frist: 13rem;

    /* ═══════════════════════════════════════════════════════════════════
       FARBEN — helle Palette (das Design-System des Portals)
       ═══════════════════════════════════════════════════════════════════
       Seite kuehles Hellgrau, Karten weiss, Text fast schwarz statt reinem
       Schwarz, Rahmen sichtbar statt angedeutet, Blau NUR fuer primaere
       Aktionen, aktive Navigation und wichtige Werte.

       DIE WERTE KOMMEN AUS DEM FLIGHT-IMPORTER (design/flight-importer.html
       im Nachbarprojekt). Zwei Anwendungen desselben Hauses, nebeneinander auf
       demselben Bildschirm — mit zwei Blautoenen und zwei Grauleitern sieht
       das aus wie zwei Programme von zwei Herstellern. Uebernommen sind die
       TOKEN, nicht die Bauteile: welche Flaeche welchen Wert bekommt, bleibt
       Sache dieser Anwendung.

       Der Grund ist kraeftiger als vorher (#edeff3 statt #f6f7f9): die Karten
       sind weiss, und der Unterschied zwischen Seite und Karte war auf einem
       hellen Buerobildschirm kaum zu sehen. Dasselbe bei den Rahmen.
       ═══════════════════════════════════════════════════════════════════ */
    --color-bg: #edeff3;
    --color-surface: #ffffff;
    /* Tabellenkopf und flaechige Abschnitte. */
    --color-surface-alt: #f6f7f9;
    /* Zeilen-Hover: eine Stufe DUNKLER als der Tabellenkopf und nicht heller.
       Der Importer nimmt fuer beides denselben Wert; in einer Liste mit
       feststehendem Kopf ist die ueberfahrene Zeile dann nicht mehr vom Kopf zu
       unterscheiden. */
    --color-hover: #edeff3;
    --color-sidebar: #ffffff;
    --color-sidebar-text: #3d4753;
    --color-sidebar-text-active: #101720;
    --color-sidebar-overlay-rgb: 16, 23, 32;
    --color-tooltip-bg: #101720;
    --color-tooltip-text: #ffffff;
    --color-tooltip-text-muted: #bac3ce;
    --color-primary: #1b3fc4;
    --color-primary-hover: #16349f;
    --color-primary-soft: rgba(27, 63, 196, 0.12);
    /* ═══════════════════════════════════════════════════════════════════
       DIE SCHRIFT AUF EINER GEFUELLTEN FARBFLAECHE
       ═══════════════════════════════════════════════════════════════════
       Hier stand `color: #fff` an vierzehn Stellen — und im Dunkelmodus war
       es an allen vierzehn falsch.

       Der Grund liegt in der Palette selbst: im dunklen Satz sind ALLE
       Farbwerte helle Toene, weil sie dort als SCHRIFT auf dunklem Grund
       stehen muessen (Verweise, aktiver Menuepunkt, Betraege der
       Buchhaltung). Wo dieselbe Farbe eine FLAECHE traegt, ist weiss
       darauf zu schwach:

         Blau   #6e90ff  weiss 2,96:1   (beim Ueberfahren #89a5ff: 2,36:1)
         Gefahr #ff7166  weiss 2,69:1
         Akzent #b79bff  weiss 2,30:1

       Verlangt sind 4,5:1. Der Seitengrund auf denselben Flaechen traegt
       6,44 / 7,09 / 8,30 — also nicht weiss, sondern dunkel.

       EINE Marke fuer alle farbigen Flaechen und nicht eine je Farbe: die
       zwei Werte sind fuer Blau, Rot und Violett dieselben, und drei Marken
       waeren drei Stellen, an denen man sich entscheiden muss.

       NICHT betroffen: die Fremdmarke WhatsApp (--color-whatsapp) und die
       festen dunklen Flaechen der Anmeldeseite (.lp-*). Die tragen weiss,
       weil sie in beiden Ansichten dunkel BLEIBEN.
       ═══════════════════════════════════════════════════════════════════ */
    --auf-farbflaeche: #ffffff;
    /* DER FOKUSRING. Er ist KRAEFTIGER als --color-primary-soft (28 statt 12
       Prozent): der weiche Ton hinterlegt Flaechen, dieser hier muss auf einer
       Maske mit dreissig Feldern von weitem sagen, in welchem Feld man steht.
       Als eigene Marke, damit Feld, Knopf und Auswahlliste denselben Ring
       tragen — so haelt es der Flight-Importer (--focus) auch. */
    --fokus-ring: 0 0 0 3px rgba(27, 63, 196, 0.28);
    /* Flaechig hinterlegtes Blau: aktiver Menuepunkt, Nummern-Pille, Badge. */
    --color-primary-light: #e3e9fa;
    /* ZWEI RAHMENTOENE, und der Unterschied ist die Rolle:
       --color-border      trennt (Tabellenlinien, Kartenkanten, Trennstriche)
       --color-border-strong umreisst, was man ANFASSEN kann (Eingabefelder,
                           sekundaere Knoepfe)
       Mit einem Wert fuer beides war ein Feld so leise umrandet wie eine
       Tabellenlinie — man sah nicht mehr, wo man hineinschreiben kann. Der
       Flight-Importer trennt dasselbe als --line und --line-strong. */
    --color-border: #d7dce3;
    --color-border-strong: #bac3ce;
    --color-text: #101720;
    --color-text-muted: #636d7a;
    --color-text-subtle: #9ba5b2;

    /* ═══════════════════════════════════════════════════════════════════
       STATUSFARBEN — ZWEI Werte je Status, und das ist kein Versehen
       ═══════════════════════════════════════════════════════════════════
       Die erste ist die Farbe des Design-Systems: sie steht auf FLAECHEN und
       an SYMBOLEN — Badge-Hintergrund, Icon, Diagrammfarbe, Rahmen.

       Die zweite (-text) gilt fuer SCHRIFT und muss 4,5:1 halten — in genau
       diesen Farben stehen die Betraege der Buchhaltung ("Offen" rot,
       "Bezahlt" gruen).

       Die Palette des Importers trennt dasselbe, nur mit anderen Namen: die
       --mark-* dort sind die Flaechenwerte, die uebrigen die Textwerte. Bei
       Rot, Gruen und Violett fallen beide zusammen, weil der Textwert schon
       kraeftig genug fuer eine Flaeche ist; nur GELB braucht zwei — #c68206
       kommt auf weiss auf 3,18:1 und taugt als Flaeche, nicht als Schrift.

       Nachgerechnet auf weissem Grund:
       #b3271e = 6,51:1 · #0b7a4b = 5,39:1 · #96650a = 5,04:1 · #6b3fa0 = 7,38:1
       ═══════════════════════════════════════════════════════════════════ */
    --color-danger: #b3271e;
    --color-danger-text: #b3271e;
    --color-success: #0b7a4b;
    --color-success-text: #0b7a4b;
    --color-warning: #c68206;
    --color-warning-text: #96650a;
    --color-accent2: #6b3fa0;
    --color-accent2-text: #6b3fa0;

    /* WHATSAPP ist keine Statusfarbe, sondern eine FREMDMARKE — ein eigener
       Wert und nicht --color-success, denn Gruen heisst im Rest der Anwendung
       "bezahlt". Er steht hier, damit alle WhatsApp-Knoepfe (Dokument-Dialog,
       Quittung, Sendedialog) denselben Ton tragen; die Farbwahl selbst ist bei
       .button-primary.button-whatsapp begruendet.

       OHNE Dunkelmodus-Fassung, anders als die Statusfarben: die stehen dort
       als Schrift auf dunklem Grund und werden deshalb aufgehellt. Dieser Wert
       traegt eine FLAECHE mit weisser Schrift darauf, und aufgehellt waere die
       nicht mehr lesbar. */
    --color-whatsapp: #128c7e;
    --color-whatsapp-hover: #0f7268;

    /* Weiche Statusflaechen fuer Pillen und Hinweiskaesten: dieselbe Farbe,
       stark aufgehellt. Keine voll gesaettigten Hintergruende — eine Liste mit
       zwanzig Statuspillen waere sonst ein Farbkasten. Als rgba, damit sie ueber
       jedem Grund liegen koennen (weisse Zeile, Hover-Grau, Kopfzeile).

       Sie standen bisher als rohe rgba() an sieben Stellen im Stylesheet, jede
       mit den Werten der ALTEN Statusfarben — beim Farbwechsel waeren die
       Flaechen im alten Ton stehen geblieben.

       Als rgba und nicht als die festen Werte des Importers (#FAE2DF und so
       fort): dessen Pillen liegen immer auf weiss, hier auch auf der
       ueberfahrenen Zeile und im Tabellenkopf. */
    --color-danger-soft: rgba(179, 39, 30, 0.10);
    --color-success-soft: rgba(11, 122, 75, 0.12);
    --color-warning-soft: rgba(198, 130, 6, 0.14);
    --color-accent2-soft: rgba(107, 63, 160, 0.12);
    --series-1: #2a78d6;
    --series-2: #eb6834;
    --series-3: #1baf7a;
    --series-4: #eda100;
    --series-5: #e87ba4;
    --series-6: #4a3aa7;
    --series-7: #e34948;
    --series-other: #898781;
    /* ═══════════════════════════════════════════════════════════════════
       RADIEN — sachlich, nicht weich
       ═══════════════════════════════════════════════════════════════════
       sm  kleine Elemente (Pillen, Marken, Symbolflaechen)
       —   Knoepfe und Eingabefelder
       lg  Karten
       xl  grosse Behaelter (Tabellenrahmen, Dialoge)
       pill Kapselform

       Halbiert gegenueber vorher (8/12/16/20 -> 5/8/12/12), mit denselben
       Werten wie der Flight-Importer. Eine Maske mit dreissig Feldern, zwoelf
       Knoepfen und einer Tabelle darunter besteht fast nur aus Kanten; bei
       12 px Radius an jedem Feld liest sich das Raster nicht mehr als Raster.
       Die Kapselform bleibt, wo sie Bedeutung traegt (Statuspillen,
       Nummernpillen) — dort ist sie kein Schmuck, sondern der Unterschied zu
       einem Knopf.

       xl und lg sind jetzt DASSELBE. Der Unterschied zwischen 12 und 16 px war
       auf dem Bildschirm keiner; zwei Marken fuer denselben Wert waeren nur
       zwei Stellen, an denen man sich entscheiden muss. */
    --radius-sm: 5px;
    --radius: 8px;
    --radius-lg: 12px;
    --radius-xl: 12px;
    --radius-pill: 999px;

    /* ═══════════════════════════════════════════════════════════════════
       ABSTANDSRASTER — 8px, mit 4px als halbem Schritt
       ═══════════════════════════════════════════════════════════════════
       Damit Abstaende nicht in jeder Regel neu erfunden werden. Wer eine
       neue Komponente baut, nimmt einen dieser Werte und keinen dazwischen.
       ═══════════════════════════════════════════════════════════════════ */
    --space-1: 0.25rem;   /*  4px */
    --space-2: 0.5rem;    /*  8px */
    --space-3: 0.75rem;   /* 12px */
    --space-4: 1rem;      /* 16px */
    --space-6: 1.5rem;    /* 24px */
    --space-8: 2rem;      /* 32px */
    --space-10: 2.5rem;   /* 40px */
    --space-12: 3rem;     /* 48px */
    --space-16: 4rem;     /* 64px */

    /* ═══════════════════════════════════════════════════════════════════
       BAUTEILMASSE
       ═══════════════════════════════════════════════════════════════════
       Ein Eingabefeld und der Knopf daneben MUESSEN gleich hoch sein — sonst
       sitzt der Knopf einer Suchleiste schief. Deshalb steht die Hoehe hier
       einmal und nicht in jeder Regel.

       Die Zeilenhoehe der Tabellen gilt fuer die NORMALE Ansicht. Die
       kompakte Ansicht (Umschalter in der Kopfzeile) setzt sie herunter —
       an einem Arbeitsplatz, an dem den ganzen Tag Zeilen gelesen und
       angehakt werden, zaehlt jede zusaetzliche Zeile im Bild.
       ═══════════════════════════════════════════════════════════════════ */
    /* EINE HOEHE FUER ALLES, WAS MAN ANFASST — Feld, Knopf, kleiner Knopf,
       Symbolknopf. Es waren vier Werte (44 / 44 / 38 / 36), und die drei
       Abstufungen hatten ihre Gruende: eine Werkzeugleiste sollte flacher sein
       als eine Suchmaske, ein Zeichenknopf schmaler als ein beschrifteter.

       In der Maske sah man davon nur eins: dass Knoepfe, die nebeneinander
       stehen, verschieden hoch sind. Im Sendedialog stand "Senden" zwei Pixel
       ueber "Abbrechen" — und wo das auffiel, half kein Grund mehr, sondern nur
       eine Sonderregel ("Wo beide Rollen nebeneinander stehen..."). Von denen
       gab es schon zwei.

       Jetzt gibt es nichts mehr auszurichten: ein Knopf ist so hoch wie ein
       Eingabefeld, immer. Der Flight-Importer haelt es genauso — dort sind
       .btn, .btn-icon und die Felder alle 34 px hoch.

       Die drei Marken bleiben als NAMEN bestehen: an den Regeln steht damit
       weiter, welche Rolle gemeint ist, und eine kuenftige Abstufung braucht
       nur diese Zeilen. */
    --hoehe-feld: 44px;
    --hoehe-knopf: var(--hoehe-feld);
    --hoehe-knopf-klein: var(--hoehe-feld);
    --hoehe-symbolknopf: var(--hoehe-feld);
    /* Eine Zeile im Menue der Seitenleiste — Dashboard und Menuepunkt gleich
       hoch. Sie waren es nicht (41 / 38 / 44 px gemessen), und die drei Werte
       waren kein Entwurf, sondern drei Regeln, die ihre Hoehe auf drei Weisen
       aus Polster und Schriftgroesse ergaben.

       36 statt 44 px, wie die Schiene des Flight-Importers. Das Menue hat neun
       Gruppen mit zusammen ueber dreissig Punkten; bei 44 px passte auf einen
       Notebookschirm nicht einmal die Haelfte, ohne zu rollen. Der GRUPPENKOPF
       zaehlt nicht mehr mit — er ist jetzt eine Beschriftung und keine Zeile,
       siehe .menu-group summary. */
    --hoehe-menuzeile: 36px;
    --hoehe-tabellenzeile: 56px;
    --hoehe-topbar: 60px;
    --breite-sidebar: 236px;
    /**
     * Ein Eintrag im Handlungsbedarf, gerechnet als MITTLERE Hoehe: zwei
     * Textzeilen (Stufe + Titel, darunter die Kontextzeile) plus Innenabstand
     * und Trennlinie. Gemessen sind es 67 px, der erste Eintrag ist 13 px
     * niedriger (keine Linie, kein Polster darueber) — vier zusammen brauchen
     * 257 px, also knapp 65 im Mittel.
     *
     * Vier davon sind die sichtbare Hoehe der Karte (app.css,
     * .db-aufgaben-liste). Ein Mittelwert statt Hoehe-plus-Korrekturposten:
     * sonst stuenden in der Rechnung zwei Abzuege, die niemand nachvollzieht.
     */
    --hoehe-db-eintrag: 4.05rem;
    --shadow-sm: 0 1px 2px rgba(16, 23, 32, 0.07);
    --shadow-md: 0 1px 2px rgba(16, 23, 32, 0.06), 0 10px 28px -14px rgba(16, 23, 32, 0.28);
    --shadow-lg: 0 2px 4px rgba(16, 23, 32, 0.08), 0 24px 60px -24px rgba(16, 23, 32, 0.36);
    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --duration: 0.18s;

    /* IBM Plex zuerst, dahinter die Systemschriften als Rueckfall — solange die
       Datei laedt und falls sie einmal fehlt.

       --schrift-cond ist die SCHMALE Fassung. Sie steht nur dort, wo Text in
       Grossbuchstaben und klein gesetzt ist: Spaltenkoepfe, Statuspillen,
       Gruppenueberschriften. Fuer Fliesstext waere sie falsch — schmal liest
       sich in kurzen Etiketten gut und in ganzen Saetzen schlecht. Faellt sie
       aus, tritt die normale Sans ein und nicht eine fremde schmale Schrift:
       eine halb passende Breite ist schlimmer als gar keine. */
    --schrift: 'IBM Plex Sans', system-ui, -apple-system, BlinkMacSystemFont,
        'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --schrift-cond: 'IBM Plex Sans Condensed', 'IBM Plex Sans', system-ui,
        -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --schrift-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas,
        monospace;
}

:root[data-theme="dark"] {
    --color-bg: #0c1016;
    --color-surface: #131a23;
    --color-surface-alt: #18212c;
    --color-hover: #18212c;
    --color-sidebar: #131a23;
    --color-sidebar-text: #b3becc;
    --color-sidebar-text-active: #e8edf4;
    --color-sidebar-overlay-rgb: 255, 255, 255;
    --color-tooltip-bg: #090d12;
    --color-tooltip-text: #e8edf4;
    --color-tooltip-text-muted: #7c8899;
    --color-primary: #6e90ff;
    --color-primary-hover: #89a5ff;
    --color-primary-soft: rgba(110, 144, 255, 0.16);
    /* Nicht weiss: siehe die Begruendung an der hellen Palette. */
    --auf-farbflaeche: #0c1016;
    --fokus-ring: 0 0 0 3px rgba(110, 144, 255, 0.28);
    /* Gegenstueck zu #e3e9fa: dort eine helle Flaeche, hier eine dunkle. */
    --color-primary-light: #17233d;
    --color-border: #232e3b;
    --color-border-strong: #35424f;
    --color-text: #e8edf4;
    --color-text-muted: #b3becc;
    --color-text-subtle: #7c8899;
    /* Auf dunklem Grund sind die HELLEN Toene die lesbaren, gemessen auf der
       Kartenflaeche #131a23: #ff7166 kommt auf 6,51:1, #3dd68c auf 9,33:1,
       #f0c22b auf 10,38:1, #b79bff auf 7,62:1. Ein eigener -text-Wert ist
       hier nur beim Gelb noetig — die uebrigen koennen Flaeche und Schrift
       in derselben Farbe tragen. */
    --color-danger: #ff7166;
    --color-danger-text: #ff7166;
    --color-success: #3dd68c;
    --color-success-text: #3dd68c;
    --color-warning: #f0c22b;
    --color-warning-text: #e0a337;
    --color-accent2: #b79bff;
    --color-accent2-text: #b79bff;
    --color-danger-soft: rgba(255, 113, 102, 0.18);
    --color-success-soft: rgba(61, 214, 140, 0.18);
    --color-warning-soft: rgba(240, 194, 43, 0.20);
    --color-accent2-soft: rgba(183, 155, 255, 0.18);
    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --series-4: #c98500;
    --series-5: #d55181;
    --series-6: #9085e9;
    --series-7: #e66767;
    --series-other: #9198ab;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-md: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 28px -14px rgba(0, 0, 0, 0.7);
    --shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.45), 0 24px 60px -24px rgba(0, 0, 0, 0.85);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) {
        --color-bg: #0c1016;
        --color-surface: #131a23;
        --color-surface-alt: #18212c;
        --color-hover: #18212c;
        --color-sidebar: #131a23;
        --color-sidebar-text: #b3becc;
        --color-sidebar-text-active: #e8edf4;
        --color-sidebar-overlay-rgb: 255, 255, 255;
        --color-tooltip-bg: #090d12;
        --color-tooltip-text: #e8edf4;
        --color-tooltip-text-muted: #7c8899;
        --color-primary: #6e90ff;
        --color-primary-hover: #89a5ff;
        --color-primary-soft: rgba(110, 144, 255, 0.16);
        --auf-farbflaeche: #0c1016;
        --fokus-ring: 0 0 0 3px rgba(110, 144, 255, 0.28);
        /* Gegenstueck zu #e3e9fa: dort eine helle Flaeche, hier eine dunkle. */
        --color-primary-light: #17233d;
        --color-border: #232e3b;
        --color-border-strong: #35424f;
        --color-text: #e8edf4;
        --color-text-muted: #b3becc;
        --color-text-subtle: #7c8899;
        /* Auf dunklem Grund sind die HELLEN Toene die lesbaren, gemessen auf
           der Kartenflaeche #131a23: #ff7166 kommt auf 6,51:1, #3dd68c auf
           9,33:1, #f0c22b auf 10,38:1, #b79bff auf 7,62:1. Ein eigener
           -text-Wert ist hier nur beim Gelb noetig. */
        --color-danger: #ff7166;
        --color-danger-text: #ff7166;
        --color-success: #3dd68c;
        --color-success-text: #3dd68c;
        --color-warning: #f0c22b;
        --color-warning-text: #e0a337;
        --color-accent2: #b79bff;
        --color-accent2-text: #b79bff;
        --color-danger-soft: rgba(255, 113, 102, 0.18);
        --color-success-soft: rgba(61, 214, 140, 0.18);
        --color-warning-soft: rgba(240, 194, 43, 0.20);
        --color-accent2-soft: rgba(183, 155, 255, 0.18);
        --series-1: #3987e5;
        --series-2: #d95926;
        --series-3: #199e70;
        --series-4: #c98500;
        --series-5: #d55181;
        --series-6: #9085e9;
        --series-7: #e66767;
        --series-other: #9198ab;
        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
        --shadow-md: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 28px -14px rgba(0, 0, 0, 0.7);
        --shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.45), 0 24px 60px -24px rgba(0, 0, 0, 0.85);
    }
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--schrift);
    /* 15 px Grundtext. Er wirkt nur dort, wo keine Regel eine Groesse setzt —
       Absaetze, Listen, Fliesstext. Die Masken bringen ihre Groessen selbst mit.
       KEIN font-size an :root oder html: rem rechnet dagegen, und die knapp
       neuntausend Zeilen darunter sind auf 16 px Wurzel abgestimmt. */
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg);
    /* IBM Plex ist auf gerasterte Darstellung gezeichnet; ohne das wirkt sie
       auf macOS eine Spur zu fett. */
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    transition: background-color 0.15s ease, color 0.15s ease;
}

/* ═══════════════════════════════════════════════════════════════════════════
   UEBERSCHRIFTEN
   ═══════════════════════════════════════════════════════════════════════════
   Drei Stufen, mehr braucht eine Verwaltungsmaske nicht.

   DIE BEIDEN GROSSEN GRADE STEHEN IN DER SCHMALEN FASSUNG (--schrift-cond),
   wie im Flight-Importer. Eine Ueberschrift ist kurz; schmal gesetzt traegt sie
   dieselbe Aussage auf weniger Breite und laesst der Maske darunter Platz. Die
   negative Laufweite von vorher ist damit weg — sie war der Ausgleich dafuer,
   dass Inter in grossen Graden auseinandergezogen wirkt, und auf einer schmalen
   Schrift wuerde sie die Buchstaben ineinanderschieben.

   h3 bleibt in der normalen Sans: ab dort sind es Abschnittstitel, die neben
   Fliesstext stehen, und zwei Schriftbreiten in einem Absatz sieht man.

   Die Groessen stehen hier und nicht je Maske. Eine Karte darf ihr h2 kleiner
   setzen (.card h2), wenn es als Abschnittstitel innerhalb der Karte dient —
   das ist eine andere Rolle, nicht eine andere Meinung zur Groesse.
   ═══════════════════════════════════════════════════════════════════════════ */
h1 {
    font-family: var(--schrift-cond);
    font-size: 1.875rem;
    font-weight: 600;
    line-height: 1.25;
}

h2 {
    font-family: var(--schrift-cond);
    font-size: 1.375rem;
    font-weight: 600;
    line-height: 1.3;
}

h3 {
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.4;
}

a {
    color: inherit;
    text-decoration: none;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* ---------- Scrollbars ---------- */

html {
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}

/* Gerollt wird im Menue, nicht an der Leiste (siehe .sidebar nav weiter unten) —
   deshalb steht die dezente Rollleiste an beiden Selektoren. */
.sidebar,
.sidebar nav {
    scrollbar-width: thin;
    scrollbar-color: rgba(var(--color-sidebar-overlay-rgb), 0.2) transparent;
}

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: var(--radius-pill);
}

.sidebar::-webkit-scrollbar-thumb,
.sidebar nav::-webkit-scrollbar-thumb {
    background: rgba(var(--color-sidebar-overlay-rgb), 0.2);
}

.sidebar::-webkit-scrollbar-thumb:hover,
.sidebar nav::-webkit-scrollbar-thumb:hover {
    background: rgba(var(--color-sidebar-overlay-rgb), 0.32);
}

/* ---------- App shell ---------- */

.app {
    display: flex;
    min-height: 100vh;
}

/**
 * DREI BEREICHE: LOGO, MENUE, FUSSZEILE — und nur das Menue rollt.
 *
 * Vorher rollte die GANZE Seitenleiste (overflow-y: auto auf ihr selbst). Bei
 * kleiner Fensterhoehe wanderten damit Logo UND Fusszeile mit den Menuepunkten
 * aus dem Bild; Impressum, Datenschutz, Version und Copyright waren nur nach
 * dem Rollen bis zum Ende zu finden.
 *
 * Jetzt: die Leiste selbst rollt nicht (overflow: hidden), Kopf und Fuss sind
 * feste Bereiche (flex: 0 0 auto), das Menue dazwischen nimmt den Rest und rollt
 * bei Bedarf. min-height: 0 an ihm ist der Punkt, an dem es haengt — ein
 * Flexkind wird ohne diese Zeile nicht kleiner als sein Inhalt, und dann rollte
 * gar nichts, sondern die Fusszeile waere aus der Leiste gedrueckt worden.
 *
 * Zwei Rollleisten kann es damit nicht geben: die aeussere ist abgeschaltet.
 */
.sidebar {
    width: var(--breite-sidebar);
    flex-shrink: 0;
    background: var(--color-sidebar);
    color: var(--color-sidebar-text);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow: hidden;
    border-right: 1px solid var(--color-border);
    transition: width 0.15s ease, background-color var(--duration) var(--ease);
}

.sidebar-brand {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.625rem;
    padding: 1.125rem 1.125rem 1rem;
}

.sidebar-toggle {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: none;
    border-radius: var(--radius);
    background: transparent;
    color: var(--color-sidebar-text);
    cursor: pointer;
}

.sidebar-toggle:hover {
    background: var(--color-surface-alt);
    color: var(--color-sidebar-text-active);
}

.sidebar-toggle .icon {
    width: 15px;
    height: 15px;
    transition: transform 0.15s ease;
}

/* MENUEPUNKTE SIND KACHELN, KEINE ZEILEN.
   ---------------------------------------------------------------------------
   Vorher lief jeder Punkt von Kante zu Kante, und der aktive trug links einen
   3-px-Balken. Jetzt liegt das Menue in einem Polster (10 px seitlich), und die
   Punkte sind abgerundete Flaechen darin — dieselbe Form wie die Schiene des
   Flight-Importers und wie die Aufklappfelder der Kopfzeile.

   Das nimmt dem aktiven Punkt den Balken ab: er traegt eine blaue Flaeche und
   blaue Schrift, und beides zusammen ist deutlicher als ein Strich am Rand, den
   man im Augenwinkel fuer die Kante der Leiste haelt. */
.sidebar nav {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    padding: 0.375rem 0.625rem;
}

/* Der Fuss der Leiste: dieselbe Trennlinie wie ueberall (--color-border statt
   einer eigenen Auflage aus Weiss oder Schwarz) und dieselbe gedaempfte Farbe
   wie die Gruppenkoepfe darueber — die Leiste soll zwei Toene tragen, nicht
   vier. */
.sidebar-footer {
    flex: 0 0 auto;
    padding: 0.875rem 1.125rem 1rem;
    font-size: 0.6875rem;
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
    text-align: center;
}

.sidebar-footer a,
.auth-footer span a {
    color: inherit;
    text-decoration: underline;
}

.sidebar-footer a:hover,
.auth-footer span a:hover {
    opacity: 0.8;
}

/* eMind-Logo hat einen weißen Hintergrund (JPG) — eigene kleine weiße Badge-Fläche,
   damit es nicht als hartkantiges weißes Rechteck auf der dunklen Sidebar wirkt. */
.sidebar-footer-emind {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    background: #ffffff;
    border-radius: 3px;
    padding: 0.1rem 0.35rem;
    text-decoration: none !important;
}

.sidebar-footer-emind img {
    display: block;
    height: 12px;
    width: auto;
}

/* Die Versionsnummer in der Festbreitenschrift, wie der Fuss der Schiene im
   Flight-Importer: sie ist eine Kennung und kein Satz. */
.sidebar-footer-version {
    margin-top: 0.3rem;
    font-family: var(--schrift-mono);
    font-size: 0.6875rem;
    color: var(--color-text-subtle);
}

.auth-footer .sidebar-footer-version {
    margin-top: 0;
}

.menu-group {
    margin-bottom: 0;
}

/* DER GRUPPENKOPF IST EINE BESCHRIFTUNG, keine Zeile mehr: klein, schmal
   gesetzt, weit gesperrt, gedaempft — wie .nav-label im Flight-Importer und wie
   die Spaltenkoepfe der Tabellen. Er soll das Menue GLIEDERN und nicht selbst
   wie ein Ziel aussehen; anklickbar bleibt er (er klappt die Gruppe auf), und
   dafuer haelt min-height eine Trefferflaeche von 28 px. */
.menu-group summary {
    cursor: pointer;
    min-height: 1.75rem;
    padding: 0.875rem 0.5rem 0.375rem;
    font-family: var(--schrift-cond);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    /* GEDAEMPFT, und der Menuepunkt darunter in voller Textfarbe: die beiden
       sollen sich auch dann unterscheiden, wenn man nur aus dem Augenwinkel
       hinsieht. Groesse und Grossbuchstaben allein reichen dafuer nicht — sie
       fallen erst auf, wenn man liest. */
    color: var(--color-text-muted);
    list-style: none;
}

.menu-group summary::-webkit-details-marker {
    display: none;
}

.menu-group ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.menu-group li a {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    /* min-height statt mehr Polster: der Text sitzt weiter mittig, und ein
       zweizeiliger Menuepunkt (langer Titel, schmale Sidebar) waechst. */
    min-height: var(--hoehe-menuzeile);
    padding: 0.5rem 0.625rem;
    font-size: 0.875rem;
    font-weight: 500;
    /* Volle Textfarbe — siehe die Begruendung am Gruppenkopf. */
    color: var(--color-text);
    border-radius: var(--radius);
    transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease);
}

/* Alle Zeichen der Seitenleiste gleich gross. Vorher: 18 px im Dashboard-Link
   und im Gruppenkopf, 15 px im Menuepunkt — nebeneinander sichtbar, sobald eine
   Gruppe offen ist. 16 px ist die Mitte und bleibt neben 14,4 px Schrift ruhig. */
.sidebar nav .icon {
    width: 16px;
    height: 16px;
}

.menu-group li a .icon {
    vertical-align: 0;
}

.menu-group li a:hover {
    background: var(--color-surface-alt);
    color: var(--color-sidebar-text-active);
}

.main {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.topbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
    /* Feste Hoehe: die Kopfzeile traegt nur Symbolknoepfe, und ihre Hoehe soll
       sich nicht danach richten, welcher davon gerade der groesste ist. */
    min-height: var(--hoehe-topbar);
    padding: var(--space-2) var(--space-8);
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

/* Eine Gruppe der Kopfzeile — Darstellung links, Werkzeuge rechts. Innerhalb
   der Gruppe stehen die Knoepfe enger als zwischen den Gruppen; der Haarstrich
   davor trennt, ohne eine Linie durch die ganze Leiste zu ziehen. */
.topbar-gruppe {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.topbar-gruppe + .topbar-gruppe {
    padding-left: var(--space-3);
    border-left: 1px solid var(--color-border);
}

/* ---------- Hovertexte der Knoepfe (data-hinweis) ----------
   Warum eigene Blasen und nicht das `title`-Attribut: der Browser zeigt title
   erst nach etwa einer Sekunde, in seiner eigenen Schrift, an seiner eigenen
   Stelle — und auf Beruehrungsgeraeten gar nicht. Die Knoepfe oben rechts
   tragen NUR Zeichen, ihre Bedeutung muss also sofort lesbar sein.

   `aria-label` bleibt an den Knoepfen: die Blase ist Dekoration, die Vorlesehilfe
   liest weiterhin den Text. `title` ist entfernt, sonst standen zwei Hinweise
   uebereinander — der eigene sofort, der des Browsers eine Sekunde spaeter.

   Die Blase haengt am Knopf (position: absolute) und wird bei :hover UND
   :focus-visible gezeigt — wer mit der Tastatur durch die Kopfzeile geht, soll
   dasselbe sehen wie mit der Maus. */
[data-hinweis] {
    position: relative;
}

[data-hinweis]::after {
    content: attr(data-hinweis);
    position: absolute;
    top: calc(100% + 0.45rem);
    /* Rechtsbuendig, nicht mittig: die Knoepfe stehen am rechten Fensterrand,
       eine mittige Blase liefe dort hinaus. */
    right: 0;
    z-index: 60;
    padding: 0.3rem 0.55rem;
    border-radius: var(--radius);
    background: var(--color-text);
    color: var(--color-surface);
    font-size: 0.78rem;
    font-weight: 400;
    line-height: 1.3;
    white-space: nowrap;
    letter-spacing: 0;
    text-transform: none;
    opacity: 0;
    /* pointer-events: none, damit die Blase nicht den Klick abfaengt, wenn sie
       ueber dem naechsten Knopf liegt. */
    pointer-events: none;
    transition: opacity var(--duration) var(--ease);
}

[data-hinweis]:hover::after,
[data-hinweis]:focus-visible::after {
    opacity: 1;
}

/* Im Kartenfuss der Anmeldung ist unter den Knoepfen kein Platz — dort zeigt
   die Blase nach OBEN (siehe partials/auth-werkzeuge.php). */
.auth-werkzeuge [data-hinweis]::after {
    top: auto;
    bottom: calc(100% + 0.45rem);
}

/* Firmenname+Benutzer (company-info.php) ist der erste Topbar-Eintrag.
   margin-right:auto schiebt Sprache/Hell-Dunkel/Abmelden nach rechts, statt
   dass alles bei justify-content:flex-end als eine Gruppe zusammenklebt. */
/* HAUSNAME, ANMELDUNG UND DRUCKNAME — sie duerfen die Kopfzeile nicht
   auseinanderziehen.
   ─────────────────────────────────────────────────────────────────────────
   Gemessen: bei 1024 px stand der Block auf VIER Zeilen und die Kopfzeile war
   111 px hoch statt 60. Die Knoepfe rechts rutschten mit, und aus der ruhigen
   Leiste wurde ein Block, der bei jeder Fensterbreite anders aussah.

   Deshalb: der Block darf schrumpfen (min-width: 0 — ohne das schrumpft ein
   Flex-Element nicht unter die Breite seines Textes), der Hausname wird
   abgeschnitten statt umzubrechen, und auf schmalen Fenstern fallen Anmeldung
   und Druckname weg. Verloren geht dabei nichts: beide stehen im Benutzermenue
   daneben. */
.topbar-company {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    margin-left: -8px;
    margin-right: auto;
    padding: 0.45rem 1rem;
    font-weight: 600;
    font-size: 1.1rem;
    color: var(--color-text);
}

.topbar-company-name,
.topbar-company-user {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Der Block bleibt EINE Zeile. Ohne das umbrachen die drei Angaben untereinander
   und machten aus 60 px Kopfzeile 111. */
.topbar-company {
    flex-wrap: nowrap;
}

@media (max-width: 1200px) {
    .topbar-company-user,
    .topbar-company-sep {
        display: none;
    }
}

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

.topbar-company-user {
    font-weight: 400;
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

/* Chevron-Icon-Stil wird weiterhin vom "Dokument ansehen"-Dropdown im
   Buchungsdetail verwendet (bookings/detail.php), siehe .doc-view-popup. */
.topbar-agency-chevron {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    color: var(--color-text-muted);
}

.topbar-logout {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Hoehe und Breite kommen aus der gemeinsamen Regel der Kopfzeile (siehe
       ".topbar .theme-toggle, ..."). Hier standen 36 x 36 px fest — der einzige
       Knopf der Reihe mit eigenem Mass, und deshalb der einzige, der nicht
       mitwuchs. Quadratisch bleibt er ueber min-width dort. */
    border: none;
    cursor: pointer;
    border-radius: var(--radius-pill);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    box-shadow: var(--shadow-sm);
    transition: transform 0.1s ease, box-shadow 0.1s ease, background-color 0.15s ease;
}

/* Benutzermenü hinter dem Logout-Knopf: Loginname/E-Mail/Filiale, Logout unten. */
/* DIE HALTER DER AUFKLAPPFELDER — Benutzermenue, Schnellsuche, News.
   Derselbe Rumpf stand dreimal in der Datei; das Feld haengt in allen drei
   Faellen am Knopf (position: relative), und der Knopf steht in der Reihe der
   Kopfzeile (inline-flex). Das Verhalten dazu steht ebenfalls an EINER Stelle,
   siehe partials/popover.php. */
.user-menu,
.suche-halter,
.news-knopf-halter {
    position: relative;
    display: inline-flex;
}

/* Der KASTEN eines Aufklappfeldes. Er sah zweimal fast gleich aus
   (.doc-view-popup fuer Dokumente, Sprache und Spaltenwahl, .user-menu-popup
   fuer das Benutzermenue) — gleiche Flaeche, gleicher Rahmen, gleicher
   Schatten, andere Zahlen fuer Mindestbreite und Ebene. Die gemeinsame Form
   steht jetzt einmal da; was die beiden unterscheidet, steht darunter.

   z-index 60 fuer beide: vorher lag das Benutzermenue ueber dem anderen, und
   ein Kasten, der je nach Herkunft auf einer anderen Ebene liegt, ueberdeckt
   frueher oder spaeter den falschen Nachbarn. */
.doc-view-popup,
.user-menu-popup {
    display: none;
    position: absolute;
    top: calc(100% + 0.45rem);
    right: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: 0.5rem;
    z-index: 60;
}

.doc-view-popup.visible,
.user-menu-popup.visible {
    display: block;
}

.user-menu-popup {
    min-width: 230px;
}

.user-menu-row {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.35rem 0.6rem;
}

.user-menu-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

.user-menu-value {
    font-size: 0.85rem;
    color: var(--color-text);
    word-break: break-all;
}

.user-menu-logout {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 0.4rem;
    padding: 0.5rem 0.6rem;
    border-top: 1px solid var(--color-border);
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    color: var(--color-danger-text);
    font-size: 0.85rem;
    font-weight: 500;
    text-decoration: none;
    transition: background-color var(--duration) var(--ease);
}

.user-menu-logout .icon {
    width: 15px;
    height: 15px;
}

.user-menu-logout:hover {
    background: var(--color-primary-soft);
}

.topbar-logout .icon {
    width: 16px;
    height: 16px;
}

.topbar-logout:hover {
    background: var(--color-danger);
    transform: translateY(-1px);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.18);
}

.content {
    /* Oben und unten weniger als seitlich: die Hoehe ist in den Arbeitslisten
       knapp, die Breite nicht. */
    padding: 1.25rem 2rem 2rem;
}

/* Die Seitenueberschrift stand hier einmal auf 1.55rem, weil eine Liste mit
   Suchleiste, Kacheln und Tabellenkopf ohnehin viel Vorlauf hat. Der Auftakt
   war das Problem, nicht der Schriftgrad — und er steckte vor allem im ABSTAND
   darunter (0.67em = 21px vom Browser). Die Groesse kommt jetzt aus der
   zentralen h1-Regel (30px), der knappe Abstand bleibt (siehe unten). */

/* Ein einfaches "<h1>Titel</h1>" (Listen/Agenturdaten/...) bekommt sonst den
   Browser-Standardabstand über der Überschrift — das Dashboard sitzt höher,
   weil sein h1 in .page-title-row liegt (margin:0). Gleiche Starthöhe für alle. */
.content > h1:first-child {
    margin-top: 0;
}

.content > h1 {
    margin-bottom: 0.9rem;
}

.page-title-row {
    display: flex;
    /* wrap, weil die Zeile jetzt die Werkzeugleiste traegt: auf schmalem Schirm
       rutschen die Knoepfe unter den Titel statt ihn zu quetschen. */
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-3);
    /* Derselbe Abstand nach unten, den ein <h1> von sich aus mitbringt (0.67em
       bei 2rem Schrift = 21px): das h1 darin traegt margin: 0, und ohne diese
       Zeile klebt die Suchleiste am Titel — im Kontenblatt sichtbar, waehrend
       Buchungsliste und Offene Posten 21px Luft hatten. */
    margin-bottom: 0.9rem;
}


/* ═══════════════════════════════════════════════════════════════════════════
   WERKZEUGLEISTE IN DER TITELZEILE
   ═══════════════════════════════════════════════════════════════════════════
   Export, Spalten und "Neu ..." standen bisher zwischen den Kacheln und der
   Tabelle — mitten in der Seite, und in jeder Liste auf einer anderen Hoehe, je
   nachdem wie viele Kacheln und Filterzeilen darueber lagen. Jetzt stehen sie
   rechts neben der Ueberschrift: eine feste Stelle, oben, in ALLEN Listen
   dieselbe.

   margin-left: auto schiebt sie an den rechten Rand. align-self: center, weil
   die Titelzeile ihre Textteile an der GRUNDLINIE ausrichtet (Titel und
   Unterzeile) — Knoepfe haengen daran schief.
   ═══════════════════════════════════════════════════════════════════════════ */
.page-title-row .list-toolbar {
    margin: 0 0 0 auto;
    align-self: center;
}

.page-title-row h1 {
    margin: 0;
}

.page-title-sub {
    margin: 0;
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

/* ---------- Dashboard cards ---------- */

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-3);
    /* OBEN UND UNTEN DERSELBE ABSTAND — die Kachelreihe steht zwischen der
       Suchmaske und der Tabelle, und sie soll zu beiden gleich weit weg sein.

       Vorher war es 0.9rem oben gegen 1.5rem unten: der untere Abstand kam von
       der Werkzeugleiste, die frueher dazwischen stand (margin: 16px 0) und
       nach ihrem Umzug neben die Ueberschrift durch einen eigenen Wert ersetzt
       wurde — der zufaellig groesser ausfiel als der obere. Ein Wert fuer
       beide, aus der Abstandsskala, und die Reihe sitzt mittig.

       Gilt fuer JEDES Modul: die Klasse traegt die Kachelreihe in allen Listen
       (Buchungen, Offene Posten, Mahnwesen, Zahlungen, Abrechnungen,
       Statistik). */
    margin-top: var(--space-4);
    margin-bottom: var(--space-4);
}

/* Flexbox instead of the auto-fill grid above: with only two cards, auto-fill can
   reserve extra empty column tracks on wide screens instead of letting the two
   real cards split the row evenly. */
.detail-info-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.detail-info-row .card {
    flex: 1 1 300px;
}

.detail-info-col {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    flex: 1 1 300px;
}

.detail-info-col .card {
    flex: none;
}

.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-6);
}

/* Ein Knopf UNMITTELBAR NACH EINER KARTE: Abstand nach oben, und er steht
   RECHTS. In den sechs Erfassungsmasken (Agentur, Kunde, Lieferant,
   Fluggesellschaft, Hotel, Mitarbeiter) ist "Speichern" ein direktes Kind des
   Formulars hinter der Karte — ohne eigene Klasse, also ohne Abstand und links
   ausgerichtet: er klebte an der Unterkante der Karte und sah aus, als gehoere
   er noch hinein.

   Rechts, weil dort auch die Knoepfe der Dialoge, der Werkzeugleisten und der
   Assistenten-Navigation stehen — die Stelle, an der man in dieser Anwendung
   nach der abschliessenden Aktion sucht.

   `display: flex` statt des inline-flex der Grundregel, weil `margin-left:auto`
   nur an einem Element auf Blockebene wirkt; `width: fit-content` haelt den
   Knopf dabei so breit wie sein Text — ein Flexelement auf Blockebene wuerde
   sonst die ganze Zeile ausfuellen.

   Als Nachbar-Regel und nicht als neue Klasse in sechs Vorlagen: das Muster
   "Karte, dann Knopf" ist die Aussage, und es gilt fuer jede kuenftige Maske
   mit demselben Aufbau mit. */
.card + .button-primary,
.card + button[type="submit"] {
    display: flex;
    width: fit-content;
    margin: var(--space-6) 0 0 auto;
}

.card h2 {
    margin: 0 0 0.75rem;
    font-size: 1rem;
}

.totp-secret {
    display: inline-block;
    font-family: var(--schrift-mono);
    font-size: 1.3rem;
    letter-spacing: 0.1em;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.75rem 1.25rem;
    margin: 0.5rem 0 1.25rem;
}

.card ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.card ul a {
    font-size: 0.9rem;
    color: var(--color-primary);
}

.card ul a:hover {
    text-decoration: underline;
}

/* ---------- Auth (login) ---------- */

.auth-body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.auth-main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
}

/* ---------------------------------------------------------------------------
   ANMELDESEITE ALS EINSEITER
   (templates/login.php, partials/login-info.php, partials/login-baender.php)

   Kopf mit Aussage und Anmeldemaske, darunter drei Baender. Alles aus den
   Farbvariablen der Anwendung — die Seite muss in Hell UND Dunkel stimmen, und
   ein zweites Farbsystem waere eine zweite Baustelle.

   KEINE Bilder ausser dem vorhandenen Logo: der Server hat keinen Zugang nach
   draussen, und eine Grafik je Sprache waere nicht zu pflegen. Der Hintergrund
   entsteht aus zwei weichen Farbverlaeufen und einem Punktraster — das kostet
   nichts und bleibt bei jeder Fenstergroesse scharf.
   --------------------------------------------------------------------------- */
.auth-body:has(.lp) .auth-main {
    /* Der Einseiter fuellt die Breite selbst; die zentrierte Box der uebrigen
       Anmeldemasken (Passwort vergessen, 2FA) wuerde ihn einschnueren. */
    align-items: flex-start;
    padding: 0;
}

.lp {
    width: 100%;
    /* Der Hintergrund: zwei weiche Kreise in der Markenfarbe und ein feines
       Punktraster darueber. `fixed` haelt sie beim Rollen still, damit die
       Baender darueber laufen statt mitzuschwimmen. */
    background-image:
        radial-gradient(42rem 28rem at 12% -6%, var(--color-primary-soft), transparent 70%),
        radial-gradient(34rem 24rem at 92% 4%, var(--color-primary-soft), transparent 68%),
        radial-gradient(var(--color-border) 1px, transparent 1px);
    background-size: auto, auto, 26px 26px;
    background-attachment: fixed, fixed, fixed;
}

/* Beim zweiten Anmeldeschritt bleibt nur die Karte — dann soll die Seite
   aussehen wie vorher: mittig, ohne Baender. */
.lp-nur-karte {
    background: none;
}

.lp-nur-karte .lp-hero {
    justify-content: center;
    padding: 3rem 1rem;
}

/* ---------- Kopf: Aussage links, Anmeldung rechts ---------- */
.lp-hero {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4rem;
    max-width: 1180px;
    margin: 0 auto;
    padding: 4.5rem 1.5rem 4rem;
}

.lp-hero-text {
    flex: 1 1 520px;
    min-width: 0;
    max-width: 620px;
}

.lp-claim {
    margin: 0 0 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-primary);
}

/* Die Aussage traegt die Seite: gross, eng gesetzt, mit einem Farbverlauf im
   Text. clamp() statt einer festen Groesse — auf einem Notebook soll sie nicht
   dieselbe Hoehe fressen wie auf einem 27-Zoll-Schirm. */
.lp-titel {
    margin: 0 0 1rem;
    font-size: clamp(2rem, 3.4vw, 3.1rem);
    line-height: 1.08;
    letter-spacing: -0.02em;
    background: linear-gradient(100deg, var(--color-text) 30%, var(--color-primary));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.lp-text {
    margin: 0 0 2rem;
    max-width: 48ch;
    font-size: 1.02rem;
    line-height: 1.6;
    color: var(--color-text-muted);
}

/* Drei Kennzahlen, durch senkrechte Linien getrennt. */
/* Der zweite Absatz im Kopf: eine Nummer kleiner als der erste, damit die
   beiden nicht als ein Block von sechs Zeilen lesen. Er nennt die
   Leistungsarten (siehe partials/login-info.php). */
.lp-text-zwei {
    margin-top: 0.9rem;
    font-size: 0.92rem;
}

/* Die Anmeldekarte im Kopf: etwas hoeher gesetzt und mit deutlicherem
   Schatten, damit sie vor dem Hintergrund steht. */
.lp .auth-card {
    flex: 0 0 auto;
    box-shadow: 0 24px 60px rgba(15, 20, 40, 0.18);
}

/* ---------- Selbst gezeichnete Bilder ----------
   Drei Sorten, alle INLINE eingebunden — nur so folgen sie den Farbvariablen
   und zeichnen in Hell und Dunkel richtig; ein <img> kennt die Variablen nicht:

     login-himmel.php      der Himmel hinter dem Kopf, mit Flugzeug
     login-icon-gross.php  die flaechigen Zeichen der Vorteile
     login-modul-bild.php  die acht kleinen Bilder der Modulkacheln

   Notebook und Telefon (login-geraete.php) sind KEIN SVG, sondern Auszeichnung
   mit CSS — dort steht echter, uebersetzter Text.
   ------------------------------------------------------------------------- */

/* Der HIMMEL liegt hinter dem ganzen Kopf und wird oben und unten weich
   ausgeblendet, damit er in die Seite uebergeht statt als Kasten zu enden.

   z-index: 0 hier und 1 an Text und Karte ist NOETIG: ein absolut gesetztes
   Element zeichnet ueber seinen statischen Geschwistern, auch wenn es im
   Quelltext davor steht. Ohne die Stapelung lag der Himmel ueber der
   Anmeldemaske. */
.lp-himmel {
    position: absolute;
    z-index: 0;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    /* Unten ausblenden: der Uebergang zum ersten Band soll nicht als Kante
       sichtbar sein. */
    mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
}

/* Der Kasten ueber die ganze Breite: er traegt den Himmel und beschneidet ihn
   (overflow), die Spalten darin bleiben auf 1180px. */
.lp-kopf {
    position: relative;
    overflow: hidden;
}

.lp-hero {
    position: relative;
}

.lp-hero-text,
.lp .auth-card {
    position: relative;
    z-index: 1;
}

/* ---- Farben des Himmels ----
   Hell: ein Tag gegen die Sonne. Dunkel: dieselbe Szene nach Sonnenuntergang.
   Beide Male IM SVG ueber Klassen gesetzt, nicht als Attribut — sonst waere
   der Dunkelmodus ein zweites Bild.

   Die Toene sind AUFHELLUNGEN DER MARKENFARBE (#1b3fc4) und nicht irgendein
   Blau: das Bild steht auf derselben Seite wie Knoepfe und Verweise in eben
   dieser Farbe. Als der Marken-Ton noch #4f6ef7 war, passte das von selbst —
   nach dem Wechsel auf das tiefere Blau stand hier ein Himmel aus dem alten
   Farbkreis. Feste Werte und keine Variablen, weil ein Verlauf Zwischenstufen
   braucht, die es als Marke nicht gibt. */
.himmel-oben  { stop-color: #c9d6f2; }
.himmel-mitte { stop-color: #e2e9f8; }
.himmel-unten { stop-color: #f4f7fb; }
.sonne-kern   { stop-color: #ffffff; stop-opacity: 0.95; }
.sonne-rand   { stop-color: #ffffff; stop-opacity: 0; }

.wolke-fern   { fill: #ffffff; opacity: 0.55; }
.wolke-mittel { fill: #ffffff; opacity: 0.8; }
.wolke-nah    { fill: #ffffff; opacity: 0.95; }

.himmel-netz path {
    fill: none;
    stroke: var(--color-primary);
    stroke-width: 1.5;
    opacity: 0.35;
}

.himmel-netz circle {
    fill: var(--color-primary);
    opacity: 0.5;
}

.himmel-netz .netz-stark {
    opacity: 0.9;
}

/* Das Flugzeug in Draufsicht: Rumpf hell, Flaechen einen Ton dunkler (so
   liest man die Tiefe), Leitwerk in der Markenfarbe, Triebwerke grau. Der
   Kondensstreifen ist eine Linie mit weichem Ende. */
.flug-rumpf     { fill: #f7f9fd; }
.flug-fluegel   { fill: #ccd6ea; }
.flug-leitwerk  { fill: #1b3fc4; }
.flug-triebwerk { fill: #8b99b6; }
.flug-cockpit   { fill: #7b89a8; }
.flug-fenster   { stroke: #bfcadf; stroke-width: 3; stroke-linecap: round; }

.flug-streifen {
    fill: none;
    stroke: #ffffff;
    stroke-width: 9;
    stroke-linecap: round;
    opacity: 0.3;
}

.flug-streifen-zart {
    stroke-width: 6;
    opacity: 0.18;
}

.horizont-land  { fill: #dbe3f3; opacity: 0.75; }
.horizont-linie { fill: none; stroke: #bfcbe6; stroke-width: 1.5; }

/* Nach Sonnenuntergang: derselbe Aufbau, andere Werte. Beide Schreibweisen,
   weil der Dunkelmodus per Umschalter (data-theme) UND per Systemeinstellung
   (prefers-color-scheme) kommen kann. */
[data-theme="dark"] .himmel-oben  { stop-color: #0a1120; }
[data-theme="dark"] .himmel-mitte { stop-color: #121b30; }
[data-theme="dark"] .himmel-unten { stop-color: #131a23; }
[data-theme="dark"] .sonne-kern   { stop-color: #35529b; stop-opacity: 0.5; }
[data-theme="dark"] .wolke-fern   { fill: #1d2740; opacity: 0.7; }
[data-theme="dark"] .wolke-mittel { fill: #24304e; opacity: 0.75; }
[data-theme="dark"] .wolke-nah    { fill: #2f4068; opacity: 0.8; }
[data-theme="dark"] .flug-rumpf     { fill: #b9c6de; }
[data-theme="dark"] .flug-fluegel   { fill: #8496b8; }
[data-theme="dark"] .flug-triebwerk { fill: #62729116; }
[data-theme="dark"] .flug-cockpit   { fill: #4e5d7d; }
[data-theme="dark"] .flug-fenster   { stroke: #93a3c0; }
[data-theme="dark"] .flug-streifen  { stroke: #6f83ab; opacity: 0.35; }
[data-theme="dark"] .horizont-land  { fill: #1d2740; opacity: 0.8; }
[data-theme="dark"] .horizont-linie { stroke: #2c3a5c; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .himmel-oben  { stop-color: #0a1120; }
    :root:not([data-theme="light"]) .himmel-mitte { stop-color: #121b30; }
    :root:not([data-theme="light"]) .himmel-unten { stop-color: #131a23; }
    :root:not([data-theme="light"]) .sonne-kern   { stop-color: #35529b; stop-opacity: 0.5; }
    :root:not([data-theme="light"]) .wolke-fern   { fill: #1d2740; opacity: 0.7; }
    :root:not([data-theme="light"]) .wolke-mittel { fill: #24304e; opacity: 0.75; }
    :root:not([data-theme="light"]) .wolke-nah    { fill: #2f4068; opacity: 0.8; }
    :root:not([data-theme="light"]) .flug-rumpf     { fill: #b9c6de; }
    :root:not([data-theme="light"]) .flug-fluegel   { fill: #8496b8; }
    :root:not([data-theme="light"]) .flug-triebwerk { fill: #627291; }
    :root:not([data-theme="light"]) .flug-cockpit   { fill: #4e5d7d; }
    :root:not([data-theme="light"]) .flug-fenster   { stroke: #93a3c0; }
    :root:not([data-theme="light"]) .flug-streifen  { stroke: #6f83ab; opacity: 0.35; }
    :root:not([data-theme="light"]) .horizont-land  { fill: #1d2740; opacity: 0.8; }
    :root:not([data-theme="light"]) .horizont-linie { stroke: #2c3a5c; }
}

/* Auf schmalen Fenstern bleibt der Himmel, aber flacher: dort steht die
   Anmeldemaske oben, und ein hohes Bild schoebe sie aus dem Blick. */
@media (max-width: 900px) {
    .lp-himmel {
        height: 22rem;
        mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
        -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
    }
}

/* ---------- Notebook und Telefon (partials/login-geraete.php) ----------
   Der ganze Aufbau haengt an EINER Zahl: der Schriftgroesse hier. Alles innen
   ist in `em` gesetzt — Rahmen, Abstaende, Balkenhoehen. Damit skaliert das
   Geraet als Ganzes und bricht nicht um; und wer es groesser will, aendert
   diese eine Regel.

   clamp(5.6px, 0.62vw, 9px): bei 1600px Fenster sind es 9px (Notebook rund
   560px breit), auf einem Telefon 5.6px (rund 350px). Unter 5.6px wird die
   Schrift zu Grau — dann traegt die Zeile darunter die Aussage. */
/* Geraete und Bildunterschrift in einer Spalte. Ohne diesen Kasten war die
   Unterschrift ein drittes Feld im Gitter von .lp-blatt-innen und stand links
   unter den Vorteilen — weit weg von dem, was sie beschreibt. */
.lp-blatt-geraete {
    display: grid;
    justify-items: center;
}

/* NEBENEINANDER, nicht uebereinander: auf dem Werbeblatt liegt das Telefon auf
   dem Notebook, dort aber ueber Himmel und Landschaft. Hier lag es ueber der
   Liste "Letzte Buchungen" und ueber der dritten Kachel — verdeckt war genau
   das, was den Bildschirm ausmacht. Also stehen beide neben einander, am
   unteren Rand ausgerichtet wie auf einem Tisch. */
/* Das Telefon liegt auf der Notebook-Kante — wie auf dem Werbeblatt. Damit es
   nichts Wichtiges verdeckt, sind unten im Bildschirm die Karten getauscht:
   die LISTE steht links, das DIAGRAMM rechts. Verdeckt wird also nur das Ende
   der Balken, nicht eine Zeile mit Zahlen. */
.lp-geraete {
    position: relative;
    width: 100%;
    font-size: clamp(5.6px, 0.62vw, 9px);
}

.nb {
    /* 88%: der Rest ist die Standflaeche des Telefons. */
    width: 88%;
}

/* --- Notebook --- */
.nb-rahmen {
    /* Das Gehaeuse: dunkel in HELL und DUNKEL. Ein Notebook ist ein Gegenstand,
       kein Teil der Oberflaeche — es wechselt die Farbe nicht mit dem Thema.
       Der Bildschirm DARIN tut es (er zeigt die Anwendung). */
    background: linear-gradient(160deg, #4a5568 0%, #2c3444 100%);
    border-radius: 1.6em 1.6em 0.5em 0.5em;
    padding: 1.1em 1.1em 1.4em;
    box-shadow: 0 3em 5em rgba(15, 20, 40, 0.28);
}

.nb-schirm {
    display: grid;
    grid-template-columns: 11.5em 1fr;
    height: 38em;
    overflow: hidden;
    background: var(--color-bg);
    border-radius: 0.5em;
}

/* Der Fuss: ein Trapez, damit man das Geraet von vorn-oben sieht. clip-path
   statt einer Grafik — eine Form, vier Punkte. */
/* `margin-left: -8%` und NICHT `margin: 0 auto`: bei 116% Breite ist das
   Element breiter als sein Kasten, und dann greift `auto` nicht — der Fuss
   stand um 16% nach rechts versetzt und ragte als dunkler Keil aus dem
   Notebook heraus. */
.nb-fuss {
    height: 1.1em;
    width: 110%;
    margin-left: -5%;
    background: linear-gradient(180deg, #3a4456 0%, #202836 100%);
    clip-path: polygon(0 0, 100% 0, 96% 100%, 4% 100%);
    border-radius: 0 0 0.6em 0.6em;
}

.nb-menue {
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    padding: 1em 0.7em;
}

.nb-marke {
    padding: 0 0.5em 1em;
    font-size: 1.5em;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--color-primary);
}

.nb-menue-zeile {
    display: flex;
    align-items: center;
    gap: 0.6em;
    padding: 0.5em;
    border-radius: 0.4em;
    font-size: 1.05em;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.nb-menue-aktiv {
    background: var(--color-primary-soft);
    color: var(--color-primary);
    font-weight: 600;
}

/* Die Zeichen aus Support\Icon sind auf 16px gebaut und tragen width/height
   im Attribut. Hier muessen sie mitschrumpfen — deshalb die Groesse in em. */
.lp-geraete .icon {
    width: 1.3em;
    height: 1.3em;
    flex: 0 0 auto;
}

.nb-inhalt {
    padding: 1.2em;
    display: grid;
    grid-template-rows: auto auto 1fr;
    gap: 1em;
}

.nb-titel {
    font-size: 1.5em;
    font-weight: 600;
}

.nb-kacheln {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.8em;
}

.nb-kachel {
    display: grid;
    gap: 0.3em;
    padding: 0.8em;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 0.5em;
}

.nb-kachel span {
    font-size: 0.95em;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nb-kachel strong {
    font-size: 1.5em;
    letter-spacing: -0.01em;
}

/* Liste links (2fr), Diagramm rechts (3fr) — siehe .lp-geraete: rechts liegt
   das Telefon auf, und Balken darf es verdecken, Zahlen nicht. */
.nb-unten {
    display: grid;
    grid-template-columns: 2fr 3fr;
    gap: 0.8em;
    min-height: 0;
}

.nb-karte {
    display: flex;
    flex-direction: column;
    padding: 0.8em;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 0.5em;
}

.nb-karte-titel {
    font-size: 1.05em;
    font-weight: 600;
    margin-bottom: 0.7em;
}

/* Das Diagramm: Balkenpaare, Hoehe in Prozent der Karte — dieselbe Sprache wie
   die Verkaufszahlen im echten Dashboard. */
.nb-diagramm {
    flex: 1;
    display: flex;
    align-items: flex-end;
    gap: 0.9em;
    padding-bottom: 0.4em;
    border-bottom: 1px solid var(--color-border);
}

.nb-paar {
    flex: 1;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 0.2em;
    height: 100%;
}

.nb-paar i {
    display: block;
    width: 0.9em;
    background: var(--color-primary);
    border-radius: 0.15em 0.15em 0 0;
}

.nb-balken-blass {
    opacity: 0.4;
}

.nb-legende {
    display: flex;
    gap: 1em;
    margin-top: 0.6em;
    font-size: 0.95em;
    color: var(--color-text-muted);
}

.nb-legende span {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
}

/* Der Punkt vor dem Legendenwort — ein ::before statt eines weiteren
   Elementes im HTML. */
.nb-legende span::before {
    content: "";
    width: 0.7em;
    height: 0.7em;
    border-radius: 0.15em;
    background: var(--color-primary);
}

.nb-legende-blass::before {
    opacity: 0.4;
}

/* Zwei Zeilen je Buchung: Nummer + Betrag, darunter Ziel + Zahlungsstand. */
.nb-zeile {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.15em 0.6em;
    padding: 0.5em 0;
    font-size: 1em;
    border-bottom: 1px solid var(--color-border);
}

.nb-nummer {
    font-weight: 600;
    color: var(--color-primary);
}

.nb-ziel {
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nb-betrag {
    font-variant-numeric: tabular-nums;
}

.nb-pille {
    justify-self: end;
    padding: 0.1em 0.6em;
    border-radius: 1em;
    font-size: 0.9em;
    font-weight: 600;
    white-space: nowrap;
}

/* Bezahlt gruen, offen gelb — dieselbe Bedeutung wie in den Listen der
   Anwendung. `color-mix` fuer den Grund: eine Farbe genuegt dann je Zustand,
   und im Dunkelmodus wird der Grund von selbst dunkler. */
.nb-pille-ok {
    background: color-mix(in srgb, var(--color-success) 16%, transparent);
    color: var(--color-success-text);
}

.nb-pille-offen {
    background: color-mix(in srgb, var(--color-warning) 18%, transparent);
    color: var(--color-warning-text);
}

/* --- Telefon ---
   Es liegt UEBER der unteren rechten Ecke des Notebooks, wie auf dem Blatt. */
.tf {
    position: absolute;
    right: 0;
    /* Unterkante auf der Linie des Notebook-Fusses. */
    bottom: 0;
    width: 15.5em;
}

.tf-rahmen {
    position: relative;
    background: linear-gradient(160deg, #3a4456 0%, #1c2331 100%);
    border-radius: 2em;
    padding: 0.7em;
    box-shadow: 0 2em 3.5em rgba(15, 20, 40, 0.34);
}

/* Der Hoererschlitz oben — ein ::before statt eines Elementes im HTML. Er
   macht aus dem Rechteck ein Telefon. */
.tf-rahmen::before {
    content: "";
    position: absolute;
    top: 1.3em;
    left: 50%;
    transform: translateX(-50%);
    width: 4em;
    height: 0.45em;
    border-radius: 0.3em;
    background: #131a26;
    z-index: 1;
}

/* min-height fuer die Hochkantform: das Telefon ist 17em breit, mit 34em Hoehe
   liegt das Verhaeltnis bei 1:2 — so sieht ein Telefon aus. Ohne die Angabe
   richtete es sich nach dem Inhalt und wurde fast quadratisch.
   `align-content: start`, damit die Felder oben stehen und der Platz unten
   frei bleibt, statt die Abstaende auseinanderzuziehen. */
/* 26em Hoehe: das Telefon ist 15.5em breit, das ergibt gut 1:1.8. Mit 34em war
   es 1:2.3 — richtig fuer ein echtes Telefon, aber neben dem Notebook sah es
   aus wie eine Leiste. */
.tf-schirm {
    background: var(--color-bg);
    border-radius: 1.5em;
    padding: 2.2em 0.9em 1.2em;
    min-height: 26em;
    display: grid;
    align-content: start;
    gap: 0.6em;
}

.tf-kopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--color-text-muted);
}

.tf-marke {
    font-size: 1.35em;
    font-weight: 600;
    color: var(--color-primary);
}

.tf-titel {
    font-size: 1.2em;
    font-weight: 600;
}

.tf-feld {
    display: grid;
    gap: 0.1em;
    padding: 0.5em 0.6em;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 0.45em;
}

.tf-feld span {
    font-size: 0.9em;
    color: var(--color-text-muted);
}

.tf-feld strong {
    font-size: 1.05em;
}

.tf-knopf {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4em;
    margin-top: 0.2em;
    padding: 0.6em;
    border-radius: 0.45em;
    background: var(--color-primary);
    color: var(--auf-farbflaeche)fff;
    font-size: 1em;
    font-weight: 600;
    text-align: center;
}

.tf-knopf .icon {
    color: var(--auf-farbflaeche)fff;
}

.tf-bezahlt {
    display: flex;
    align-items: center;
    gap: 0.4em;
    font-size: 1em;
    font-weight: 600;
    color: var(--color-success-text);
}

.lp-geraete-text {
    max-width: 34rem;
    margin: 1.4rem 0 0;
    text-align: center;
    font-size: 0.84rem;
    line-height: 1.55;
    color: var(--color-text-muted);
}

/* ---------- Die kleinen Zeichnungen in den Modulkacheln ----------
   Die .mock-*-Klassen kommen aus dem frueheren, selbst gezeichneten Abbild der
   Anwendung. Das Abbild selbst ist weg — an seiner Stelle stehen jetzt Notebook
   und Telefon aus echtem HTML (partials/login-geraete.php). Die Klassen sind
   geblieben, weil die acht Modulbilder sie benutzen
   (partials/login-modul-bild.php): Flaeche, Linie, Zeile, Kachel, Balken. */
.mock-flaeche {
    fill: var(--color-surface);
    stroke: var(--color-border);
}

.mock-linie {
    stroke: var(--color-border);
    stroke-width: 1;
    fill: none;
}

.mock-karte,
.mock-feld {
    fill: var(--color-bg);
    stroke: var(--color-border);
    stroke-width: 1;
}

/* Die Zeilen sind ANGEDEUTETER Text: graue Balken, keine Schrift. Damit
   behauptet das Bild keine Zahlen und veraltet nicht mit der naechsten
   Maskenaenderung. */
.mock-zeile {
    fill: var(--color-text-muted);
    opacity: 0.35;
}

.mock-kopf {
    fill: var(--color-text-muted);
    opacity: 0.55;
}

.mock-punkt {
    fill: var(--color-border);
}

.mock-marke,
.mock-wert {
    fill: var(--color-primary);
    opacity: 0.85;
}

.mock-marke-klein {
    fill: var(--color-primary);
    opacity: 0.25;
}

.mock-aktiv {
    fill: var(--color-primary-soft);
}

.mock-balken {
    fill: var(--color-primary);
}

.mock-balken-blass {
    fill: var(--color-primary);
    opacity: 0.35;
}

/* Nur in den kleinen Modulbildern gebraucht (partials/login-modul-bild.php):
   der Pfeil der CRS-Uebernahme, die Verlaufslinie der Statistik und die eine
   faellige Zeile in der Abrechnung. */
.mock-pfeil {
    stroke: var(--color-primary);
    stroke-width: 2;
    fill: none;
}

.mock-pfeil-spitze {
    fill: var(--color-primary);
}

.mock-verlauf {
    fill: none;
    stroke: var(--color-primary);
    stroke-width: 2;
    stroke-linejoin: round;
    opacity: 0.65;
}

.mock-warnung {
    fill: var(--color-danger);
    opacity: 0.75;
}

/* ---------- Baender ---------- */
.lp-band {
    max-width: 1180px;
    margin: 0 auto;
    padding: 3.5rem 1.5rem;
}

/* Ein ruhiges Band mit eigenem Grund: es gliedert die Seite, ohne eine Linie
   zu ziehen. Der GRUND laeuft ueber die ganze Breite, der INHALT bleibt auf
   derselben Kante wie die uebrigen Baender — sonst rutscht die Ueberschrift
   "Module" 200 Pixel nach links und die Seite hat zwei Raender.

   Geloest mit einer inneren Begrenzung statt max-width am Band selbst: das
   Band braucht die volle Breite fuer seinen Grund, der Inhalt nicht. */
.lp-band-ruhig {
    max-width: none;
    padding-left: 0;
    padding-right: 0;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
}

/* ZWEI Klassen im Waehler, und das ist der Grund: `*` hat in CSS keine
   Staerke, `.lp-band-ruhig > *` waere also genauso stark wie `.lp-band-titel`
   weiter unten — und die spaetere Regel setzt margin: 0. Die Ueberschrift
   "Module" stand damit am linken Fensterrand statt auf der Kante der uebrigen
   Baender. */
.lp-band.lp-band-ruhig > * {
    max-width: 1180px;
    margin-left: auto;
    margin-right: auto;
    padding-left: 1.5rem;
    padding-right: 1.5rem;
}

.lp-band-titel {
    margin: 0 0 1.75rem;
    font-size: 1.45rem;
    letter-spacing: -0.01em;
}

.lp-band-text {
    margin: -1.25rem 0 1.75rem;
    max-width: 60ch;
    color: var(--color-text-muted);
}

/* Vier Karten mit Zeichen, Titel, Satz. auto-fit: aus vier Spalten werden zwei
   und dann eine, ohne dass es dafuer eine Medienabfrage braucht. */
/* ---------- Die MITTE der Seite: das Werbeblatt, nachgebaut ----------
   Aufbau wie auf dem Blatt: links Aussage und Vorteile, rechts Notebook und
   Telefon, darunter der dunkle Streifen. Siehe partials/login-blatt.php.

   Eigener Grund und volle Breite, damit der Abschnitt als ein Stueck liest —
   wie ein Blatt, das man in die Seite gelegt hat. */
.lp-blatt {
    margin-top: 1rem;
    /* Der Notebook-Fuss ist breiter als der Deckel (so sieht ein Notebook aus).
       Bei schmalen Fenstern ragte er aus dem Fenster und die ganze Seite liess
       sich nach rechts schieben. Hier abgeklemmt — am Bandrand sieht man das
       nicht, weil das Band ueber die ganze Breite laeuft. */
    overflow: hidden;
    background:
        radial-gradient(80% 60% at 78% 12%, var(--color-primary-soft) 0%, transparent 60%),
        linear-gradient(180deg, var(--color-surface) 0%, var(--color-bg) 100%);
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
}

.lp-blatt-innen {
    max-width: 1180px;
    margin: 0 auto;
    padding: 3rem 1.5rem 2.5rem;
    display: grid;
    /* 5 zu 7: die Geraete brauchen die breitere Haelfte, sonst wird der
       Bildschirm darin zu klein, um etwas zu zeigen. */
    grid-template-columns: 5fr 7fr;
    gap: 2.5rem;
    align-items: center;
}

.lp-blatt-marke {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 0.35rem;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-primary);
}

.lp-blatt-unter {
    margin: 0 0 1.75rem;
    font-size: 0.9rem;
    line-height: 1.6;
    color: var(--color-text-muted);
}

/* Die Vorteile: Zeichen in einer Plakette, daneben Titel und Satz — die Zeile
   vom Blatt. */
.lp-punkte {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 1.15rem;
}

.lp-punkt {
    display: flex;
    align-items: flex-start;
    gap: 0.9rem;
}

.lp-punkt-bild {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.9rem;
    height: 2.9rem;
    border-radius: var(--radius);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
}

/* Das grosse Zeichen sitzt hier in einer Plakette und ist entsprechend
   kleiner als im Kopf einer Kachel. */
.lp-punkt-bild .lp-icon-gross {
    width: 1.85rem;
    height: 1.85rem;
    margin: 0;
}

/* Aussparungen im Zeichen tragen die Farbe DER PLAKETTE, nicht die des
   Bandes — hier liegt das Zeichen auf --color-surface. */
.lp-punkt-bild .lp-icon-negativ {
    fill: var(--color-surface);
}

.lp-punkt-bild .lp-icon-strich-negativ {
    stroke: var(--color-surface);
}

.lp-punkt-text {
    display: grid;
    gap: 0.15rem;
}

.lp-punkt-text strong {
    font-size: 0.98rem;
}

.lp-punkt-text > span {
    font-size: 0.86rem;
    line-height: 1.55;
    color: var(--color-text-muted);
}

/* ---------- Der dunkle Streifen am Fuss ----------
   Vier Werte und die eMind-Plakette. Feste Farben, nicht --color-primary: im
   Dunkelmodus ist die Markenfarbe ein heller Lavendelton, und weisse Schrift
   darauf waere unlesbar. */
.lp-streifen {
    background: linear-gradient(110deg, #1b2f7a 0%, #16256a 100%);
    color: #ffffff;
}

.lp-streifen-innen {
    max-width: 1180px;
    margin: 0 auto;
    padding: 1.5rem;
    display: grid;
    grid-template-columns: repeat(4, 1fr) auto;
    gap: 1.5rem;
    align-items: center;
}

.lp-streifen-wert {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    /* Trennlinien wie auf dem Blatt, aber nur ZWISCHEN den Werten. */
    border-left: 1px solid rgba(255, 255, 255, 0.18);
    padding-left: 1.2rem;
}

.lp-streifen-wert:first-child {
    border-left: 0;
    padding-left: 0;
}

.lp-streifen-wert .icon {
    flex: 0 0 auto;
    margin-top: 0.1rem;
    color: #ffffff;
    opacity: 0.85;
}

.lp-streifen-wert strong {
    display: block;
    font-size: 0.85rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* min-height auf DREI Zeilen (3 x 1.45em = 4.35em).
   ---------------------------------------------------------------------------
   Der Grund steht im Streifen selbst: "Effizienz" brauchte zwei Zeilen, die
   drei anderen drei — die Ueberschriften standen dadurch auf einer Linie, die
   Texte aber endeten auf zwei verschiedenen Hoehen, und zwischen den
   Trennlinien klaffte es. Den Text zu verlaengern reicht nicht: wie viele
   Zeilen es werden, haengt an der Sprache und an der Fensterbreite — im
   Englischen sind es vier mal zwei, im Franzoesischen 2/3/3/2.

   Die Mindesthoehe macht es unabhaengig davon: alle vier Bloecke sind gleich
   hoch, egal was darin steht. */
.lp-streifen-wert span {
    display: block;
    /* Zwei Zeilen als Untergrenze (2 x 1.45em). Die Texte selbst sind je
       Sprache auf gleiche Zeilenzahl gebracht — drei im Deutschen,
       Tuerkischen, Franzoesischen und Polnischen, zwei im Englischen und
       Niederlaendischen. Diese Untergrenze ist nur das Netz fuer
       Fensterbreiten, bei denen eine Zeile mehr umbricht. */
    min-height: 2.9em;
    font-size: 0.8rem;
    line-height: 1.45;
    color: #cdd8f7;
}

.lp-plakette {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    padding: 0.7rem 1.1rem;
    background: #ffffff;
    border-radius: var(--radius);
    text-decoration: none;
    color: #16256a;
    font-size: 0.82rem;
    font-weight: 600;
}

.lp-plakette img {
    display: block;
    width: auto;
    height: 1.6rem;
}

.lp-plakette span {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

/* Das grosse Zeichen: 4.5rem, flaechig, in Markenfarbe. `fill: currentColor`
   auf dem SVG, damit die Farbe an EINER Stelle steht. */
.lp-icon-gross {
    display: block;
    width: 4.5rem;
    height: 4.5rem;
    margin: 0 auto;
    color: var(--color-primary);
    fill: currentColor;
}

/* Ausgesparte Teile: Haekchen, Fenster, umgeknickte Ecke. Sie tragen die Farbe
   der FLAECHE, auf der das Zeichen sitzt — deshalb stimmt es im Dunkelmodus
   ohne zweite Regel. Wichtig: das Vorteilsband liegt auf --color-bg. */
.lp-icon-negativ {
    fill: var(--color-bg);
}

.lp-icon-strich-negativ {
    fill: none;
    stroke: var(--color-bg);
    stroke-width: 5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.lp-icon-strich {
    fill: none;
    stroke: currentColor;
    stroke-width: 5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* ACHT Modulkacheln, jede mit Bild, Namen und Beschreibungssatz.
   ---------------------------------------------------------------------------
   Vorher waren es sechs Zeilen mit Zeichen und Wort in einer Reihe. Deshalb
   stand hier eine kleinste Spalte von 150px. Jetzt traegt jede Kachel ein Bild
   (320x132, siehe partials/login-modul-bild.php) und drei Zeilen Text — unter
   260px wird das Bild zu klein, um noch etwas zu zeigen. Bei 1180px Spalte
   ergibt das vier Kacheln je Reihe, also zwei volle Reihen; darunter werden es
   zwei, auf dem Telefon eine. */
.lp-module {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
}

.lp-modul {
    display: flex;
    flex-direction: column;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    /* Das Bild sitzt auf der oberen Kante — ohne dies stehen seine Ecken ueber
       der Rundung der Kachel. */
    overflow: hidden;
    transition: transform var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

.lp-modul:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

/* `display: block` gegen die Luecke unter einem Inline-SVG (es sitzt sonst auf
   der Schriftlinie); `height: auto` mit `width: 100%`, damit das Bild sein
   Seitenverhaeltnis behaelt, egal wie breit die Spalte wird. */
.lp-modul-bild {
    display: block;
    width: 100%;
    height: auto;
    border-bottom: 1px solid var(--color-border);
}

.lp-modul-text {
    padding: 1rem 1.1rem 1.2rem;
}

.lp-modul-kopf {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    font-size: 1rem;
}

.lp-modul-kopf .icon {
    flex: 0 0 auto;
    color: var(--color-primary);
}

.lp-modul-text p {
    margin: 0.5rem 0 0;
    font-size: 0.86rem;
    line-height: 1.55;
    color: var(--color-text-muted);
}

/* ---------- "Warum Ventus WEB?" ----------
   Dunkle Tafel links, Funktionsliste rechts — wie auf dem Werbeblatt. Die
   Tafel ist schmaler als die Liste (5 zu 7), damit der Text nicht in langen
   Zeilen laeuft und die Liste ihre Haken untereinander behaelt. */
.lp-warum {
    display: grid;
    grid-template-columns: 5fr 7fr;
    gap: 2rem;
    align-items: start;
}

.lp-tafel {
    /* Feste Farben, nicht --color-primary: die Tafel soll in Hell UND Dunkel
       dunkelblau bleiben. Im Dunkelmodus ist --color-primary ein heller
       Lavendelton — als Flaeche hinter weisser Schrift waere sie unlesbar. */
    background: linear-gradient(160deg, #1b2f7a 0%, #16256a 100%);
    color: #f3f6ff;
    border-radius: var(--radius-lg);
    padding: 2rem;
}

.lp-tafel h2 {
    margin: 0 0 0.9rem;
    font-size: 1.3rem;
    color: #ffffff;
}

.lp-tafel p {
    margin: 0 0 1.6rem;
    font-size: 0.92rem;
    line-height: 1.65;
    /* Nicht reinweiss: ein Absatz in vollem Weiss auf Dunkelblau flimmert. */
    color: #d7e0fb;
}

.lp-knopf {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 1.3rem;
    background: #ffffff;
    color: #16256a;
    border-radius: var(--radius);
    font-weight: 600;
    font-size: 0.92rem;
    text-decoration: none;
    transition: transform var(--duration) var(--ease);
}

.lp-knopf:hover {
    transform: translateX(3px);
}

.lp-weiteres h2 {
    margin: 0 0 1.2rem;
    font-size: 1.3rem;
}

.lp-weiteres ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.85rem;
}

/* `flex-start` und nicht `center`: auf schmalen Fenstern brechen zwei der fuenf
   Zeilen um, und ein mittig gesetzter Haken stand dann zwischen den Zeilen
   statt vor der ersten. */
.lp-weiteres li {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    font-size: 0.95rem;
    line-height: 1.5;
}

.lp-weiteres .icon {
    flex: 0 0 auto;
    margin-top: 0.15rem;
    color: var(--color-primary);
}

/* ---------- Schlussstreifen ----------
   Der Fuss des Werbeblattes: dunkelblau, Papierflieger, zwei Zeilen. Er laeuft
   ueber die ganze Breite und ist bewusst das Letzte auf der Seite. */
.lp-schluss {
    background: linear-gradient(120deg, #1b2f7a 0%, #16256a 100%);
    color: #ffffff;
    padding: 2.5rem 1.5rem;
}

.lp-schluss-inhalt {
    max-width: 1180px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 1.5rem;
}

.lp-schluss-inhalt > div {
    display: grid;
    gap: 0.35rem;
}

.lp-schluss strong {
    font-size: 1.15rem;
}

.lp-schluss span {
    font-size: 0.92rem;
    color: #cdd8f7;
}

/* Der Papierflieger ist hier weiss, nicht in Markenfarbe: er liegt auf der
   dunklen Flaeche. */
.lp-schluss .lp-icon-gross {
    flex: 0 0 auto;
    width: 3.5rem;
    height: 3.5rem;
    margin: 0;
    color: #ffffff;
}

/* ---------- Schmale Fenster ----------
   Der Kopf wird einspaltig, und die ANMELDUNG kommt ZUERST: wer sich vom
   Telefon anmeldet, will sich anmelden. Die Aussage steht darunter, die
   Baender folgen — die Seite bleibt also vollstaendig, nur in anderer
   Reihenfolge. */
@media (max-width: 900px) {
    .lp-hero {
        flex-direction: column;
        gap: 2.5rem;
        padding: 2rem 1rem 2.5rem;
    }

    .lp-hero .auth-card {
        order: -1;
        width: 100%;
    }

    .lp-titel {
        font-size: clamp(1.7rem, 7vw, 2.2rem);
    }

    .lp-band {
        padding: 2.5rem 1rem;
    }

    .lp-band-ruhig {
        padding-left: 0;
        padding-right: 0;
    }

    .lp-band.lp-band-ruhig > * {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    /* ---------- Die Mitte auf schmalen Fenstern ----------
       Einspaltig: Text und Vorteile oben, Geraete darunter. Zweispaltig blieb
       fuer die Geraete so wenig Breite, dass das Gitter seine Spalten nicht
       mehr unterbringen konnte und die Seite nach rechts auslief. */
    .lp-blatt-innen {
        grid-template-columns: 1fr;
        gap: 2rem;
        padding: 2.25rem 1rem 2rem;
    }

    /* Notebook und Telefon UNTEREINANDER, und beide duerfen groesser sein: bei
       0.62vw waeren es hier 2.7px Schrift — Grau statt Buchstaben. */
    .lp-geraete {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.5em;
        font-size: clamp(6.5px, 2vw, 9px);
    }

    .nb {
        width: 100%;
    }

    /* Das Menue faellt weg. Es traegt neun Woerter, die auf einem Telefon ein
       Drittel der Breite fressen — und die Aussage des Bildschirms ist die
       Uebersicht, nicht die Navigation. In der echten Anwendung ist die
       Seitenleiste auf schmalen Fenstern ebenfalls eingeklappt. */
    .nb-menue {
        display: none;
    }

    .nb-schirm {
        grid-template-columns: 1fr;
        height: 32em;
    }

    /* Untereinander statt uebereinander: bei dieser Breite wuerde das Telefon
       das halbe Notebook verdecken. */
    .tf {
        position: static;
        width: 15.5em;
    }

    /* Der Streifen: zwei Werte je Reihe, die Plakette darunter ueber die ganze
       Breite. Die Trennlinie faellt bei jedem ersten Wert einer Reihe weg —
       eine Linie am Rand trennt nichts. */
    .lp-streifen-innen {
        grid-template-columns: 1fr 1fr;
        gap: 1.25rem;
        padding: 1.5rem 1rem;
    }

    .lp-streifen-wert:nth-child(odd) {
        border-left: 0;
        padding-left: 0;
    }

    .lp-plakette {
        grid-column: 1 / -1;
        justify-self: start;
        flex-direction: row;
        align-items: center;
        gap: 0.8rem;
    }

    /* Tafel und Liste untereinander: nebeneinander bliebe fuer beide zu wenig
       Breite, und der Absatz der Tafel liefe auf zwei Woerter je Zeile. */
    .lp-warum {
        grid-template-columns: 1fr;
        gap: 1.75rem;
    }

    .lp-schluss-inhalt {
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
    }
}

.auth-card {
    width: 100%;
    max-width: 500px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: 2rem;
}

.auth-card h1 {
    margin: 0 0 1.5rem;
    font-size: 1.25rem;
    text-align: center;
}

.auth-card form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.auth-card label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* Flaeche, Rahmen, Radius und Polster kommen aus dem gemeinsamen Block
   ("EIN AUSSEHEN FUER ALLE EINGABEFELDER"); hier steht nur, was diese Maske
   davon abweichend braucht. */
.auth-card input {
    font-size: 0.95rem;
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

.otp-inputs {
    display: flex;
    gap: 0.5rem;
    justify-content: center;
}

.otp-box {
    width: 2.6rem;
    height: 3rem;
    padding: 0 !important;
    text-align: center;
    font-size: 1.4rem !important;
    font-weight: 600;
}

.auth-card button {
    margin-top: 0.5rem;
    padding: 0.6rem;
    border: none;
    border-radius: var(--radius);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    font-size: 0.95rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.auth-card button:hover {
    background: var(--color-primary-hover);
}

.auth-card button:active {
    transform: scale(0.98);
}

/* Sprachwahl und Hell/Dunkel im Kartenfuss sind KEINE Anmeldeknoepfe.
   ---------------------------------------------------------------------------
   `.auth-card button` weiter oben faerbt JEDEN Knopf in der Karte in
   Markenfarbe. Fuer "Anmelden" ist das richtig, fuer diese zwei nicht: sie
   standen in derselben Farbe und fast derselben Groesse da wie die Handlung,
   um die es auf der Seite geht. Dieselbe Falle hat vorher schon der
   Passwort-Knopf gestellt (siehe .auth-card button.password-toggle).

   ZWEI Klassen im Waehler, damit die Regel sicher gewinnt: 0,2,1 gegen 0,1,1.
   Mit `.auth-werkzeuge button` allein waeren beide gleich stark und es haenge
   an der Reihenfolge in der Datei — das ist keine Grundlage. */
.auth-card .auth-werkzeuge button {
    margin-top: 0;
    padding: 0.32rem 0.5rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 0.85rem;
    font-weight: 400;
}

.auth-card .auth-werkzeuge button:hover {
    background: var(--color-bg);
    border-color: var(--color-primary);
    color: var(--color-text);
}

/* AUSGESCHALTET MUSS MAN SEHEN. Bei 0,75 war der Unterschied zu einem
   benutzbaren Knopf so klein, dass man ihn erst am ausbleibenden Klick bemerkte
   — der Flight-Importer nimmt 0,45, und das ist der Punkt, an dem ein Knopf
   erkennbar nicht dran ist. */
button:disabled {
    opacity: 0.45;
    cursor: default;
}

.spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-right: 0.5rem;
    vertical-align: -2px;
    /* Der Ring sitzt IM Primaerknopf und muss dieselbe Farbe tragen wie dessen
       Beschriftung — mit festem Weiss war er im Dunkelmodus auf hellem Blau
       kaum zu sehen. */
    border: 2px solid color-mix(in srgb, var(--auf-farbflaeche) 40%, transparent);
    border-top-color: var(--auf-farbflaeche);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

/* Variante für Buttons/Links ohne farbigen Hintergrund (z. B. .row-action) —
   nutzt die aktuelle Textfarbe statt fest Weiß. */
.spinner-current {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    opacity: 0.8;
    animation: spin 0.7s linear infinite;
}

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

.password-field {
    position: relative;
    display: flex;
}

.password-field input {
    flex: 1;
    padding-right: 2.4rem;
}

.auth-card button.password-toggle {
    position: absolute;
    right: 0.3rem;
    top: 50%;
    transform: translateY(-50%);
    margin-top: 0;
    padding: 0.3rem;
    background: none;
    border: none;
    color: var(--color-text-muted);
    cursor: pointer;
    display: flex;
    align-items: center;
}

.auth-card button.password-toggle:hover {
    opacity: 1;
    color: var(--color-text);
}

.password-toggle svg {
    width: 18px;
    height: 18px;
}

.auth-error {
    background: var(--color-danger-soft);
    color: var(--color-danger-text);
    padding: 0.6rem 0.75rem;
    border-radius: var(--radius);
    font-size: 0.85rem;
    margin: 0 0 1rem;
}

.auth-subtitle {
    margin: -1rem 0 1rem;
    font-size: 1rem;
    text-align: center;
    color: var(--color-text);
}

.auth-intro {
    margin: 0 0 1.25rem;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    text-align: center;
}

.auth-back {
    margin: 1rem 0 0;
    font-size: 0.85rem;
    text-align: center;
}

.debug-log {
    width: 100%;
    max-width: 500px;
    margin: 1rem auto 0;
    padding: 0.85rem 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-danger);
    border-radius: var(--radius);
    font-size: 0.78rem;
    color: var(--color-text);
}

.debug-log strong {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--color-danger-text);
}

.debug-log pre {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: var(--schrift-mono);
    max-height: 260px;
    overflow-y: auto;
}

/* ---------- Search form ---------- */

.search-form {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 0.6rem 0.85rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    /* 16 px und nicht die 20–24 px der uebrigen Karten: die Felder darin sind
       jetzt 44 px hoch, die Leiste damit schon 76 px. Mit 24 px waeren es 92 px
       Vorlauf, bevor die erste Datenzeile beginnt — in einer Arbeitsliste ist
       das der teuerste Platz der Seite. */
    padding: var(--space-4);
    margin-bottom: var(--space-3);
}

.search-form label {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    /* 13 px: 12 waren an der Grenze des Lesbaren, und die Beschriftung nennt
       das einzige, woran man ein leeres Feld erkennt. */
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}


/* Das erste Feld (Buchungsnummer / Suchbegriff) ist das elastische der Leiste:
   es nimmt freien Platz auf und gibt ihn als ERSTES wieder ab, damit die Leiste
   in einer Zeile bleibt. Datums- und Auswahlfelder behalten ihre Breite.

   `min-width: 0` ist dabei der eigentliche Kniff und nicht wegzulassen: ein
   Flex-Element schrumpft von sich aus nicht unter die Mindestbreite seines
   Inhalts, und ein `<input type="text">` bringt über sein size-Attribut rund
   180px mit. Ohne diese Zeile bleibt das Feld breit und die Leiste bricht um,
   obwohl flex-shrink es erlaubt — genau der Umbruch, der den Suchen-Knopf in
   die zweite Zeile geschoben hat.

   Die Basis ist bewusst klein (140px): sie gilt, wenn kein Platz zu verteilen
   ist. Bei breitem Fenster wächst das Feld über flex-grow ohnehin deutlich
   darüber hinaus. */
.search-form label:first-of-type {
    flex: 2 1 140px;
    min-width: 0;
}

.search-form label:first-of-type input {
    width: 100%;
    min-width: 0;
}

/* Datumsfelder bleiben in jeder Suchleiste schmal/fest (einheitlich über die
   ganze App) — Comboboxen mit .filter-flex wachsen stattdessen in den
   verbleibenden Platz (z. B. lange Firmennamen bei Agentur/Lieferant/Reiseart). */
/* +8 px gegen die frueheren 150: das Polster ist von 8,8 auf 12 px je Seite
   gewachsen. Ohne das stand "18.08.202" im Feld — der Fehler ist in diesem
   Projekt schon einmal passiert und faellt nur am Bild auf. */
.search-form input[type="date"] {
    width: 158px;
}

.search-form .filter-fixed {
    flex: 0 0 auto;
}

/* .search-form label:first-of-type/-input greifen auch, wenn ein .filter-fixed
   (z. B. "Datum von") zufällig das erste <label>-Kind seines eigenen
   Elternelements ist (z. B. weil eine Radiogruppen-<div> davorsteht) — ohne
   diese :first-of-type-Overrides würde es breiter als das benachbarte
   "Datum bis" werden. */
.search-form label.filter-fixed:first-of-type {
    flex: 0 0 auto;
}

.search-form label.filter-fixed:first-of-type input {
    width: 158px;
}

.search-form .filter-flex {
    flex: 1 1 220px;
}

/* FREITEXTFELDER GEBEN PLATZ AB.
   ─────────────────────────────────────────────────────────────────────────
   Ein Textfeld bringt ueber sein size-Attribut rund 176 px mit und behaelt sie
   auch dann, wenn die Leiste zu eng wird: geschrumpft wird in einem
   Flex-Umbruch NICHT — der Browser schiebt lieber das letzte Element in die
   naechste Zeile. Das letzte Element ist der Suchen-Knopf mit dem Filterzeichen
   daneben, und der stand in der Flugliste dadurch allein in einer dritten
   Reihe.

   Deshalb bekommen sie hier eine KLEINE Basis (140 px statt der 176 aus dem
   Inhalt) und duerfen wachsen: ist Platz da, fuellen sie die Leiste wie bisher;
   ist keiner da, ist die gedachte Breite klein genug, dass Felder und Knoepfe
   zusammen in eine Zeile passen.

   Auswahlfelder sind ausgenommen — deren Breite richtet sich nach der laengsten
   Option ("Alle Lieferanten"), abgeschnitten waeren sie unbrauchbar. Und das
   erste Feld der Leiste behaelt seine staerkere Dehnung (flex-grow 2, Regel
   weiter oben): es ist das Suchfeld, in dem der Text steht, den man liest. */
.search-form label:has(input[type="text"]):not(:first-of-type) {
    flex: 1 1 140px;
    min-width: 0;
}

.search-form label:has(input[type="text"]):not(:first-of-type) input {
    width: 100%;
    min-width: 0;
}

.search-form .filter-flex select {
    width: 100%;
}

/* EIN TEXTFELD MIT .filter-flex IST DAS HAUPTSUCHFELD DER LEISTE.
   ─────────────────────────────────────────────────────────────────────────
   Die Regel darueber gibt jedem Textfeld ausser dem ersten dieselbe
   Dehnung — bis zur Buchungsliste war das richtig, dort war das erste Feld
   (die Buchungsnummer) auch das, in dem man liest.

   Seit die Nummer fest ist wie ein Datumsfeld und der NAME daneben das
   elastische ist, braucht es einen Weg, das zu SAGEN: .filter-flex an einem
   Textfeld heisst "dieses hier nimmt den Platz". Ohne das teilte es sich den
   Rest gleichmaessig mit den Auswahlfeldern der Leiste, und der Name — das
   einzige Feld, dessen Inhalt lang werden kann — waere so breit wie "Alle". */
.search-form label.filter-flex:has(input[type="text"]) {
    flex: 2 1 180px;
    min-width: 0;
}

.search-form label.filter-flex:has(input[type="text"]) input {
    width: 100%;
    min-width: 0;
}
/* Suchleiste, die in EINER Zeile bleibt (Buchungsliste: neun Felder + Knopf).

   flex-wrap: wrap allein genügt dafür nicht — im Gegenteil. Reicht der Platz
   nicht, schiebt der Browser die letzten Elemente in die nächste Zeile, statt
   das elastische Feld zu verkleinern: geschrumpft wird nur innerhalb einer
   bereits umgebrochenen Zeile. Deshalb muss der Umbruch hier ausdrücklich weg,
   dann greift flex-shrink und das Nummernfeld gibt seinen Platz ab.

   ─────────────────────────────────────────────────────────────────────────
   WARUM DIE LEISTE JETZT UMBRICHT, statt seitlich zu rollen
   ─────────────────────────────────────────────────────────────────────────
   Hier stand `flex-wrap: nowrap` mit `overflow-x: auto`: alles in EINE Zeile,
   und wenn es nicht passt, rollt die Leiste seitlich. Das hat jahrelang
   funktioniert, weil die Breiten auf 1680 px in der breitesten Sprache
   ausgerechnet waren — auf den Pixel.

   Genau daran ist es zerbrochen, als das Design-System kam: Felder wurden
   44 px hoch mit mehr Innenabstand, die Beschriftungen 13 statt 12 px. Die
   Rechnung ging nicht mehr auf, und weil der Suchen-Knopf das LETZTE Element
   ist, war er der, der halb im Nichts stand — sichtbar abgeschnitten, obwohl
   die Leiste "nur" gerollt hat. Ein Knopf, den man erst durch Rollen findet,
   ist ein verlorener Knopf.

   Ein Umbruch ist die ehrlichere Antwort: passt alles, bleibt es EINE Zeile
   (nichts aendert sich auf breiten Schirmen). Passt es nicht, entsteht eine
   zweite Zeile — sichtbar, ohne Rollen, mit dem Knopf am Ende. Und es hoert auf,
   ein Rechenwerk zu sein, das bei jeder Schrift- oder Sprachaenderung neu
   nachgerechnet werden muss.
   ───────────────────────────────────────────────────────────────────────── */
.search-form-einzeilig {
    flex-wrap: wrap;
    /* Engerer Abstand als in den uebrigen Suchleisten: bei neun Feldern und dem
       Knopf sind es NEUN Zwischenraeume, jeder gesparte Pixel zaehlt also
       neunfach — es soll so lange wie moeglich eine Zeile bleiben. */
    gap: 0.5rem;
    padding: var(--space-4);
}

/* Der Suchen-Knopf steht IMMER am rechten Ende seiner Zeile — auch wenn die
   Leiste umgebrochen ist und die letzte Zeile nur halb voll ist. Sonst klebte er
   mitten in der Zeile an das letzte Auswahlfeld. */
.search-form-einzeilig > button[type="submit"] {
    margin-left: auto;
}

/* Stehen zwei Knoepfe in der Leiste, sind sie EIN Element (.filter-aktionen)
   und ruecken gemeinsam ans rechte Ende. Vorher trug der Suchen-Knopf das
   margin-left: auto allein — der freie Platz landete dann ZWISCHEN den beiden,
   Schalter links, Suchen rechts, die halbe Leiste dazwischen. */
.search-form-einzeilig > .filter-aktionen {
    margin-left: auto;
}

/* Untergrenzen gehören an das LABEL, nicht an das Feld darin: die Flex-Rechnung
   verteilt das Schrumpfen auf die Labels, ein min-width am Eingabefeld wird dabei
   überfahren. Ohne Untergrenze trug das Nummernfeld die ganze Differenz und
   schrumpfte auf 23px — eine Buchungsnummer war darin nicht mehr zu lesen.

   150 statt 100 px, und der Grund ist die BESCHRIFTUNG, nicht das Feld: sie ist
   EIN Wort und kann nicht umbrechen, lief also aus ihrem 100 px breiten Kasten
   heraus und in "Gebucht von" hinein. Nachgezaehlt in allen sechs Sprachen —
   "Numéro de réservation" (21 Zeichen) und "Rezervasyon Numarası" (20) sind die
   laengsten, rund 147 px bei 13 px Schrift. Mit dem Umbruch der Leiste kostet
   die groessere Untergrenze keine andere Spalte mehr etwas. */
.search-form-einzeilig label:first-of-type {
    min-width: 150px;
}

/* Letzte Sicherung fuer eine Beschriftung, die trotzdem laenger ist als ihr
   Kasten (eine kuenftige Sprache, ein laengerer Begriff): dann bricht sie
   innerhalb des Wortes um, statt in das Nachbarfeld zu laufen. Lieber ein
   getrenntes Wort als zwei Beschriftungen uebereinander. */
.search-form label {
    overflow-wrap: break-word;
}

/* Damit das Nummernfeld nicht allein aufkommen muss, geben die vier
   Datumsfelder ebenfalls etwas ab — bis 136px, darunter passt "18.08.2026"
   samt Kalendersymbol nicht mehr. 124px waren zwischenzeitlich gesetzt, um Platz
   zu schaffen: dort stand dann "18.08.202" im Feld. Die Ersparnis kam am Ende
   aus dem Abstand, dem Polster und den kuerzeren Filialbezeichnungen. Die Auswahlfelder schrumpfen von sich aus bis
   zur Breite ihres Inhalts. */
.search-form-einzeilig label:has(input[type="date"]) {
    flex: 0 1 158px;
    min-width: 144px;
}

.search-form-einzeilig input[type="date"] {
    width: 100%;
    min-width: 0;
}

/* Auch die Auswahlfelder geben Platz ab.
   
   Ihre Breite richtet sich sonst nach der LAENGSTEN Option, und die faellt je
   Sprache anders aus: "Nur stornierte" gegen "Annulées uniquement". Deutsch
   passte damit in 1680, Franzoesisch fehlten 34 und Niederlaendisch 12 Pixel.
   Neun Felder und ein Knopf gehen in dieser Breite nicht in jeder Sprache auf,
   also muss auch hier etwas nachgeben.
   
   Abgeschnitten wird dabei die Anzeige des GEWAEHLTEN Werts, und der ist im
   Regelfall "Alle" — kurz. Nur wenn eine lange Option gewaehlt ist, endet der
   Text sichtbar frueher; ausgewaehlt bleibt er trotzdem, und die aufgeklappte
   Liste zeigt ihn vollstaendig. 84px halten "Alle" samt Pfeil lesbar. */
.search-form-einzeilig label:has(select) {
    min-width: 84px;
}

.search-form-einzeilig select {
    width: 100%;
    min-width: 0;
}

/* Radiogruppe als EIN Flex-Item innerhalb einer .search-form-Zeile (z. B.
   Flugliste "Auswertung nach"/"Agentur/Kunde/Beide") — verhindert, dass jede
   Radio-Option zu einem eigenen, hochkant gestapelten Flex-Item wird. */
.filter-radio-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 1.1rem;
    flex-basis: 100%;
}

.filter-radio-group label,
.filter-radio-group label:first-of-type {
    display: flex;
    flex: 0 0 auto;
    flex-direction: row;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--color-text);
    cursor: pointer;
}

/* .search-form label:first-of-type { flex: 2 1 260px } und
   label:first-of-type input { width: 100% } greifen auch hier, weil sich
   :first-of-type auf JEDES Label bezieht, das als erstes Kind seines eigenen
   Elternelements steht (hier: erstes Label je Radiogruppe) — ohne die
   :first-of-type-Overrides oben/unten würde die erste Radio-/Checkbox-Option
   die ganze Zeile breitziehen. */
.filter-radio-group input[type="radio"],
.filter-radio-group input[type="checkbox"] {
    width: auto;
}

/* Generische eigene Suchzeile innerhalb einer .search-form (z. B. Passagierliste
   "Agentur"/"Lieferant" nebeneinander) — erzwingt per flex-basis:100% einen
   Zeilenumbruch, unabhängig davon, ob im Rest der Zeile noch Platz wäre. */
.filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
    flex-basis: 100%;
}

/* Gleiche :first-of-type-Falle wie bei .filter-radio-group: das erste Label
   in einer .filter-row ist "erstes Kind seines Elternelements" und bekommt
   sonst ungewollt flex:2 1 260px statt der eigenen .filter-flex-Größe. */
.filter-row label.filter-flex:first-of-type {
    flex: 1 1 220px;
}

.filter-row label.filter-fixed:first-of-type {
    flex: 0 0 auto;
}

.filter-row label.filter-fixed:first-of-type input {
    width: 150px;
}

/* ── Weitere Filter und aktive Filter ────────────────────────────────────────
   Zwei gemeinsame Muster fuer ALLE Suchleisten, gebaut von
   templates/partials/filter-leiste.php. Keine Regel je Maske: welche Felder in
   die zweite Reihe wandern, sagt das Merkmal data-filter-mehr in der Maske —
   das Aussehen steht hier einmal.

   Die Reihe selbst ist eine .filter-row (dieselbe Klasse, die schon die
   Passagierliste benutzt): flex-basis:100% erzwingt den Umbruch, und die
   :first-of-type-Ausnahmen darueber gelten damit auch hier. */
/**
 * DIE AKTIONSGRUPPE — [ Suchen ][ Weitere Filter ]
 *
 * Zusammen und in dieser Reihenfolge: die haeufigste Handlung zuerst, die
 * seltenere daneben. Die Reihenfolge steht im DOM (siehe
 * partials/filter-leiste.php) und nicht in einer CSS-order — sonst liefe die
 * Tabulatortaste anders als das Auge.
 *
 * align-items: end setzt sie auf dieselbe Grundlinie wie die Felder daneben,
 * auch wenn ueber den Feldern noch eine Beschriftung steht.
 */
.filter-aktionen {
    display: flex;
    align-items: end;
    gap: var(--space-2);
}

.filter-mehr-gruppe[hidden] {
    display: none;
}

/* Das erste Feld der zweiten Reihe ist nicht das Suchfeld der Leiste: ohne
   diese Zeile bekaeme es ueber .search-form label:first-of-type dessen
   Dehnung und Mindestbreite (siehe den Kommentar bei .filter-row). */
.filter-mehr-gruppe > label:first-of-type {
    flex: 0 1 auto;
    min-width: 0;
}

/* Aufgeklappt: kraeftigerer Rahmen und ein Hauch Fuellung — dasselbe Mittel,
   mit dem sich in dieser Anwendung ein aktiver Zustand zeigt.

   Grund UND Schrift stehen hier zusammen, obwohl die Schriftfarbe schon aus
   .export-button kaeme: getrennt hatten sie sich einmal auseinanderdividieren
   lassen (weisse Schrift aus einer allgemeineren Regel auf hellem Grund von
   hier). Wer den Grund aendert, sieht jetzt die Schrift daneben stehen. */
/* Die GEOMETRIE dieses Knopfes (Hoehe, Polster, Schriftgrad, Radius) steht
   nicht hier, sondern gemeinsam mit der des Suchen-Knopfes weiter unten:
   "GEMEINSAME GEOMETRIE DER LEISTENKNOEPFE". Hier steht nur, was ihn vom
   Suchen-Knopf UNTERSCHEIDET. */

.filter-mehr-knopf.is-open {
    border-color: var(--color-text-subtle);
    background: var(--color-hover);
    color: var(--color-text);
}

/* Zahl der aktiven Filter in der eingeklappten Reihe — dieselbe Rolle wie die
   Zahl am News-Knopf: ein Hinweis, dass dahinter etwas wartet. */
.filter-mehr-zahl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.15rem;
    height: 1.15rem;
    padding: 0 0.3rem;
    border-radius: var(--radius-pill);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    font-size: 0.7rem;
    font-weight: 600;
}

/* Zwei Ebenen: aussen die Plaettchen-GRUPPE und die Aktion daneben, innen die
   Plaettchen unter sich.

   Der Spaltenabstand aussen ist bewusst der grosse Wert der Skala: "Filter
   zuruecksetzen" ist keiner der Filter, sondern was man mit ihnen tut. Mit dem
   engen Abstand der Plaettchen daneben las es sich wie ein weiterer Filterwert
   — beide tragen einen Rahmen und stehen in derselben Zeile.

   Der ZEILENabstand ist der mittlere: bricht die Aktion auf eine eigene Zeile
   um, traegt er die Trennung weiter. Ein margin-left an der Aktion taete das
   nicht — es wuerde die umgebrochene Zeile nur einruecken. */
/* Stehen Plaettchen unter der Leiste, traegt DIESE den Abstand dazwischen —
   nicht der Aussenabstand des Formulars. Der ist maskenabhaengig (das
   Kontenblatt setzt ihn auf 0, weil sein Raster den Abstand macht), und die
   Plaettchen klebten dort an der Suchleiste. So ist die Luecke ueberall
   dieselbe. */
.search-form.filter-hat-chips {
    margin-bottom: 0;
}

.filter-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-6);
    margin-top: var(--space-3);
    margin-bottom: var(--space-3);
}

.filter-chips-liste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    padding: 0.2rem 0.25rem 0.2rem 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 0.8rem;
}

/* Ein Plaettchen ohne Kreuz (Pflichtfeld) braucht rechts dasselbe Polster wie
   links, sonst sieht es angeschnitten aus. */
.filter-chip:not(:has(.filter-chip-weg)) {
    padding-right: 0.65rem;
}

.filter-chip-weg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    padding: 0;
    border: 0;
    border-radius: var(--radius-pill);
    background: none;
    color: var(--color-text-muted);
    cursor: pointer;
}

.filter-chip-weg:hover {
    background: var(--color-hover);
    color: var(--color-text);
}

.filter-chip-weg .icon {
    width: 13px;
    height: 13px;
}

/* Der Zuruecksetzen-Knopf ist ein VERWEIS auf dieselbe Adresse ohne Filter —
   damit funktioniert er auch dort, wo ein Pflichtfeld das Absenden des
   Formulars verhindern wuerde. Er sieht aus wie die uebrigen Leistenknoepfe
   (.export-button) und steht am Ende der Plaettchen. */
/* Nur die Unterstreichung weg — Hoehe, Schrift und kompakte Ansicht kommen von
   .export-button, damit der Knopf denselben Regeln folgt wie jeder andere in
   einer Leiste. */
.filter-chips-weg {
    text-decoration: none;
}

/* Kompakte Ansicht: enger, aber der Unterschied zwischen dem Abstand INNERHALB
   der Gruppe und dem DANEBEN bleibt deutlich — er ist die Aussage, nicht seine
   Groesse. */
[data-dichte="kompakt"] .filter-chips {
    gap: var(--space-2) var(--space-4);
    margin-top: var(--space-2);
    margin-bottom: var(--space-2);
}

[data-dichte="kompakt"] .filter-chips-liste {
    gap: var(--space-1);
}

/* Zahlungen-Suchleiste: feste Grid-Spalten statt frei umbrechendem Flex, damit
   Buchungsnummer/Datum von/Datum bis/Text/Zahlart sauber untereinander stehen. */
.search-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

.search-form-grid label:nth-of-type(4) {
    grid-column: span 2;
}

/* ── Kontenblatt-Suchleiste ──────────────────────────────────────────────────
   EINE Zeile, wie in der Buchungsliste: das Formular traegt
   .search-form-einzeilig (nowrap, enge Abstaende, Mindestbreiten je Feldart,
   seitliches Rollen als letzte Sicherung).

   Vorher zwei nowrap-Flexzeilen, in denen NUR das Textfeld Platz abgab: es fiel
   auf 25px zusammen, nur noch die Beschriftung war zu sehen, und der Rest samt
   Suchen-Knopf rutschte aus dem Fenster (Knopf bei 1596px in einem 1280px
   breiten Fenster). Danach ein Raster — das brach zwar nicht mehr aus dem
   Fenster, brauchte aber zwei bis drei Zeilen.

   Das Polster ist knapper als in den uebrigen Leisten: die Leiste hat hier
   nicht die ganze Seitenbreite, links stehen die Konten. */
.kontenblatt-filter-form {
    padding: 0.85rem 1rem;
    gap: 0.5rem;
}

/* Die drei Textfelder (Vorgang, Z-Beleg, Text) teilen den freien Platz und geben
   ihn zuerst wieder ab. 90px halten eine Belegnummer lesbar, darunter waere das
   Feld nur noch Zierde. */
.kontenblatt-filter-form label:has(input[type="text"]) {
    flex: 1 1 100px;
    min-width: 90px;
}

.kontenblatt-filter-form label:has(input[type="text"]) input {
    width: 100%;
    min-width: 0;
}

/* Die Auswahlfelder (Gegenkonto, Mitarbeiter) geben ebenfalls ab — ihre Breite
   richtet sich sonst nach der laengsten Option ("Alle Gegenkonten"). */
.kontenblatt-filter-form label:has(select) {
    flex: 1 1 110px;
    min-width: 100px;
}

.kontenblatt-filter-form label:has(select) select {
    width: 100%;
    min-width: 0;
}

/* Der Suchknopf der Filterleiste schrumpft nicht mit und behaelt eine
   Mindestbreite. Hoehe und Aussehen kommen aus den Marken wie bei jedem Knopf.

   Hier stand einmal ZWEIMAL derselbe Knopf: dieser und der der Kontensuche
   links, die es nicht mehr gibt — das Filterfeld der Kontenliste kommt ohne
   Knopf aus. */
/* Wie oben nur der ABSENDEN-Knopf: seit der Schalter "Weitere Filter" dazukommt,
   steht in dieser Leiste mehr als einer, und die Mindestbreite ist fuer den
   Suchknopf gedacht. */
/* Felder der Suchleisten. Hoehe aus --hoehe-feld, damit sie mit dem
   Suchen-Knopf daneben auf einer Linie stehen.

   Der Schriftgrad bleibt bei 0.9rem (14,4 px) und wird NICHT auf 15 px
   angehoben: die Buchungssuche traegt neun Felder und den Knopf in EINER Zeile,
   und ihre Breiten sind auf 1680 px in der breitesten Sprache gerechnet
   (Franzoesisch). 14–16 px sind ohnehin der Rahmen des Design-Systems, und die
   0,6 px waeren dort neunmal bezahlt worden. */
.search-form input[type="text"],
.search-form input[type="date"],
.search-form select,
.totp-form input[type="text"] {
    height: var(--hoehe-feld);
    padding: 0 var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: 0.9rem;
    background: var(--color-bg);
    color: var(--color-text);
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

/* Der Browser zeichnet das Kalender-Icon in Chromium/Safari standardmäßig dunkel —
   im Dark Mode auf dunklem Eingabefeld-Hintergrund praktisch unsichtbar, daher invertiert. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) input[type="date"]::-webkit-calendar-picker-indicator {
        filter: invert(1);
    }
}

:root[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(1);
}

/* PRIMAERKNOPF: gefuelltes Blau, weisse Schrift, gleich hoch wie ein
   Eingabefeld, kein harter Schatten. Gewicht 600 — bei 500 wirkte er neben
   den Ueberschriften blass.

   ─────────────────────────────────────────────────────────────────────────
   NUR DER ABSENDEN-KNOPF, NICHT JEDER KNOPF IN EINER SUCHLEISTE
   ─────────────────────────────────────────────────────────────────────────
   Hier stand `.search-form button` — jeder Knopf in einer Suchleiste wurde
   damit zum blauen Primaerknopf. Solange darin nur der Suchen-Knopf stand, war
   das dasselbe. Mit dem Schalter "Weitere Filter" nicht mehr: er traegt
   `.export-button` (heller Grund, dunkle Schrift), aber `.search-form button`
   ist um eine Stelle spezifischer und hat `color: #fff` durchgesetzt. Im
   aufgeklappten Zustand setzte `.filter-mehr-knopf.is-open` den Grund
   seinerseits auf `--color-hover` — und dann stand WEISSE SCHRIFT AUF FAST
   WEISSEM GRUND. Im dunklen Modus fiel es nicht auf, dort ist `--color-hover`
   dunkel.

   Die Einschraenkung auf `[type="submit"]` sagt, was gemeint war: der eine
   Knopf, der die Suche abschickt. Alle Knoepfe, die in den Vorlagen in einer
   Suchleiste stehen, sind genau das (nachgezaehlt: 23 von 23) — die einzige
   Ausnahme ist der Schalter, der zur Laufzeit dazukommt, und der soll gerade
   NICHT wie die primaere Aktion aussehen. */
/* ═══════════════════════════════════════════════════════════════════════════
   DIE GEMEINSAME GRUNDLAGE ALLER KNOEPFE
   ═══════════════════════════════════════════════════════════════════════════
   Zwei Rollen, ein Bauplan:

     .button-primary   die Aktion, um die es auf der Maske geht (Suchen,
                       Speichern, Anlegen) — gefuellt, Feldhoehe.
     .export-button    alles Uebrige (Export, Spalten, Zurueck, Zeilenaktionen
                       mit Text) — umrandet, eine Stufe kleiner.

   Was BEIDE ausmacht — Ausrichtung, Abstand zwischen Zeichen und Text, Radius,
   Schriftfamilie, Zeiger — stand zweimal in der Datei. Es steht jetzt einmal
   hier; darunter steht nur noch, was die beiden Rollen unterscheidet.

   DIE HOEHEN SIND GLEICH, und das ist Absicht: jeder Knopf ist so hoch wie ein
   Eingabefeld (--hoehe-feld). Die sekundaeren waren einmal eine Stufe kleiner,
   damit Werkzeugleisten flacher bleiben — man sah davon aber nur, dass zwei
   Knoepfe nebeneinander verschieden hoch sind, und an jeder solchen Stelle
   stand am Ende eine Sonderregel, die sie wieder gleich machte.
   ═══════════════════════════════════════════════════════════════════════════ */
.search-form button[type="submit"],
.totp-form button,
.button-primary,
.export-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    border-radius: var(--radius);
    font-family: inherit;
    cursor: pointer;
}

/* Die primaere Rolle. Der Suchknopf und der Knopf der Zwei-Faktor-Maske sind
   dasselbe und stehen deshalb mit in der Auswahl — sie tragen die Klasse nicht,
   weil sie in ihren Masken die einzigen Knoepfe sind. */
.search-form button[type="submit"],
.totp-form button,
.button-primary {
    height: var(--hoehe-feld);
    padding: 0 var(--space-4);
    /* EIN RAHMEN IN DER EIGENEN FARBE statt `border: none`. Er ist nicht zu
       sehen, aber er zaehlt: ein Knopf ohne Rahmen neben einem mit Rahmen ist
       innen zwei Pixel groesser, und die Beschriftungen standen dadurch auf
       verschiedenen Grundlinien. So haben beide Rollen dieselbe Geometrie —
       nur andere Farben. */
    border: 1px solid var(--color-primary);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    /* GLEICHE SCHRIFT WIE DIE SEKUNDAEREN KNOEPFE — Groesse und Gewicht.
       Gewicht 600 stand hier, weil der Knopf neben Inter-Ueberschriften blass
       wirkte; mit IBM Plex ist das nicht mehr so, und 600 auf gefuelltem Blau
       las sich fett. Was die primaere Rolle traegt, ist die FLAECHE, nicht die
       Strichstaerke — genau so haelt es der Flight-Importer. */
    font-size: 0.85rem;
    font-weight: 500;
    /* Derselbe flache Schatten wie an Feldern und sekundaeren Knoepfen: er hebt
       das Bedienbare eine Spur von der Flaeche ab, auf der es liegt. */
    box-shadow: var(--shadow-sm);
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease),
        transform var(--duration) var(--ease);
}

.search-form button[type="submit"]:hover,
.totp-form button:hover,
.button-primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

.search-form button[type="submit"]:active,
.totp-form button:active,
.button-primary:active {
    transform: scale(0.98);
}

/* ═══════════════════════════════════════════════════════════════════════════
   GEMEINSAME GEOMETRIE DER LEISTENKNOEPFE
   ═══════════════════════════════════════════════════════════════════════════
   In einer Suchleiste stehen zwei Knoepfe nebeneinander: "Weitere Filter"
   (sekundaer) und "Suchen" (primaer). Sie kamen aus zwei verschiedenen
   Knopf-Familien und waren deshalb verschieden hoch. Die HOEHE ist inzwischen
   fuer alle Knoepfe dieselbe (siehe --hoehe-feld); was hier bleibt, ist der
   Rest ihrer Geometrie an einer Stelle und fuer beide zugleich: dasselbe
   Polster, derselbe Schriftgrad, derselbe Radius.
   Zwei Regeln mit zufaellig gleichen Werten waeren zwei Stellen, an denen man
   die eine aendert und die andere vergisst.

   Die Hoehe ist die FELDHOEHE und keine eigene Zahl: die Knoepfe stehen neben
   Eingabefeldern und sollen mit ihnen auf einer Linie liegen. Damit geht auch
   die kompakte Ansicht von selbst mit (dort setzt [data-dichte] die Marke auf
   34px) — ohne zweiten Satz Werte und ohne feste Pixelhoehe.

   box-sizing: border-box gilt global (siehe `*` ganz oben). Der Rahmen des
   sekundaeren Knopfes liegt deshalb INNERHALB der Hoehe; beide Knoepfe sind
   aussen exakt gleich hoch, obwohl nur einer einen Rahmen hat.

   Was NICHT hierher gehoert und verschieden bleibt: Farbe, Rahmen und
   Schriftgewicht. Das ist der Unterschied zwischen primaerer und sekundaerer
   Aktion, und er soll sichtbar sein.

   Zustaende aendern die Geometrie nicht: :hover und .is-open setzen nur Farben,
   der Fokusring liegt als outline ausserhalb des Kastens, und :active bewegt
   den Primaerknopf ueber transform — ohne seinen Platz zu aendern.
   ═══════════════════════════════════════════════════════════════════════════ */
.search-form button[type="submit"],
.search-form .filter-mehr-knopf {
    height: var(--hoehe-feld);
    padding: 0 var(--space-4);
    border-radius: var(--radius);
    font-size: 0.9rem;
    /* SCHRUMPFT NICHT. Das stand als Sonderregel am Kontenblatt ("min-width:
       92px"), gilt aber ueberall: ein Knopf, dessen Beschriftung umbricht oder
       der auf die Breite seines Wortes zusammenfaellt, ist in einer Leiste mit
       neun Feldern der erste, den man nicht mehr findet. */
    flex: 0 0 auto;
}

/* Der Filterschalter traegt nur den Trichter. Quadratisches Polster statt der
   Breite eines beschrifteten Knopfes — sonst staende das Zeichen in einem
   Kasten, der doppelt so breit ist wie hoch. Die HOEHE bleibt die des
   Suchen-Knopfes daneben (Regel darueber). */
.search-form .filter-mehr-knopf {
    padding: 0;
    width: var(--hoehe-feld);
}

/* Mit Zahl daneben braucht er wieder etwas Breite. */
.search-form .filter-mehr-knopf:has(.filter-mehr-zahl:not([hidden])) {
    width: auto;
    padding: 0 var(--space-3);
}

/* ---------- Authenticator-Setup: Bestätigungscode ---------- */

.totp-form {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
    margin-top: 1rem;
}

.totp-form label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.totp-form input[type="text"] {
    width: 9rem;
    font-size: 1.3rem;
    font-weight: 600;
    letter-spacing: 0.4em;
    text-align: center;
    font-family: var(--schrift-mono);
}

/* ---------- Data table ---------- */

.data-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-6);
}

/* EINE SPALTE NIMMT DEN REST DER BREITE.
   ---------------------------------------------------------------------------
   In einer Tabelle gibt es kein flex — der Weg dafuer ist `width: 100%` auf
   genau EINER Zelle: der Browser gibt ihr alles, was die uebrigen Spalten
   nicht fuer ihren Inhalt brauchen. Mehrere Zellen mit 100% teilen sich den
   Rest, deshalb immer nur eine je Tabelle.

   Gebraucht dort, wo eine Spalte langen Text traegt und alle anderen Nummern,
   Daten oder Betraege mit bekannter Laenge (Agentur in den Avisrechnungen). */
.data-table th.spalte-dehnt,
.data-table td.spalte-dehnt {
    width: 100%;
}

/* ZAHLEN IN DER FESTBREITENSCHRIFT.
   ---------------------------------------------------------------------------
   Rechtsbuendig heisst in dieser Anwendung: eine Zahl — Betrag, Anzahl,
   Prozentwert. Genau das ist die Spalte, die man ueberfliegt und vergleicht,
   und dafuer muessen die Stellen senkrecht untereinander stehen.

   Zwei Dinge zusammen: die Festbreitenschrift (IBM Plex Mono) gibt jeder Ziffer
   dieselbe Breite, tabular-nums haelt sie auch dort, wo doch einmal die normale
   Schrift greift. Der Flight-Importer macht dasselbe an seiner Zahlenspalte
   (td.num); hier braucht es keine eigene Klasse, weil die Ausrichtung die
   Bedeutung schon traegt.

   NUR die Zellen, nicht der Spaltenkopf: der traegt ein Wort und steht in der
   schmalen Fassung wie alle anderen Koepfe auch. */
.data-table td.text-right {
    font-family: var(--schrift-mono);
    font-variant-numeric: tabular-nums;
    /* Die Mono laeuft breiter als die Sans — eine Spur kleiner, damit die
       Betragsspalte nicht waechst. */
    font-size: 0.82rem;
}

.data-table th.text-right {
    font-variant-numeric: tabular-nums;
}

/* Die SUMMENZEILE traegt Betraege und keine Ueberschriften — sie steht in
   derselben Schrift wie die Spalte darueber, sonst stehen die Kommas der Summe
   nicht unter denen der Werte. */
.data-table tfoot.seiten-summe th.text-right {
    font-family: var(--schrift-mono);
    font-size: 0.82rem;
}

.data-table th,
.data-table td {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    /* NUR waagerechte Trennlinien. Senkrechte hat diese Tabelle nie gehabt und
       soll sie nicht bekommen: sie zerlegen eine Liste in Kaestchen und lassen
       sie nach Tabellenkalkulation aussehen. */
    border-bottom: 1px solid var(--color-border);
    font-size: 0.88rem;
}

/* ZEILENHOEHE als height am <tr> und nicht als Polster in der Zelle.

   Bei einer Tabellenzeile wirkt height wie eine Mindesthoehe: die Zeile ist so
   hoch, WENN der Inhalt nicht mehr braucht, und waechst sonst mit. Ueber das
   Polster geloest waere sie starr — eine Zeile mit einem 36 px hohen
   Symbolknopf haette dann 36 + zweimal Polster getragen und deutlich mehr
   Hoehe gehabt als eine Zeile mit reinem Text daneben.

   Die kompakte Ansicht setzt den Wert herunter, siehe [data-dichte]. */
.data-table tbody tr {
    height: var(--hoehe-tabellenzeile);
}

/* SPALTENKOEPFE DUERFEN AN EINEM ZEILENUMBRUCHZEICHEN BRECHEN.
   ---------------------------------------------------------------------------
   Format::mitWaehrungSpalte() setzt das Waehrungszeichen mit einem echten "\n"
   in eine zweite Zeile — kein <br>, weil die Templates Kopfzeilen durch
   htmlspecialchars() geben und ein Tag dort sichtbarer Text waere.

   `pre-line` ist die einzige der drei Varianten, die passt: es ehrt den
   Umbruch, laesst aber alle uebrigen Leerzeichen zusammenfallen. `pre` wuerde
   auch die Einrueckung aus dem Template uebernehmen, `normal` den Umbruch
   verschlucken. */
/* TABELLENKOPF — kleine gesperrte Grossbuchstaben in der schmalen Fassung, auf
   einem hellen BAND.

   Das Band war einmal weg, weil die Rasterzeilen der Leistungsbloecke
   (.row-grid-head) keines haben und beide Bauformen gleich aussehen sollten.
   Was die beiden zusammenhaelt, ist jetzt die SCHRIFT — dieselbe schmale
   Fassung, dieselbe Groesse, dieselbe Sperrung. Das Band bleibt dort weg, wo
   der Kopf in einem FORMULAR steht (Leistungsblock, Preiszeile), und steht
   dort, wo er eine Liste anfuehrt: eine Tabelle mit fuenfzig Zeilen braucht
   eine Kante nach oben, ein Formularraster mit drei nicht.

   DIE FARBE IST NICHT "transparent": der Kopf ist geheftet (position: sticky,
   siehe unten) und muss beim Blaettern die Zeilen verdecken, die unter ihm
   durchlaufen. Mit transparent schoeben sie sich sichtbar hindurch — und aus
   demselben Grund ist der Zeilen-Hover eine Stufe DUNKLER als das Band und
   nicht heller (siehe --color-hover).

   Die SUMMENZEILE behaelt ihr eigenes Band (.data-table tfoot.seiten-summe th):
   sie gehoert nicht zu den Daten, sondern schliesst sie ab. */
.data-table th {
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    /* Schmale Fassung: der Kopf steht in Grossbuchstaben, und dort spart sie
       Breite, ohne enger zu wirken — eine Liste mit zwoelf Spalten gewinnt
       damit eine ganze Spalte. Dieselbe Schrift traegt .row-grid-head, die
       Kopfzeile der Leistungsbloecke: die beiden sollen gleich aussehen. */
    font-family: var(--schrift-cond);
    font-weight: 600;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: pre-line;
    /* Der Kopf bleibt FLACHER als eine Datenzeile: er traegt nur Text, und
       Hoehe an dieser Stelle ist Hoehe, die den Zeilen fehlt. */
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.data-table tbody tr:last-child td {
    border-bottom: none;
}

.data-table tbody tr {
    transition: background-color var(--duration) var(--ease);
}

/* ---------------------------------------------------------------------------
   MIT DEN PFEILTASTEN GEWAEHLTE ZEILE (siehe partials/grid-tastatur.php).

   Der FOKUS ist die Auswahl — deshalb wird er hier sichtbar gemacht und nicht
   eine zweite "ausgewaehlt"-Klasse gepflegt.

   KEIN RAHMEN um die Zeile: ein umlaufender Rahmen war in einer Liste, durch
   die man mit der Pfeiltaste laeuft, zu viel Bild — bei jedem Tastendruck
   zeichnete sich ein Kasten neu. Stattdessen der weiche Grund (wie beim
   Zeigen) und ein schmaler Streifen am linken Rand, der die gewaehlte Zeile
   von der ueberfahrenen unterscheidet. Als `inset`-Schatten und nicht als
   border, damit die Zeilenhoehe gleich bleibt und die Liste beim Durchlaufen
   nicht zuckt.

   :focus-visible waere hier falsch: die Zeile bekommt den Fokus auch nach einem
   Klick zugewiesen (damit die Pfeile dort weitermachen), und dann soll man
   sehen, wo man steht. */
.data-table tbody tr:focus {
    outline: none;
    background: var(--color-primary-soft);
    box-shadow: inset 3px 0 0 var(--color-primary);
}

/* Beim Mitrollen etwas LUFT lassen (grid-tastatur.php rollt mit
   scrollIntoView 'nearest'): ohne das klebt die gewaehlte Zeile am unteren
   Fensterrand, und man sieht nicht, was als naechstes kommt. */
.data-table tbody tr {
    scroll-margin-block: 1.5rem;
}

/* Hover DEZENT. Vorher lag hier --color-primary-soft, ein blauer Schleier: in
   einer Liste, durch die man mit der Maus faehrt, war das zu viel Farbe, und es
   sah aus wie die Auswahl. Die Auswahl (Fokus, siehe oben) bleibt blau — und
   ist damit vom Ueberfahren unterscheidbar. */
.data-table tbody tr:hover {
    background: var(--color-hover);
}

.data-table tr.totals-row td {
    font-weight: 600;
    background: var(--color-surface-alt);
    border-top: 2px solid var(--color-border);
}

/* ---------- Status badge ---------- */

/* GEOMETRIE ALLER ABZEICHEN an einer Stelle — Statusabzeichen und Zahlabzeichen
   trugen dieselben sechs Zeilen doppelt. Was sie unterscheidet, steht darunter:
   die FARBE je Bedeutung, und die SCHRIFT je Art des Inhalts. */
.status-badge,
.number-badge {
    display: inline-block;
    padding: 0.2rem 0.65rem;
    border-radius: var(--radius-pill);
    /* DER RAHMEN GEHOERT ZUR GEOMETRIE, nicht zur Bedeutung: er steht hier
       durchsichtig und bekommt seine Farbe unten je Bedeutung. Sonst waeren
       Plaettchen mit und ohne Rahmen zwei Pixel verschieden gross, und in einer
       Spalte untereinander sieht man das. */
    border: 1px solid transparent;
    font-weight: 600;
    /* vertical-align: sonst zaehlt der Platz fuer Unterlaengen unter der
       Grundlinie zur Zeilenhoehe der Tabelle. */
    vertical-align: middle;
}

/* DAS STATUSPLAETTCHEN TRAEGT EIN WORT: klein, gesperrt, in Grossbuchstaben und
   in der schmalen Fassung — wie die Spaltenkoepfe darueber und wie .pill im
   Flight-Importer. Es ist ein Etikett und kein Satz; in Grossbuchstaben liest
   man es als Zustand und nicht als Text der Zeile.

   Die Sperrung ist der Grund, warum es trotz kleinerer Schrift nicht enger
   wird: Grossbuchstaben ohne Sperrung kleben aneinander. */
.status-badge {
    font-family: var(--schrift-cond);
    font-size: 0.72rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* DAS ZAHLABZEICHEN TRAEGT EINE NUMMER: Festbreitenschrift, damit zwei
   Buchungsnummern untereinander gleich breit sind und die Stellen senkrecht
   stehen. Nicht in Grossbuchstaben — an einer Ziffer gaebe es nichts zu
   wandeln, und die Sperrung machte sie nur breit. */
.number-badge {
    font-family: var(--schrift-mono);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Auswahldialog fuer Stammdaten (bookings/_auswahl-dialog.php)
   --------------------------------------------------------------------------- */
.auswahl-dialog-box {
    width: min(1000px, 100%);
}

.auswahl-suche {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.75rem;
    color: var(--color-text-muted);
    margin-bottom: 0.75rem;
}

.auswahl-suche input {
    font-size: 0.9rem;
    font-family: inherit;
}

/* Hoehe begrenzt: die Trefferliste holt bis zu 200 Zeilen, und der Dialog soll
   nicht ueber den Bildschirm hinauswachsen. */
.auswahl-liste {
    max-height: 24rem;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.auswahl-zeile {
    cursor: pointer;
}

.auswahl-zeile:hover,
.auswahl-zeile:focus-visible {
    background: var(--color-surface-alt);
    outline: none;
}

/* Der Knopf im Kopf einer Leistungszeile: schmaler als ein normaler Knopf, er
   steht neben Titel und Loeschen. */
.auswahl-knopf {
    padding: 0.25rem 0.6rem;
    font-size: 0.78rem;
}

/* ---------------------------------------------------------------------------
   Rueckmeldungen (partials/meldungen.php)
   Oben rechts eingeblendet, statt in jeder Maske eine eigene Zeile ueber dem
   Inhalt — die schob die Liste nach unten und sah in jeder Maske anders aus.
   --------------------------------------------------------------------------- */
.meldungen {
    position: fixed;
    top: 4.75rem;
    right: 1.25rem;
    z-index: 200;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    /* Nicht breiter als noetig, aber lesbar: eine Fehlermeldung aus der
       Buchhaltung ist gern zwei Zeilen lang. */
    max-width: min(30rem, calc(100vw - 2.5rem));
    pointer-events: none;
}

.meldung {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    padding: 0.7rem 0.9rem;
    border-radius: var(--radius);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    box-shadow: var(--shadow-md);
    font-size: 0.88rem;
    line-height: 1.35;
    pointer-events: auto;
    animation: meldung-auf 0.25s var(--ease);
}

.meldung .icon {
    flex-shrink: 0;
    margin-top: 0.1rem;
}

.meldung-erfolg {
    border-left: 3px solid var(--color-success);
}

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

.meldung-fehler {
    border-left: 3px solid var(--color-danger);
}

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

.meldung-zu {
    margin-left: auto;
    border: 0;
    background: none;
    color: var(--color-text-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
}

.meldung-weg {
    opacity: 0;
    transform: translateX(0.75rem);
    transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}

@keyframes meldung-auf {
    from { opacity: 0; transform: translateY(-0.4rem); }
    to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------------
   Betragsfelder in den Sammelzahlungs-Dialogen
   Die Zeilen entstehen im Browser, ihre Felder standen deshalb ausserhalb der
   Regeln fuer .form-grid und .inline-edit-form — sie hatten den nackten
   Browser-Rahmen, waehrend die Felder direkt darueber im selben Dialog
   gerahmt und gepolstert sind. Hier dieselbe Gestalt, nur schmaler: in der
   Spalte steht ein Betrag, keine Zeile Text.
   --------------------------------------------------------------------------- */
.sammel-liste input[type="text"] {
    width: 7.5rem;
    max-width: 100%;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: 0.88rem;
    font-family: inherit;
    background: var(--color-surface);
    color: var(--color-text);
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

/* Die Betragsspalte selbst: fest, damit die Felder untereinander stehen und
   nicht mit der Textlaenge der Zeile wandern. */
.sammel-liste td:last-child,
.sammel-liste th:last-child {
    width: 9rem;
}

/* ---------------------------------------------------------------------------
   FUENF ZEILEN SICHTBAR, der Rest per Bildlauf.

   Ohne Begrenzung wuchs der Dialog mit der Zahl der angehakten Buchungen: bei
   zwanzig Zeilen standen Hinweis und die Knoepfe "Abbrechen"/"Speichern" unter
   dem Fensterrand, und man musste die ganze SEITE scrollen, um zu speichern.

   Die Hoehe ist gerechnet, nicht geraten — Kopfzeile + fuenf Datenzeilen +
   Summenzeile. Eine Datenzeile ist hoeher als eine Kopfzeile, weil in ihr das
   Eingabefeld fuer den Betrag steht (0.8rem Innenabstand der Zelle + rund
   2.1rem Feldhoehe).

   Kopf- UND Summenzeile bleiben stehen (position: sticky): die Summe ist der
   Wert, auf den man beim Aendern der Einzelbetraege schaut — sie darf nicht
   nach unten aus dem Bild laufen. Den Kopf heftet schon `.data-table thead th`.
   --------------------------------------------------------------------------- */
.sammel-liste {
    /* Kopf- und Summenzeile: Polster (zweimal --space-3) plus die Zeilenhoehe
       ihrer 0.78rem-Schrift. Die Datenzeilen bringen ihre Hoehe selbst mit
       (--hoehe-tabellenzeile am <tr>), also wird HIER damit gerechnet und
       nicht mit einem eigenen Wert.

       Vorher standen an dieser Stelle zwei feste Werte (2.1rem / 2.95rem). Sie
       waren gegen ein 35 px hohes Eingabefeld gerechnet und stimmten nicht mehr,
       sobald die Feldhoehe des Design-Systems kam — der Kasten haette dann vier
       Zeilen gezeigt und die fuenfte halb. Ueber die Marken gerechnet passt es
       auch in der kompakten Ansicht, ohne zweiten Satz Werte. */
    --sammel-kopfzeile: calc(2 * var(--space-3) + 1.1rem);
    max-height: calc(2 * var(--sammel-kopfzeile) + 5 * var(--hoehe-tabellenzeile));
    overflow-y: auto;
}

.sammel-liste tfoot th {
    position: sticky;
    bottom: 0;
    z-index: 2;
    /* .data-table th traegt diese Farbe schon; hier noch einmal, weil eine
       geheftete Zelle sonst die durchlaufenden Zeilen durchscheinen liesse,
       falls die Regel spaeter einmal anders greift. */
    background: var(--color-surface-alt);
    box-shadow: inset 0 1px 0 var(--color-border);
}

@media print {
    .sammel-liste {
        max-height: none;
    }

    .sammel-liste tfoot th {
        position: static;
    }
}

/* ---------------------------------------------------------------------------
   Spaltenwahl und Seitensumme (partials/tabellen-werkzeuge.php)
   --------------------------------------------------------------------------- */

.spalten-popup {
    max-height: 22rem;
    overflow-y: auto;
}

.spalten-eintrag {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.85rem;
    cursor: pointer;
    white-space: nowrap;
}

.spalten-eintrag:hover {
    background: var(--color-surface-alt);
    border-radius: var(--radius);
}

.spalten-alle {
    width: 100%;
    text-align: left;
    border: 0;
    border-top: 1px solid var(--color-border);
    background: none;
    margin-top: 0.3rem;
    cursor: pointer;
}

/* Summe der angezeigten Seite. Kein Zebrastreifen, dafuer eine deutliche
   Oberkante: sie gehoert nicht zu den Daten, sondern schliesst sie ab. */
.data-table tfoot.seiten-summe th {
    background: var(--color-surface-alt);
    border-top: 2px solid var(--color-border);
    border-bottom: 0;
    font-weight: 600;
    color: var(--color-text);
    /* pre-line statt nowrap: das Kontenblatt stellt Einnahme und Ausgabe in EINER
       Spalte untereinander, und die Summenzeile tut es ihm mit einem
       Zeilenumbruch im Wert nach. Umbrechen von selbst tut hier nichts, die
       Betraege enthalten keine Leerzeichen. */
    white-space: pre-line;
}

/* ---------------------------------------------------------------------------
   Sortierbare Spaltenkoepfe (Support\Sortierung)
   Der Kopf ist ein Verweis, sieht aber wie der Kopf aus: dieselbe Farbe,
   dieselbe Groesse. Nur der Zeiger und der Pfeil sagen, dass hier etwas
   passiert — ein blau unterstrichener Spaltenkopf saehe wie ein Fehler aus.
   --------------------------------------------------------------------------- */
/* SORTIERKOPF: bricht am Zeilenumbruchzeichen, sonst nicht.
   ---------------------------------------------------------------------------
   Hier stand `nowrap`, damit der Sortierpfeil nicht allein in die naechste
   Zeile faellt. Das ueberstimmte aber das `pre-line` des Spaltenkopfes: eine
   Beschriftung wie "Gesamtpreis\n(EUR)" blieb einzeilig, und der Umbruch war
   in jeder sortierbaren Spalte wirkungslos — also in fast allen.

   `pre-line` ehrt den Umbruch. Dass der Pfeil trotzdem bei seinem Wort bleibt,
   loest jetzt ein geschuetztes Leerzeichen vor ihm (siehe Sortierung::kopf) —
   die Aufgabe des nowrap, aber nur fuer die Stelle, die sie braucht. */
.sort-kopf {
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    white-space: pre-line;
}

.sort-kopf:hover {
    color: var(--color-primary);
}

.sort-kopf.aktiv {
    color: var(--color-primary);
}

.sort-pfeil {
    font-size: 0.7em;
    /* Der Pfeil darf die Zeilenhoehe des Kopfes nicht vergroessern. */
    line-height: 1;
    vertical-align: middle;
}

/* Jeder Status bekommt eine Form. Bisher trugen nur BUCHUNG und STORNO eine
   Farbe; jeder andere Wert (OPTION, ANFRAGE, WARTELISTE — je Kunde verschieden)
   stand als nackter Text mitten in der Zeile, ohne Abzeichen. Die Grundregel
   faengt das ab, die bekannten Faelle bleiben, wie sie waren. */
/* ═══════════════════════════════════════════════════════════════════════════
   SEMANTIK DER FLAECHEN — vier Bedeutungen, eine Quelle
   ═══════════════════════════════════════════════════════════════════════════
   Die Farbenpaare (heller Grund + kraeftige Schrift derselben Familie) standen
   ueber die Datei verteilt: einmal am Statusabzeichen, einmal an der Marke im
   Handlungsbedarf des Dashboards, einmal am Fehlerkasten. Jedes Mal neu
   hingeschrieben, jedes Mal dieselben zwei Marken.

   Jetzt stehen sie hier, und die fachlichen Klassen haengen sich an die
   BEDEUTUNG, die sie haben. Wer eine fuenfte Statusart bekommt, waehlt eine
   Bedeutung, statt zwei Farben zu suchen.

   Die Zuordnung bleibt fachlich: WELCHER Buchungsstatus "erfolgreich" ist,
   entscheidet die Fachlichkeit — hier steht nur, wie "erfolgreich" aussieht.
   An den Werten aendert sich nichts, es sind dieselben Marken.

   FARBE IST NIE DAS EINZIGE MERKMAL: in jedem dieser Faelle steht der Text
   daneben oder darin (Statusname, Meldung, Zahl).
   ═══════════════════════════════════════════════════════════════════════════ */

/* JEDE BEDEUTUNG TRAEGT AUCH EINEN RAHMEN, nicht nur eine Flaeche.

   Die weichen Flaechen sind mit Absicht blass (eine Liste mit zwanzig
   Statuspillen waere sonst ein Farbkasten) — genau deshalb verschwanden sie
   dort, wo die Zeile selbst eingefaerbt ist: auf der ueberfahrenen Zeile, in
   der markierten Zeile, im Tabellenkopf. Uebrig blieb farbige Schrift ohne
   erkennbaren Rand, und aus dem Plaettchen wurde ein Wort.

   Die Linie ist dieselbe Farbe mit 30 Prozent Deckung (color-mix). Sie haelt
   auf jedem Untergrund, weil sie nicht vom Grund abhaengt, sondern von der
   Statusfarbe — so macht es der Flight-Importer bei seinen Pillen auch. */

/* NEUTRAL — kein Zustand, nur eine Angabe. Steht zuerst, damit die fachlichen
   Klassen darunter sie ueberschreiben. */
.ist-neutral,
.status-badge,
.db-prio-hinweis .db-marke {
    background: var(--color-surface-alt);
    border-color: var(--color-border);
    color: var(--color-text-muted);
}

/* ERFOLG — abgeschlossen, bestaetigt, bezahlt. */
.ist-erfolg,
.status-buchung {
    background: var(--color-success-soft);
    border-color: color-mix(in srgb, var(--color-success) 30%, transparent);
    color: var(--color-success-text);
}

/* GEFAHR — storniert, fehlgeschlagen, ueberfaellig. */
.ist-gefahr,
.status-storno,
.db-prio-kritisch .db-marke {
    background: var(--color-danger-soft);
    border-color: color-mix(in srgb, var(--color-danger) 34%, transparent);
    color: var(--color-danger-text);
}

/* GEMAHNT steht neben dem Status, nicht statt ihm: eine gemahnte Buchung ist
   weiter eine Buchung. Gelb wie die noch nicht verbindlichen Status — es ist
   eine Warnung, kein Endzustand. Das Symbol darf nicht mitwachsen. */
.status-gemahnt {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: var(--color-warning-soft);
    border-color: color-mix(in srgb, var(--color-warning) 32%, transparent);
    color: var(--color-warning-text);
}

.status-gemahnt .icon {
    width: 14px;
    height: 14px;
}

/* WARNUNG — noch nicht verbindlich, laeuft ab, muss angefasst werden. */
.ist-warnung,
.status-option,
.status-anfrage,
.status-warteliste,
.status-vorgang,
.db-prio-warnung .db-marke {
    background: var(--color-warning-soft);
    border-color: color-mix(in srgb, var(--color-warning) 32%, transparent);
    color: var(--color-warning-text);
}

/* Ein Formular, das in einer Zeile neben anderen steht — die Loeschknoepfe in
   Buchungsdetail und Blockeditor sind je ein eigenes <form>, sollen aber neben
   dem Bearbeiten-Knopf stehen und nicht darunter. Stand fuenfmal als
   style="display:inline" in den Vorlagen. */
.form-inline {
    display: inline;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIE LEERE LISTE
   ═══════════════════════════════════════════════════════════════════════════
   "Keine Buchungen gefunden" stand als nackter Text in der ersten Spalte, links
   an der Kante, in Zeilenhoehe — es sah aus wie ein Datensatz, der etwas
   Merkwuerdiges enthaelt, und nicht wie eine Antwort auf die Suche.

   Eine leere Liste ist ein ERGEBNIS und soll auch so aussehen: mittig, mit
   Luft, gedaempft. Die Luft ist der eigentliche Punkt — sie sagt "hier ist
   nichts", bevor man den Satz gelesen hat.

   Die Klasse steht an der ZELLE und nicht an der Zeile: die Zeile traegt in
   dieser Anwendung die Hoehe (--hoehe-tabellenzeile), und die soll die leere
   Liste gerade nicht haben.

   Kein Trennstrich darunter und keine Faerbung beim Ueberfahren: beides sagt
   "hier steht eine Zeile, die man anfassen kann". */
.data-table td.tabelle-leer {
    padding: 3rem 1rem;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.9rem;
    border-bottom: 0;
}

.data-table tbody tr:hover td.tabelle-leer {
    background: transparent;
}

/* Dieselbe Antwort ausserhalb einer Tabelle — die Vorgangskarte der
   CRS-Uebernahme, solange links nichts gewaehlt ist. */
.crs-detail-empty {
    padding: 3rem 1rem;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

/* Feste Breite für Aktionsspalten (Bearbeiten/Löschen) — verhindert, dass die
   Spalte je nach Zeileninhalt der Nachbarspalten in der Breite springt. */
.col-actions {
    width: 48px;
    white-space: nowrap;
}

.number-badge {
    /* Die Farbe kommt aus der Marke und steht nicht mehr als rgba() hier: sie
       war eine Kopie des alten Blaus und waere beim Wechsel der Markenfarbe
       stehen geblieben. */
    background: var(--color-primary-soft);
    border-color: color-mix(in srgb, var(--color-primary) 28%, transparent);
    color: var(--color-primary);
}

/* ---------- Definition list (booking detail) ---------- */

dl {
    margin: 0;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.5rem 1rem;
}

dt {
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

dd {
    margin: 0;
    font-size: 0.9rem;
}

/* Anklickbarer Wert in einer Beschreibungsliste — Telefonnummer (tel:) und
   E-Mail (mailto:) im Kontaktdaten-Block.

   Global gilt `a { color: inherit; text-decoration: none }`, weil in dieser
   Anwendung ganze Zeilen anklickbar sind und blaue Wortlinks das Raster
   zerschneiden wuerden. Hier braucht es aber einen Hinweis, dass ein Klick
   etwas tut: eine gepunktete Unterlinie, die beim Zeigen zur Volllinie in der
   Akzentfarbe wird. Zurueckhaltend im Ruhezustand, eindeutig unter dem Zeiger. */
dd a.kontakt-link {
    text-decoration: underline dotted;
    text-underline-offset: 0.2em;
    text-decoration-color: var(--color-border);
}

dd a.kontakt-link:hover,
dd a.kontakt-link:focus-visible {
    color: var(--color-primary);
    text-decoration: underline solid;
    text-decoration-color: currentColor;
}

/* ---------- Brand / logo ---------- */

.brand {
    display: inline-flex;
    align-items: center;
}

.brand-logo {
    flex-direction: column;
    gap: 0.25rem;
}

.brand-logo img {
    display: block;
    height: auto;
    width: auto;
    max-height: 128px;
    max-width: 100%;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DAS LOGO FOLGT DER ANSICHT
   ═══════════════════════════════════════════════════════════════════════════
   Zwei Bilder liegen im HTML (partials/brand.php, dort steht warum), hier
   entscheidet sich, welches man sieht: blau auf hell, weiss auf dunkel.

   ALLE DREI STAENDE des Umschalters sind abgedeckt, und das ist der Grund fuer
   die drei Regelpaare: eine ausdrueckliche Wahl setzt `data-theme`, die Vorgabe
   "System" setzt nichts und laesst nur `prefers-color-scheme` entscheiden. Ein
   `<picture>`-Element kennt nur den letzten Fall.

   Reihenfolge: hell ist die Grundstellung, dunkel ueberschreibt sie. Damit ist
   die Grundstellung nie an eine Medienabfrage gebunden — sonst zeigte ein
   Browser ohne Farbschema-Unterstuetzung gar kein Logo.
   ═══════════════════════════════════════════════════════════════════════════ */
/* JEDER WAEHLER NENNT `img`, und das ist kein Schmuck: die Regel darueber
   (.brand-logo img) ist mit Klasse UND Element staerker als eine Klasse allein.
   Ohne das `img` hier blieb `display: none` wirkungslos — im hellen Modus stand
   das weisse Logo unsichtbar auf weissem Grund UNTER dem blauen und schob die
   Beschriftung "Web-Portal" um seine ganze Hoehe nach unten (gemessen: 126,6
   statt 71,7 px). Im Dunkelmodus fiel es nicht auf, weil die Regeln dort zwei
   Klassen tragen und damit ohnehin gewinnen. */
.brand-logo img.brand-logo-dunkel {
    display: none;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .brand-logo img.brand-logo-hell {
        display: none;
    }

    :root:not([data-theme="light"]) .brand-logo img.brand-logo-dunkel {
        display: block;
    }
}

:root[data-theme="dark"] .brand-logo img.brand-logo-hell {
    display: none;
}

:root[data-theme="dark"] .brand-logo img.brand-logo-dunkel {
    display: block;
}

.brand-tagline {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

/* AUF DER ANMELDEKARTE ZWEI STUFEN GROESSER.
   ─────────────────────────────────────────────────────────────────────────────
   Dort steht das Logo gross und allein, und "WEB-PORTAL" darunter verschwand
   dagegen — 0.7rem sind elf Pixel unter einem Schriftzug von rund achtzig.

   NUR dort: in der Seitenleiste steht dasselbe Wort unter einem viel kleineren
   Logo und in einer Spalte, die jeden Millimeter braucht. Was auf der einen
   Seite zu klein ist, ist auf der anderen richtig. */
.auth-card .brand-tagline {
    font-size: 0.9rem;
    letter-spacing: 0.08em;
}

/* eMind logo (login footer) has a real opaque white background in the source JPG,
   so it keeps a white badge behind it. The Ventus logo (transparent PNG) does not. */
.brand-logo-badge {
    background: #ffffff;
    border-radius: var(--radius);
    padding: 0.4rem 0.75rem;
    box-shadow: var(--shadow-sm);
}

.brand-logo-small img {
    height: 20px;
}

.auth-card .brand-logo img {
    height: auto;
    width: auto;
    max-height: 280px;
    max-width: 100%;
}

/* ---------- Theme toggle ---------- */

/* DIE SYMBOLKNOEPFE DER KOPFZEILE sind Knoepfe wie alle anderen: kraeftiger
   Rahmen, weisser Grund, derselbe flache Schatten. Sie standen auf dem
   Seitengrund (--color-bg) und mit dem Trennlinien-Ton umrandet — in einer
   weissen Kopfzeile sah das aus wie eine Vertiefung und nicht wie etwas, das
   man drueckt. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    color: var(--color-text-muted);
    border-radius: var(--radius);
    padding: 0.3rem 0.55rem;
    font-size: 0.85rem;
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: color var(--duration) var(--ease), background-color var(--duration) var(--ease),
        border-color var(--duration) var(--ease);
}

.theme-toggle:hover {
    color: var(--color-text);
    background: var(--color-hover);
    border-color: var(--color-text-muted);
}

.theme-toggle-icon {
    /* Am KNOPF steht nur das Zeichen der gewaehlten Ansicht — die drei Staende
       (Hell, Dunkel, System) stehen im Menue darunter mit Namen. Solange beides
       Sonne und Mond waren, konnten beide nebeneinander stehen; mit "System"
       waeren es drei Zeichen in einem Knopf von 36 px, und keines davon
       lesbar. */
    display: none;
    line-height: 1;
}

.theme-toggle-icon.active {
    display: inline;
    opacity: 1;
    color: var(--color-text);
}

/* ---------- Ansicht: Hell / Dunkel / System (partials/theme-toggle.php) ----------
   Derselbe Bautyp wie der Sprachumschalter daneben: ein Knopf mit dem Zeichen
   der Wahl, darunter ein Menue mit den drei Staenden. position:relative, weil
   das Menue an ihm haengt. */
.theme-switch {
    position: relative;
    display: flex;
    align-items: center;
}

.theme-switch-knopf {
    justify-content: center;
}

.theme-switch-popup {
    min-width: 150px;
}

/* Zeichen und Name NEBENEINANDER — dieselbe Begruendung wie beim
   Sprachumschalter: .doc-view-popup-link setzt weiter unten `display: block`,
   und die spaetere Regel gewaenne mit gleicher Staerke. */
.doc-view-popup-link.theme-switch-eintrag {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.theme-switch-zeichen {
    width: 1.1em;
    text-align: center;
    color: var(--color-text-muted);
}

.theme-switch-eintrag.active {
    font-weight: 600;
    color: var(--color-primary);
}

.theme-switch-eintrag.active .theme-switch-zeichen {
    color: var(--color-primary);
}

/* ═══════════════════════════════════════════════════════════════════════════
   ALLE KNOEPFE DER KOPFZEILE GLEICH HOCH
   ═══════════════════════════════════════════════════════════════════════════
   Sie waren es nicht, und der Grund war, dass drei verschiedene Regeln ihre
   Groesse auf drei verschiedene Weisen bestimmten:

     .theme-toggle       Hoehe aus Polster + Zeilenhoehe (Sprache, Hell/Dunkel,
                         Dichte, Suche, News, Hilfe)
     .lang-switch-knopf  Hoehe aus Polster + Hoehe der FLAGGENGRAFIK
     .topbar-logout      feste 36 x 36 px

   Damit war die Gleichheit Zufall: sie hielt, solange niemand ein Zeichen, eine
   Schriftgroesse oder eine Grafik anfasste. Sichtbar wurde es, als das
   Design-System die Schrift wechselte — die Umrandeten wuchsen mit der
   Zeilenhoehe, der feste Abmelden-Knopf nicht.

   Jetzt kommt die Hoehe fuer ALLE aus derselben Marke, und nur der Grund
   unterscheidet sie: umrandet fuer die Werkzeuge, gefuellt fuer das Abmelden.
   min-width haelt die Knoepfe mit einem einzelnen Zeichen quadratisch, ohne die
   breiteren (Hell/Dunkel traegt zwei) zu begrenzen.

   Dieselben zwei Knoepfe stehen am FUSS DER ANMELDEKARTE (auth-werkzeuge.php,
   Sprache und Hell/Dunkel) — dort galt derselbe Zufall, deshalb steht der
   Behaelter mit in der Auswahl.
   ═══════════════════════════════════════════════════════════════════════════ */
.topbar .theme-toggle,
.topbar .lang-switch-knopf,
.topbar .topbar-logout,
.auth-werkzeuge .theme-toggle,
.auth-werkzeuge .lang-switch-knopf {
    height: var(--hoehe-symbolknopf);
    min-width: var(--hoehe-symbolknopf);
    /* Schmaleres Polster als vorher (space-1 statt space-2): damit bleiben auch
       die beiden Knoepfe mit breiterem Inhalt — die Flagge und das Paar aus
       Sonne und Mond — im Quadrat der uebrigen. Gemessen waren sie 38 und 43
       Pixel breit neben 36; in einer Reihe aus sieben Zeichen faellt das auf,
       ohne dass man sagen koennte, woran es liegt. */
    padding: 0 var(--space-1);
    justify-content: center;
}

/* Die Grafik darf die Hoehe des Knopfes nicht mehr vorgeben. */
.topbar .lang-switch-flag,
.auth-werkzeuge .lang-switch-flag {
    max-height: calc(var(--hoehe-symbolknopf) - 0.75rem);
    width: auto;
}

/* ---------- Language switch ---------- */

.lang-switch {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* Flagge der aktuellen Sprache, links neben der Auswahl. Sie steht dort und
   nicht IM <option>: dort ist nur Text erlaubt, und als Emoji fehlte sie unter
   Windows ganz (siehe Ventus\Support\Flag). */
.lang-switch-flag {
    display: block;
    flex: 0 0 auto;
    border-radius: 2px;
}

/* Der Knopf traegt NUR die Flagge — der Sprachname steht erst im offenen Menue
   (siehe partials/lang-switch.php). position:relative, weil das Menue an ihm
   haengt. */
.lang-switch {
    position: relative;
}

.lang-switch-knopf {
    display: inline-flex;
    align-items: center;
    padding: 0.3rem 0.45rem;
    border-radius: var(--radius);
    background: var(--color-surface);
    /* Wie .theme-toggle daneben — siehe die Begruendung dort. */
    border: 1px solid var(--color-border-strong);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
}

.lang-switch-knopf:hover {
    border-color: var(--color-text-muted);
    background: var(--color-hover);
}

/* Schmaler als das Dokument-Menue, aus dem die Klassen kommen: hier stehen sechs
   Sprachnamen und keine Saetze. */
.lang-switch-popup {
    min-width: 170px;
}

/* Flagge und Sprachname NEBENEINANDER.

   Zwei Klassen im Waehler, und das ist der Grund: .doc-view-popup-link (aus dem
   Dokument-Menue, dieselbe Klasse traegt jeder Eintrag hier) setzt weiter unten
   in der Datei `display: block`. Mit nur `.lang-switch-eintrag` waere die
   Staerke gleich und die spaetere Regel gewinnt — die Flagge stand dann UEBER
   dem Namen, und das Menue war doppelt so hoch. */
.doc-view-popup-link.lang-switch-eintrag {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.lang-switch-eintrag.active {
    font-weight: 600;
    color: var(--color-primary);
}

/* ---------- Footer ---------- */

.app-footer {
    padding: 1rem 2rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border);
}

.auth-footer {
    border-top: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 0 0 1.5rem;
}

.auth-toolbar {
    display: flex;
    justify-content: center;
    gap: 0.75rem;
    padding: 1.5rem 0 0;
}

/* Sprachwahl und Hell/Dunkel am FUSS DER KARTE, rechts (siehe
   partials/auth-werkzeuge.php). Die Trennlinie darueber sagt: das gehoert zur
   Karte, ist aber nicht Teil des Formulars. */
.auth-werkzeuge {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

/* Das Sprachmenue oeffnet hier NACH OBEN: unter dem Kartenfuss ist kein Platz,
   dort waeren die sechs Sprachen halb ausserhalb des Fensters. `top: auto`
   muss mit, sonst gilt das `top` aus .doc-view-popup weiter und das Menue
   stuende an zwei Kanten gleichzeitig. */
.auth-werkzeuge .lang-switch-popup,
.auth-werkzeuge .theme-switch-popup {
    top: auto;
    bottom: calc(100% + 0.4rem);
}

/* ---------- Stat tiles ---------- */

.stat-tiles {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

/* ---------------------------------------------------------------------------
   DICHTE DER ARBEITSLISTEN
   Gemessen an den Offenen Posten auf 1600x1000: die erste Datenzeile begann bei
   481 px, also nach 48 % der Fensterhoehe — sichtbar waren neun Zeilen. Die
   Hoehe ging fuer drei Zahlen in 149 px hohen Kacheln, eine 91 px hohe
   Suchleiste und 54 px hohe Tabellenzeilen. In einer Maske, in der den ganzen
   Tag Zeilen gelesen und angehakt werden, ist das der teuerste Platz im Haus.

   Die folgenden Regeln aendern NUR Abstaende und Schriftgroessen, keine Farben
   und keine Anordnung — das Aussehen bleibt, es passt mehr aufs Blatt.
   --------------------------------------------------------------------------- */

/* Kachel: Symbol links, Beschriftung und Wert rechts untereinander. Vorher
   standen alle drei untereinander, das kostete zwei Zeilenhoehen. */
.stat-tile {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 0.15rem 0.7rem;
    position: relative;
    padding: 0.7rem 1rem;
}

/* Das Zeichen einer Kennzahlenkachel: Platz im Raster UND Groesse. Beides stand
   in zwei Regeln mit DEMSELBEN Selektor, achthundert Zeilen auseinander — wer
   die eine fand, hielt sie fuer die ganze Wahrheit. */
.stat-tile .stat-icon {
    grid-row: 1 / span 2;
    align-self: center;
    width: 22px;
    height: 22px;
    margin-bottom: 0.2rem;
}

.stat-label {
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

/* DIE ZAHL IST DER INHALT DER KACHEL. Die Beschriftung darueber sagt, WAS
   gezaehlt wird, und die liest man einmal; danach sieht man nur noch auf die
   Zahl — aus zwei Metern Abstand vom Bildschirm im Buero genauso wie beim
   Vorbeigehen. Sie war mit 1,35 rem kaum groesser als eine Ueberschrift in
   einer Karte, und in der kompakten Ansicht — seit sie die Vorgabe ist, also
   fast immer — mit 1,1 rem nur eine Spur groesser als der Fliesstext daneben.

   Fett und gross zugleich waere zu viel: das Gewicht bleibt bei 600, die
   Groesse traegt den Unterschied. */
.stat-value {
    font-size: 1.7rem;
    font-weight: 600;
    line-height: 1.15;
}

/* Die vierte Kachel der Offenen Posten hat eine dritte Zeile (Summe der
   Markierung) — sie gehoert unter den Wert, nicht neben das Symbol. */
.stat-tile .stat-sub {
    grid-column: 2;
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

/* ---------- Sales chart ---------- */

.chart-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: 1.25rem 1.5rem 0.5rem;
    margin: 1.5rem 0;
}

.chart-card h2 {
    margin: 0 0 1rem;
    font-size: 1rem;
}

.chart-tabs {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

/* Export in der Tab-Zeile (Verkaufsstatistik): ganz rechts, weil er dem offenen
   Tab folgt und deshalb dort hingehoert, wo die Tabs stehen. */
.chart-tabs .doc-view-menu {
    margin-left: auto;
}

/* Zeitraum-Umschalter (Tag | Woche | Monat | Jahr) als KAPSELN, nicht als
   Reiter: sie schalten einen Filter um und nicht den Abschnitt der Seite. Die
   Reiter mit Unterstrich (.tabs/.tab weiter unten) bleiben den Abschnitten
   vorbehalten — Kundendetail, Systemeinstellungen —, damit an der Form ablesbar
   ist, was passiert. */
.chart-tab {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text-muted);
    border-radius: var(--radius-pill);
    height: 32px;
    padding: 0 var(--space-3);
    font-size: 0.8rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.chart-tab:hover:not(.active) {
    background: var(--color-surface-alt);
    color: var(--color-text);
}

.chart-tab.active {
    color: var(--auf-farbflaeche);
    background: var(--color-primary);
    border-color: var(--color-primary);
}

.chart-panel {
    display: none;
}

.chart-panel.active {
    display: block;
}

/* Generische Inhalts-Tabs (z. B. Kundendetail: Zugehörige Personen/Parameter) —
   gleiches Verhalten wie .chart-tab/.chart-panel, nur etwas größer/prominenter,
   da hier ganze Abschnitte statt Chart-Zeiträume umgeschaltet werden. */
.tabs {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--color-border);
    /* KEIN REITER FAELLT WEG. Gemessen im Kontenblatt bei 900 px Fensterbreite:
       die Reiterzeile war 332 px breit, ihr Inhalt 513 — "Jahresliste" und
       "Gegenkonten" standen ausserhalb und waren nicht erreichbar, ohne dass
       etwas darauf hingewiesen haette. Jetzt rollt die Zeile seitlich.

       Rollen und nicht umbrechen: die Reiter sind eine Reihe, und eine zweite
       Zeile unter dem Trennstrich sieht aus wie ein anderer Abschnitt. */
    overflow-x: auto;
}

/* Ein Knopf IN der Reiterzeile: rechts aussen und auf der Grundlinie der
   Reiter (deren Unterstrich sitzt 0.5rem tiefer als die Schrift).
   
   Die beiden Raender gelten NUR dort. In den Stammdaten sitzt derselbe Knopf in
   der Werkzeugleiste der Titelzeile — dort machte margin-bottom die Zeile 8px
   hoeher, und die Suchleiste dieser einen Maske begann tiefer als in allen
   anderen. */
.tabs .tabs-add-button,
.tabs .tabs-action-button {
    margin-left: auto;
    margin-bottom: 0.5rem;
}

.tab {
    border: none;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--color-text-muted);
    padding: 0.65rem 0.1rem;
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition: color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.tab:hover:not(.active) {
    color: var(--color-text);
}

.tab.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.tab:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.tab-panel {
    display: none;
}

.tab-panel.active {
    display: block;
}

.chart-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    margin-bottom: 1.25rem;
}

.chart-mini {
    flex: 1 1 240px;
    min-width: 0;
    height: 260px;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    padding: 0.85rem 1rem;
}

.chart-mini h3 {
    flex-shrink: 0;
    margin: 0 0 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.chart-mini .chart-svg {
    flex-shrink: 0;
}

.chart-svg {
    width: 100%;
    height: auto;
    aspect-ratio: 720 / 220;
    display: block;
    overflow: visible;
}

.chart-bar {
    fill: var(--color-primary);
}

/* ---------------------------------------------------------------------------
   DIE LINIE DER BUCHUNGSENTWICKLUNG
   ---------------------------------------------------------------------------
   Eigene Ansichtsbox (720x180) und damit ein anderes Seitenverhaeltnis als die
   Balken (720x220) — die Linie braucht weniger Hoehe, um dasselbe zu sagen.
   Ohne diese Regel zoege .chart-svg sie auf 220 und die Linie stuende in einem
   Feld mit 40 px Luft darunter.

   Die FARBEN kommen aus den Marken und nicht aus dem SVG: damit stimmt das
   Bild im Dunkelmodus, ohne dass hier eine zweite Farbtabelle stuende. Die
   Flaeche ist dieselbe Markenfarbe mit 14 % Deckung — genug, um die Richtung
   zu sehen, zu wenig, um die Rasterlinien zu verdecken.
   --------------------------------------------------------------------------- */
.chart-svg.chart-linie {
    aspect-ratio: 720 / 150;
}

.chart-line {
    fill: none;
    stroke: var(--color-primary);
    stroke-width: 2.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.chart-flaeche {
    fill: var(--color-primary);
    opacity: 0.14;
    stroke: none;
}

.chart-punkt {
    fill: var(--color-surface);
    stroke: var(--color-primary);
    stroke-width: 2;
}

/* Der Punkt unter dem Zeiger wird gefuellt — das Fangfeld liegt darueber und
   traegt die Klasse, also greift der Nachbarselektor. */
.chart-hit.chart-hover + .chart-punkt,
.chart-punkt:hover {
    fill: var(--color-primary);
}

.chart-bar-group.chart-hover .chart-bar {
    opacity: 0.8;
}

.chart-hit {
    fill: transparent;
    cursor: pointer;
}

.chart-gridline {
    stroke: var(--color-border);
    stroke-width: 1;
}

.chart-baseline {
    stroke: var(--color-text-muted);
    stroke-width: 1;
}

.chart-axis-label {
    fill: var(--color-text-muted);
    font-size: 13px;
}

.chart-count-label {
    fill: var(--color-primary);
    font-size: 11px;
    font-weight: 600;
}

.chart-tooltip {
    position: fixed;
    z-index: 50;
    background: var(--color-tooltip-bg);
    color: var(--color-tooltip-text);
    padding: 0.4rem 0.65rem;
    border-radius: var(--radius);
    font-size: 0.78rem;
    line-height: 1.4;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.1s ease;
    white-space: nowrap;
}

.chart-tooltip.visible {
    opacity: 1;
}

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

/* ═══════════════════════════════════════════════════════════════════════════
   STARTSEITE — Raster, Handlungsbedarf, Kurzlisten
   ═══════════════════════════════════════════════════════════════════════════
   Alles, was nur die Startseite betrifft, steht hier zusammen. Es benutzt die
   vorhandenen Marken und die vorhandenen Klassen (.card, .export-button,
   .data-table, .stat-tile) — neu sind nur die Anordnung und die drei
   Dringlichkeitsstufen.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Zwei Drittel Entwicklung, ein Drittel Handlungsbedarf. Kein fester
   Pixelwert: minmax(0, …) laesst die Grafik schrumpfen, statt das Raster zu
   sprengen — ein SVG mit fester Ansichtsbox tut das sonst. */
/* align-items bleibt auf dem Vorgabewert `stretch`: die Karten einer Reihe sind
   damit GLEICH HOCH. Vorher stand hier `start`, und jede Karte war so hoch wie
   ihr Inhalt — der Handlungsbedarf wuchs mit jedem Eintrag, und die beiden
   Karten darunter endeten auf verschiedenen Hoehen. */
.dashboard-raster {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

/**
 * DIE OPERATIVEN KARTEN — DREI in EINER Reihe.
 *
 * Es waren vier in zwei Reihen (dazu anstehende Reisen und kommende
 * Optionsfristen). Jetzt sind es drei — letzte Buchungen, offene Posten,
 * Wiedervorlagen —, und sie stehen nebeneinander: bei 1600 px Seitenbreite
 * bekommt jede rund 500 px, und darin sind drei bis fuenf Spalten lesbar.
 * Genau dafuer hat die Karte "Offene Posten" ihre vierte Spalte abgegeben.
 *
 * auto-fit und keine feste Spaltenzahl: faellt eine Karte wegen fehlender
 * Rechte weg, ruecken die uebrigen nach, und eine einzelne nimmt die ganze
 * Breite statt zwei Drittel leer zu lassen. Unter 380px Kartenbreite bricht
 * das Raster von selbst um — bei 1180 px Fenster auf zwei Karten, auf dem
 * Telefon auf eine.
 */
.dashboard-raster-op {
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
}

/* Fehlt das Diagramm (kein Recht auf Buchungen), ist die obere Reihe
   einspaltig — sonst staende der Handlungsbedarf in einem Drittel und daneben
   nichts. */
.dashboard-raster-eins {
    grid-template-columns: minmax(0, 1fr);
}

/**
 * DIE STARTSEITE NUTZT DIE GANZE BREITE — wie jede andere Maske.
 *
 * Hier stand eine Obergrenze von 1600 px. Ihr Grund war das Diagramm: es wurde
 * auf einem 27-Zoll-Schirm 1300 px breit und blieb 400 px hoch, also ein
 * flacher Streifen, in dem die Linie nichts mehr aussagte.
 *
 * Dieser Grund ist weg, und zwar an der richtigen Stelle geloest: .chart-svg
 * haelt sein Seitenverhaeltnis (aspect-ratio 720/150). Das Diagramm waechst
 * heute in der HOEHE mit, wenn es breiter wird — aus 1300 px Breite werden
 * 270 px Hoehe und kein Streifen. Eine Grenze fuer die ganze Seite war damit
 * die Antwort auf eine Frage, die eine einzelne Kachel selbst beantwortet.
 *
 * Was bleibt, ist eine Abwaegung und kein Fehler: auf sehr breiten Schirmen
 * werden die drei Karten der unteren Reihe (Letzte Buchungen, Offene Posten,
 * Wiedervorlagen) sehr breit, und zwischen Nummer und Betrag liegt viel Luft.
 * Wer den Platz lieber knapp haette, nimmt die kompakte Ansicht — die ist die
 * Vorgabe und schneidet Abstaende, nicht Inhalte.
 *
 * Die Klasse bleibt bestehen: an ihr haengen die Rasterregeln der Startseite
 * (dashboard-raster, dashboard-block), nur ihre Breitenregel ist entfallen.
 */

/* Der Zeitraum der Kennzahlenreihe: einmal darueber statt fuenfmal in den
   Beschriftungen. */
.dashboard-zeitraum {
    margin: var(--space-4) 0 calc(-1 * var(--space-2));
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

/* .chart-card bringt einen eigenen Aussenabstand mit (sie stand frueher allein
   untereinander). Im Raster macht den Abstand die Luecke. */
.dashboard-raster .chart-card {
    margin: 0;
}

.dashboard-stand {
    color: var(--color-text-subtle);
}

.dashboard-stand::before {
    content: " · ";
}

/* Kachel "laufender Monat": dieselbe Form wie die drei daneben, eigene Farbe
   wie jede der anderen auch. */
.stat-tile-monat .stat-icon,
.stat-tile-monat .stat-value {
    color: var(--color-primary);
}

/* Stornos: die Warnfarbe, nicht die Gefahrenfarbe. Ein Storno ist ein
   normaler Geschaeftsvorfall — rot waere eine Wertung. */
.stat-tile-storno .stat-icon,
.stat-tile-storno .stat-value {
    color: var(--color-warning-text);
}

/* Die Veraenderung gegenueber dem Vormonat. Das Vorzeichen steht IM Text — die
   Farbe ist die Zugabe, nicht die Aussage. */
.db-delta {
    font-weight: 600;
}

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

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

/* ---------- Handlungsbedarf ---------- */

/**
 * Der Handlungsbedarf ist so hoch wie die Grafik daneben — nicht so hoch wie
 * seine Liste.
 *
 * DIE GRAFIK GIBT DIE HOEHE VOR. `min-height: 0` nimmt dieser Karte die
 * automatische Mindesthoehe eines Rasterfeldes (sie waere sonst so gross wie
 * ihr Inhalt und wuerde die ganze Zeile mitwachsen lassen). Uebrig bleibt die
 * Zeilenhoehe, die das andere Feld setzt — und in die rollt die Liste hinein.
 *
 * Ueberschrift und Zaehler stehen AUSSERHALB des rollenden Bereichs: sie sind
 * Geschwister der Liste, nicht ihr Inhalt.
 */
.dashboard-aufgaben {
    display: flex;
    flex-direction: column;
    min-height: 0;
    /* Notbremse, weit oberhalb der Diagrammhoehe: die Kopplung an die
       Nachbarkarte macht die Hoehe im Regelfall, aber ein Rasterfeld richtet
       sich nach dem GROESSTEN Inhalt seiner Zeile. Stuenden hier einmal
       fuenfzehn Eintraege, koennte die Karte die Zeile mitziehen. Ab hier
       nicht mehr — im Normalfall greift diese Zeile nie. */
    max-height: 40rem;
    padding: var(--space-4) var(--space-4) var(--space-3);
}

/**
 * VIER EINTRAEGE SICHTBAR, DER FUENFTE ROLLT.
 *
 * Die Hoehe ist GERECHNET und nicht geraten: vier Eintraege je
 * --hoehe-db-eintrag. Ein Eintrag ist zwei Zeilen (Stufe + Titel, darunter die
 * Kontextzeile) plus Innenabstand — gemessen 66 px, in der kompakten Ansicht
 * weniger, deshalb steht die Marke dort neu.
 *
 * Ueberschrift, Zahl und Kartenrahmen liegen AUSSERHALB dieses Kastens und
 * rollen nicht mit; die Karte waechst mit weiteren Faellen nicht, und die Seite
 * bekommt dadurch keine zweite Rollleiste.
 */
/* Der zweite Klassenname ist kein Zufall: `.card ul` (weiter oben) macht jede
   Liste in einer Karte zu einer Flexspalte mit 0.4rem Luecke. Hier ist die
   Trennlinie der Abstand — die zusaetzliche Luecke verschob nur die Rechnung
   unten (drei Luecken zwischen vier Eintraegen). Ein Klassenname mehr, damit
   diese Regel gewinnt. */
.dashboard-aufgaben .db-aufgaben-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    display: block;
    gap: 0;
    /* Nimmt den Platz unter der Ueberschrift ein. min-height: 0 auch hier — ein
       Flexkind waere sonst nicht kleiner als sein Inhalt. */
    flex: 1 1 auto;
    min-height: 0;
    max-height: calc(4 * var(--hoehe-db-eintrag));
    overflow-y: auto;
}

/* Links die Zeile (Stufe, Titel, Angaben), rechts der Weg dorthin. */
/**
 * EIN EINTRAG IN ZWEI ZEILEN, nicht in drei.
 *
 * Die Stufe stand als eigene Zeile ueber dem Titel — drei Zeilen je Fall, und
 * bei fuenf Faellen war die Karte 480 px hoch, waehrend die Grafik daneben mit
 * 340 auskam. Der Rest der Zeile war leerer Kasten.
 *
 * Jetzt: Stufe UND Titel in der ersten Zeile, die Kontextzeile darunter, der
 * Weg dorthin rechts ueber beide. Das sind rund 64 px je Fall — fuenf davon
 * passen neben die Grafik, ohne dass eine der beiden Karten leer wirkt.
 */
.db-aufgabe {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.1rem var(--space-3);
    padding: var(--space-3) 0;
    border-top: 1px solid var(--color-border);
}

.db-aufgabe .db-marke {
    grid-column: 1;
    grid-row: 1;
}

.db-aufgabe .db-aufgabe-titel {
    grid-column: 2;
    grid-row: 1;
}

.db-aufgabe .db-aufgabe-text {
    grid-column: 1 / span 2;
    grid-row: 2;
}

.db-aufgabe .db-aufgabe-knopf {
    grid-column: 3;
    grid-row: 1 / span 2;
}

.db-aufgabe:first-child {
    border-top: 0;
    padding-top: 0;
}

.db-marke,
.db-aufgabe-titel,
.db-aufgabe-text {
    grid-column: 1;
}

.db-aufgabe-knopf {
    grid-column: 2;
    grid-row: 1 / span 3;
}

/* Die Stufe als WORT — Farbe allein waere im Ausdruck, bei Farbenblindheit und
   in einer Vorlesehilfe keine Aussage. */
.db-marke {
    justify-self: start;
    padding: 0.05rem 0.45rem;
    border-radius: var(--radius-pill);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}


.db-aufgabe-titel {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.9rem;
    font-weight: 600;
}

.db-aufgabe-titel .icon {
    width: 15px;
    height: 15px;
    color: var(--color-text-muted);
}

/**
 * DIE KONTEXTZEILE BLEIBT EINE ZEILE.
 *
 * "Buchung 100440 · Max Testkunde · 30.08.2026 18:00" brauchte in der 427 px
 * breiten Spalte zwei Zeilen; bei fuenf Faellen wurde die Karte dadurch 150 px
 * hoeher als die Grafik daneben, und in der Grafikkarte stand entsprechend viel
 * leerer Kasten.
 *
 * Deshalb eine Zeile mit Auslassungspunkten — und die FRIST steht darin vorn:
 * gekuerzt wird damit der Name und nicht der Termin. Der ganze Text steht im
 * Titel (Hoverhinweis) und in der Maske hinter "Öffnen".
 */
.db-aufgabe-text {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---------- Kurzlisten (kommende Optionen, letzte Buchungen) ---------- */

/**
 * KOMPAKTER ALS EINE ARBEITSLISTE.
 *
 * Eine Kurzliste der Startseite traegt fuenf Zeilen mit drei bis vier Angaben —
 * sie braucht die Zeilenhoehe einer Arbeitsliste nicht, in der den ganzen Tag
 * angehakt und geklickt wird. Die Zeilenhoehe wird deshalb hier lokal auf die
 * FELDHOEHE gesetzt: 44px statt 56px, in der kompakten Ansicht 34px statt 38px.
 *
 * Eine Marke, kein zweiter Satz Werte: --hoehe-feld folgt der Dichte von
 * selbst, und der Deckel der Tabelle (max-height weiter unten) rechnet mit
 * derselben Marke — er geht also automatisch mit.
 */
.dashboard-block {
    display: flex;
    flex-direction: column;
    --hoehe-tabellenzeile: var(--hoehe-feld);
    padding: var(--space-4);
}

/* Die Ueberschrift einer Kurzliste steht dichter am Inhalt als die einer
   ganzen Maske — die Karte ist klein, und 12px Vorlauf sind darin viel. */
.dashboard-block h2,
.dashboard-aufgaben h2 {
    margin-bottom: var(--space-2);
}

/**
 * KEIN UMBRUCH IN EINER KURZLISTE.
 *
 * Gemessen bei drei Karten in einer Reihe: "Franz Fremd" brach in zwei Zeilen
 * um, die Zeile wurde 54 statt 44 px hoch, und aus fuenf Zeilen wurden 270 px
 * statt 220. Zwei Zeilen in einer Zelle sind in einer Uebersicht ohnehin kein
 * Gewinn — man liest sie nicht besser, die Karte wird nur hoeher.
 */
.dashboard-block .data-table td {
    white-space: nowrap;
}

/* Enger als in einer Arbeitsliste: dort stehen 1200 px fuer acht Spalten zur
   Verfuegung, hier 390 fuer vier. Der Kopf behaelt seinen Umbruch
   (.data-table th, white-space: pre-line) — "Gesamtpreis (EUR)" untereinander
   macht die Spalte SCHMALER, nicht breiter. */
.dashboard-block .data-table th,
.dashboard-block .data-table td {
    padding-left: var(--space-2);
    padding-right: var(--space-2);
}

/* Die eine Spalte, die kuerzen darf: der Freitext (Name, Notiz). Ein langer
   Kundenname wuerde sonst die Zahlen aus der Karte schieben. Gekuerzt wird mit
   Auslassungspunkten, der ganze Text steht im Titel — und vollstaendig in der
   Maske hinter "Alle anzeigen". */
.dashboard-block .data-table td.zell-kurzen {
    /* 7.5rem: bei 9 war die Tabelle der letzten Buchungen 393 px breit in einem
       387 px breiten Kasten — sechs Pixel, die eine Rollleiste erzeugen. */
    max-width: 7.5rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/**
 * FUENF ZEILEN — UND KEIN GERECHNETER DECKEL MEHR.
 *
 * Hier stand eine Obergrenze aus Kopfhoehe plus fuenf Zeilenhoehen. Sie war ein
 * Auffangnetz gegen umgebrochene Zellen: bricht ein Kundenname in eine zweite
 * Zeile, wuchs die Karte sonst mit.
 *
 * Umgebrochen wird jetzt nichts mehr (siehe oben, white-space: nowrap), und
 * geholt werden ohnehin genau fuenf Zeilen. Damit ist die Hoehe der Karte
 * vorhersagbar — der gerechnete Deckel war es nicht: er lag rund 20 px unter
 * dem, was Kopf und fuenf Zeilen wirklich brauchen, und schnitt die fuenfte
 * Zeile an. Gemessen bei drei Karten in einer Reihe: Inhalt 305 px, Deckel 282.
 *
 * Der Bildlauf bleibt fuer die BREITE: passt eine Tabelle einmal nicht, rollt
 * sie seitlich statt die Seite zu sprengen. Der Tabellenkopf ist geheftet
 * (`.data-table thead th`, position: sticky) und bleibt dabei stehen.
 *
 * Der Rahmen entfaellt: die Tabelle steht in einer Karte, die schon einen hat.
 */
.dashboard-block .table-scroll {
    border: 0;
}

/* In einer Kurzliste ist die zweite Angabe einer Zelle eine eigene ZEILE (das
   Buchungsdatum unter der Nummer, die Buchungsnummer unter der Notiz). In den
   Arbeitslisten steht sie hinter dem Wert — dort ist Platz in der Breite, hier
   nicht. */
.dashboard-block .zell-zweite {
    display: block;
    margin-top: 0;
}

/**
 * DER FUSS EINER KURZLISTE — in allen vier Karten derselbe.
 *
 * "Alle anzeigen" sass bisher als blosser Absatz unter der Tabelle und las sich
 * wie Fliesstext. Es ist aber der Weg in die vollstaendige Maske und damit die
 * einzige Handlung der Karte.
 *
 * Deshalb: eine Trennlinie darueber (der Fuss ist ein eigener Bereich, kein
 * Anhaengsel der Tabelle), Markenfarbe und Gewicht 600 — erkennbar als Verweis,
 * aber ohne Knopfoptik; er soll die Karte nicht dominieren.
 *
 * margin-top: auto haelt ihn am Kartenfuss, auch wenn die Nachbarkarte hoeher
 * ist. Der Abstand kommt als Polster, damit das auto ihn nicht auffrisst.
 */
.dashboard-mehr {
    margin: auto 0 0;
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    font-size: 0.8rem;
}

.dashboard-mehr a {
    color: var(--color-primary);
    font-weight: 600;
}

.dashboard-mehr a:hover {
    text-decoration: underline;
}

/* ═══════════════════════════════════════════════════════════════════════════
   EBENE 2 — DER KOPF DER BUCHUNGSENTWICKLUNG
   ═══════════════════════════════════════════════════════════════════════════
   Ueberschrift, Zeitraumschalter und Fensterhinweis in EINER Zeile: das sparte
   gegenueber "Titel oben, Schalter darunter" eine Zeilenhoehe, und die Karte
   soll kompakter sein als die Saeulenkarte davor. Bricht die Zeile auf schmalen
   Fenstern um, geht der Hinweis nach unten und nicht der Schalter — er ist die
   Beschriftung, nicht die Bedienung.
   ═══════════════════════════════════════════════════════════════════════════ */
/**
 * DIE KARTE IST SO HOCH WIE DIE REIHE — UND HAT KEIN LOCH.
 *
 * Sie steht mit dem Handlungsbedarf in einem Raster, und Rasterfelder einer
 * Zeile sind gleich hoch (align-items: stretch). Ihr Inhalt ist aber kuerzer als
 * vier Aufgabenzeilen; die Differenz stand als leere Flaeche UNTER den vier
 * Kennzahlen — bei fuenf Aufgaben waren das 150 px.
 *
 * Jetzt ist die Karte selbst eine Spalte: die Diagrammflaeche nimmt den Platz
 * (flex: 1), die vier Kennzahlen liegen am Fuss (margin-top: auto). Was uebrig
 * ist, verteilt sich damit UM den Inhalt und nicht als Loch dahinter. Eine feste
 * Mindesthoehe gibt es nicht.
 */
.dashboard-entwicklung {
    display: flex;
    flex-direction: column;
}

/* Die aktive Flaeche ist hier eine Spalte (Diagramm oben, Kennzahlen unten) und
   nicht der Block aus der allgemeinen Regel. */
.dashboard-entwicklung .chart-panel.active {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.entwicklung-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.entwicklung-kopf h2 {
    margin: 0;
}

.entwicklung-kopf .chart-tabs {
    margin-bottom: 0;
}

/* Der Fensterhinweis ("Letzte 8 Wochen") steht dreimal in der Seite, einer je
   Zeitraum — sichtbar ist der des gewaehlten. Er teilt sich die Kennung
   data-panel-key mit den Diagrammflaechen, deshalb schaltet ihn derselbe
   Klick um; die Anzeige regelt aber DIESE Regel und nicht .chart-panel, denn
   ein Block in einer Flex-Zeile stuende in einer eigenen Zeile. */
.entwicklung-fenster {
    display: none;
    margin-left: auto;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.entwicklung-fenster.active {
    display: inline;
}

/* ---------------------------------------------------------------------------
   DIE VIER KENNZAHLEN UNTER DEM DIAGRAMM
   ---------------------------------------------------------------------------
   Vier gleich breite Felder, getrennt durch eine Linie nach oben. Sie sind die
   TEXTFASSUNG des Diagramms: wer die Linie nicht ablesen kann oder nicht
   ablesen will, findet hier Summe, Durchschnitt, staerkste und letzte Periode
   als Zahl. Deshalb stehen sie in der Karte und nicht daneben.

   auto-fit statt repeat(4, …): auf einem schmalen Fenster werden es zwei
   Reihen mit je zwei Feldern statt vier Spalten mit abgeschnittenen Zahlen.
   --------------------------------------------------------------------------- */
.entwicklung-kennzahlen {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: var(--space-2) var(--space-4);
    /* auto oben: die vier Zahlen liegen am Kartenfuss, nicht unter dem Diagramm
       mit Leerraum dahinter (siehe .dashboard-entwicklung). */
    margin: auto 0 0;
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}

.entwicklung-kennzahl dt {
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

/* Die vier Zahlen unter der Buchungsentwicklung sind Kennzahlen wie die
   Kacheln oben, nur kleiner gesetzt: sie stehen zu viert nebeneinander unter
   einem Diagramm und nicht allein in einer Kachel. Gross genug muessen sie
   trotzdem sein — siehe .stat-value. */
.entwicklung-kennzahl dd {
    margin: 0.1rem 0 0;
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.2;
}

/* Einheit und Periodenname sind ZUSAETZE zur Zahl und nicht die Zahl: kleiner
   und in gedaempfter Farbe, damit "3" und nicht "Buchungen" ins Auge fasst. */
.entwicklung-kennzahl .ek-einheit,
.entwicklung-kennzahl .ek-zusatz {
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--color-text-muted);
}

.entwicklung-kennzahl .ek-zusatz::before {
    content: "· ";
}

/* ═══════════════════════════════════════════════════════════════════════════
   EBENE 4 — DIE VERTEILUNG, GANZ UNTEN UND UEBER DIE VOLLE BREITE
   ═══════════════════════════════════════════════════════════════════════════
   Drei gleichwertige Felder in einer Karte: zwei Ringe und eine Rangliste.
   Gleichwertig heisst gleich breit — keines der drei ist die Hauptaussage.

   Der Zeitraum steht EINMAL im Kopf der Karte und nicht dreimal in den
   Unterueberschriften: er gilt fuer alle drei.
   ═══════════════════════════════════════════════════════════════════════════ */
.verteilung-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.verteilung-kopf h2 {
    margin: 0;
}

.verteilung-zeitraum {
    margin-left: auto;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.verteilung-raster {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

/* ---------------------------------------------------------------------------
   DIE RANGLISTE DER REISEZIELE
   ---------------------------------------------------------------------------
   Dieselben Balken wie in der Verkaufsstatistik (.bar-list-track /
   .bar-list-fill), nur nicht mit deren fester Breite von 160 px: hier soll der
   Balken die Spalte ausfuellen, damit die Rangfolge auch bei drei nahen Werten
   sichtbar bleibt.

   Die Zeilen sind niedriger als in einer Arbeitsliste — angehakt wird hier
   nichts, es wird gelesen.
   --------------------------------------------------------------------------- */
.verteilung-rang {
    /* Ein eigener Wert und nicht mehr die Hoehe eines Knopfes: die war nie
       gemeint, sie war nur zufaellig die Zahl, die "niedriger als eine
       Arbeitszeile" ergab — und seit alle Knoepfe Feldhoehe haben, waere die
       Rangliste so hoch wie eine Arbeitsliste. */
    --hoehe-tabellenzeile: 2.375rem;
    font-size: 0.82rem;
}

.verteilung-rang th,
.verteilung-rang td {
    padding-top: var(--space-1);
    padding-bottom: var(--space-1);
}

.verteilung-rang .verteilung-balken {
    width: 40%;
}

.verteilung-rang .bar-list-track {
    width: 100%;
    height: 8px;
}

/* Auf schmalen Fenstern steht der HANDLUNGSBEDARF OBEN. Ein Diagramm, an dem
   man erst vorbeiscrollen muss, um zu sehen, dass eine Frist abgelaufen ist,
   waere die falsche Reihenfolge — auf einem kleinen Schirm liest man das Erste.
   Vorhandener Umbruchpunkt, kein neuer. */
@media (max-width: 1200px) {
    .dashboard-raster {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Einspaltig gibt es keine Nachbarkarte mehr, an der sich die Hoehe messen
       koennte — der Handlungsbedarf waere wieder so hoch wie seine Liste.
       Deshalb hier eine Obergrenze; darueber rollt die Liste wie zuvor. Eine
       feste HOEHE waere falsch: bei zwei Eintraegen staende der halbe Kasten
       leer, und auf einem Telefon ist das die teuerste Flaeche. */
    .dashboard-aufgaben {
        order: -1;
        max-height: 24rem;
    }

    [data-dichte="kompakt"] .dashboard-aufgaben {
        max-height: 20rem;
    }

    /* Fuer die beiden Tabellen braucht es hier KEINE eigene Obergrenze mehr:
       fuenf Zeilen sind auch gestapelt keine Wand, und ein zweiter Wert waere
       nur eine zweite Stelle, an der man dieselbe Zahl pflegt. Vorher standen
       hier sechs — bei zehn sichtbaren Zeilen im Regelfall war das eine echte
       Begrenzung, bei fuenf waere es keine. */
}

/* Kompakte Ansicht: weniger Hoehe, gleiche Anordnung. Das Diagramm bleibt, wie
   es ist — kleiner waere es nicht mehr abzulesen. */
[data-dichte="kompakt"] .dashboard-raster {
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

[data-dichte="kompakt"] .dashboard-aufgaben,
[data-dichte="kompakt"] .dashboard-block {
    padding: var(--space-3);
}

[data-dichte="kompakt"] .db-aufgabe {
    padding: var(--space-2) 0;
}

/* Kompakt sind die Eintraege niedriger (Innenabstand space-2 statt space-3) —
   sichtbar bleiben vier, die Karte wird nur kuerzer. */
[data-dichte="kompakt"] {
    /* Gemessen 59 px je Eintrag statt 67 — die kompakte Ansicht nimmt den
       Innenabstand zurueck, nicht die Textzeilen. Vier zusammen 237 px. */
    --hoehe-db-eintrag: 3.75rem;
}

/* Die neuen Bereiche der Startseite in der kompakten Ansicht: engere Abstaende,
   gleiche Anordnung. Die Diagramme selbst bleiben, wie sie sind — kleiner waeren
   sie nicht mehr abzulesen. */
[data-dichte="kompakt"] .entwicklung-kennzahlen {
    padding-top: var(--space-2);
    gap: var(--space-1) var(--space-3);
}

[data-dichte="kompakt"] .entwicklung-kennzahl dd {
    font-size: 1.15rem;
}

[data-dichte="kompakt"] .verteilung-raster {
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

[data-dichte="kompakt"] .verteilung-raster .chart-mini {
    padding: var(--space-3);
    min-height: 13rem;
}

/* ---------- Statistik: Grafik-Spalte in der Tabelle (Balken pro Zeile) ---------- */

.bar-list-track {
    display: block;
    width: 160px;
    background: var(--color-surface-alt);
    border-radius: var(--radius);
    height: 10px;
    overflow: hidden;
}

.bar-list-fill {
    display: block;
    height: 100%;
    background: var(--color-primary);
    border-radius: var(--radius);
}

@media (max-width: 480px) {
    .bar-list-track {
        width: 100px;
    }
}

/* ---------- Icons ---------- */

.icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    vertical-align: -4px;
}

.reiseart-icon {
    width: 15px;
    height: 15px;
    color: var(--color-text-muted);
    vertical-align: -3px;
}

h2 .icon {
    width: 20px;
    height: 20px;
    vertical-align: -5px;
    margin-right: 0.3rem;
    color: var(--color-primary);
}

/* ---------- Sidebar: dashboard link + group icons ---------- */

.menu-dashboard-link {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    min-height: var(--hoehe-menuzeile);
    padding: 0.5rem 0.625rem;
    margin-bottom: 0;
    border-radius: var(--radius);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-sidebar-text);
    transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease);
}

.menu-dashboard-link:hover {
    background: var(--color-surface-alt);
    color: var(--color-sidebar-text-active);
}

/* DER AKTIVE PUNKT: blaue Flaeche, blaue Schrift, kein Balken am Rand. */
.menu-dashboard-link.active,
.menu-group li a.active {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

/* ═══════════════════════════════════════════════════════════════════════════
   DER AKTIVE PUNKT IM DUNKELMODUS: KRAEFTIGERE FLAECHE, HELLE SCHRIFT
   ═══════════════════════════════════════════════════════════════════════════
   Zwei Dinge stimmen dort nicht von selbst.

   DIE FLAECHE: --color-primary-light ist im dunklen Satz #17233d und liegt
   damit so dicht an der Leiste (#131a23), dass sie kaum zu sehen ist. Deshalb
   hier eine Auflage in derselben Farbe, nur kraeftiger.

   DIE SCHRIFT: --color-primary ist dort ein helles Blau (#6e90ff) und stand
   auf eben dieser blauen Auflage — blau auf blau. Der aktive Punkt war der
   einzige im Menue, den man SCHLECHTER las als seine Nachbarn, und das ist
   genau verkehrt. Im Dunkelmodus traegt er deshalb die helle Schriftfarbe der
   Leiste (--color-sidebar-text-active, #e8edf4): die Flaeche sagt "hier", die
   Schrift bleibt lesbar.

   In der HELLEN Ansicht bleibt es beim Blau — dort ist die Flaeche #e3e9fa und
   die blaue Schrift kommt darauf auf 7,1:1.

   Die GRUPPE zieht mit (sie traegt dieselbe Auskunft, siehe unten), sonst
   stuende ueber einem weissen Punkt ein blauer Gruppenkopf.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) .menu-group li a.active,
    :root:not([data-theme="light"]):not([data-theme="dark"]) .menu-dashboard-link.active {
        background: rgba(110, 144, 255, 0.22);
        color: var(--color-sidebar-text-active);
    }

    :root:not([data-theme="light"]):not([data-theme="dark"]) .menu-group.active > summary {
        color: var(--color-sidebar-text-active);
    }
}

:root[data-theme="dark"] .menu-group li a.active,
:root[data-theme="dark"] .menu-dashboard-link.active {
    background: rgba(110, 144, 255, 0.22);
    color: var(--color-sidebar-text-active);
}

:root[data-theme="dark"] .menu-group.active > summary {
    color: var(--color-sidebar-text-active);
}

/* DIE GRUPPE, IN DER MAN STEHT, BLEIBT MARKIERT.
   ---------------------------------------------------------------------------
   Wer einen Menuepunkt anwaehlt, sieht danach nur noch DIESEN Punkt blau — die
   Gruppe darueber sagte in derselben gedaempften Farbe wie alle anderen, wozu
   er gehoert. Bei neun Gruppen und ueber dreissig Punkten ist das die Frage,
   die man beim Hereinkommen zuerst hat: wo bin ich.

   Die Gruppe traegt deshalb dieselbe Farbe wie der aktive Punkt darin, und ihr
   Zeichen mit. Eine FLAECHE bekommt sie nicht: dann stuenden zwei blaue Kaesten
   uebereinander, und der aktive Punkt waere nicht mehr der auffaelligste.

   Die Klasse setzt layout.php ($groupActive), nicht das <details open> — eine
   Gruppe kann offen sein, ohne dass man in ihr steht. */
.menu-group.active > summary {
    color: var(--color-primary);
}

/* Und die Punkte DIESER Gruppe haengen sichtbar an ihr: eine feine Linie am
   linken Rand fuehrt vom Gruppenkopf zum aktiven Punkt. Sie ersetzt den
   3-px-Balken, den frueher der aktive Punkt selbst trug — der stand am Rand der
   Leiste und sagte nichts ueber die Zugehoerigkeit. */
.menu-group.active > ul {
    margin-left: 0.625rem;
    padding-left: 0.5rem;
    border-left: 2px solid var(--color-primary-soft);
}

.menu-group summary {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.menu-chevron {
    width: 14px;
    height: 14px;
    margin-left: auto;
    flex-shrink: 0;
    opacity: 0.6;
    transition: transform 0.15s ease;
}

.menu-group[open] > summary .menu-chevron {
    transform: rotate(90deg);
}

/* ---------- Collapsible sidebar (icon-only rail) ---------- */

html[data-sidebar="collapsed"] .sidebar {
    width: 64px;
}

html[data-sidebar="collapsed"] .sidebar-brand {
    justify-content: center;
    padding: 1.125rem 0 1rem;
}

html[data-sidebar="collapsed"] .sidebar-brand .brand-logo {
    display: none;
}

html[data-sidebar="collapsed"] .sidebar-toggle .icon {
    transform: rotate(180deg);
}

html[data-sidebar="collapsed"] .menu-label {
    display: none;
}

html[data-sidebar="collapsed"] .menu-dashboard-link,
html[data-sidebar="collapsed"] .menu-group summary {
    justify-content: center;
    gap: 0;
    padding-left: 0;
    padding-right: 0;
}

html[data-sidebar="collapsed"] .menu-group li a {
    justify-content: center;
    gap: 0;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
}

html[data-sidebar="collapsed"] .menu-chevron {
    display: none;
}

html[data-sidebar="collapsed"] .sidebar-footer {
    display: none;
}

/* Submenu becomes a flyout instead of pushing layout — the rail is too narrow
   to show group + children stacked. */
html[data-sidebar="collapsed"] .menu-group {
    position: relative;
}

html[data-sidebar="collapsed"] .menu-group[open] > ul {
    position: absolute;
    left: 64px;
    top: 0;
    min-width: 200px;
    background: var(--color-sidebar);
    border: 1px solid var(--color-border);
    border-left: 0;
    border-radius: 0 var(--radius) var(--radius) 0;
    box-shadow: var(--shadow-md);
    padding: 0.375rem;
    z-index: 40;
}

html[data-sidebar="collapsed"] .menu-group[open] > ul li a {
    justify-content: flex-start;
    gap: 0.625rem;
    padding: 0.5rem 0.625rem;
}

/* Die Linie am linken Rand der aktiven Gruppe gehoert ins ausgeklappte Menue.
   Im Ausklappfeld der schmalen Schiene steht die Gruppe ohnehin allein — dort
   waere sie eine Kante ohne Gegenueber und wuerde die Punkte verschieben. */
html[data-sidebar="collapsed"] .menu-group.active > ul {
    margin-left: 0;
    padding-left: 0.375rem;
    border-left: 0;
}

html[data-sidebar="collapsed"] .menu-group[open] > ul .menu-label {
    display: inline;
}

/* ---------- Stat tile icons + color coding ---------- */

.stat-tile-count .stat-icon,
.stat-tile-count .stat-value {
    color: var(--color-primary);
}

.stat-tile-total .stat-icon,
.stat-tile-total .stat-value {
    color: var(--color-accent2-text);
}

/* Bezahlt und Passagiere teilen sich die Farbe: KEINE neue fuer die
   Passagierkachel, sondern die vorhandene Erfolgsfarbe. Ein eigener
   Klassenname trotzdem, damit an der Kachel steht, was sie zaehlt. */
.stat-tile-paid .stat-icon,
.stat-tile-paid .stat-value,
.stat-tile-pax .stat-icon,
.stat-tile-pax .stat-value {
    color: var(--color-success-text);
}

.stat-tile-open .stat-icon,
.stat-tile-open .stat-value {
    color: var(--color-danger-text);
}

/* ---------- Row action (open icon) ---------- */

.row-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Ohne das sitzt der Knopf auf der Grundlinie der Zeile, und der Platz fuer
       Unterlaengen darunter macht die Tabellenzeile sieben Pixel hoeher, ohne
       dass etwas darin steht. */
    vertical-align: middle;
    /* 28 px waren es, solange die Zeilenhoehe an der Groesse dieses Knopfes
       hing. Sie steht jetzt am <tr> (--hoehe-tabellenzeile), also kostet der
       Knopf keine Zeilenhoehe mehr und darf die Groesse haben, die ein Ziel fuer
       die Maus braucht. */
    width: var(--hoehe-symbolknopf);
    height: var(--hoehe-symbolknopf);
    /* Wie jeder andere Knopf: der kraeftige Rahmen und der flache Schatten.
       Mit dem Trennlinien-Ton verschwand er zwischen den Zeilenlinien, an denen
       er steht. */
    border: 1px solid var(--color-border-strong);
    box-shadow: var(--shadow-sm);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-primary);
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.row-action:hover {
    background: var(--color-primary-light);
    border-color: var(--color-primary);
}

.row-action .icon {
    width: 18px;
    height: 18px;
    vertical-align: 0;
}

/* ---------- Agent form (read-only display) ---------- */

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1rem;
}

/* Mehrere .form-grid untereinander (z. B. die Zeilen der Reisedaten-Karte oder
   einer Leistung) sind eigene Grids — der interne gap wirkt zwischen ihnen nicht.
   Derselbe Abstand als margin, damit gestapelte Grids genauso aussehen wie die
   Zeilen innerhalb eines einzelnen Grids. */
.form-grid + .form-grid {
    margin-top: 1rem;
}

/* Ein Feld ueber zwei Rasterspalten — fuer Inhalte, die in ein Feld von 220px
   nicht passen: E-Mail-Adressen (Adresse & Kontakt bei Kunde, Agentur,
   Lieferant) sind regelmaessig 30 Zeichen und mehr.

   Die Regel steht unter einer Mindestbreite, weil .form-grid mit auto-fit
   arbeitet: passt nur EINE Spalte in den Container, waere `span 2` eine Spalte
   zu viel und legte eine implizite Spalte an — die Karte wuerde seitlich
   ueberlaufen. Ab 640px sind es immer mindestens zwei Spalten. */
@media (min-width: 640px) {
    .form-grid label.feld-breit {
        grid-column: span 2;
    }
}

.form-grid label {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* ═══════════════════════════════════════════════════════════════════════════
   KURZE FELDER BLEIBEN KURZ
   ═══════════════════════════════════════════════════════════════════════════
   In den Detailmasken war JEDES Textfeld so breit wie seine Rasterspalte —
   gemessen 287 px, ob darin ein Laenderkuerzel mit drei Zeichen stand oder eine
   Strasse. Das ist nicht nur unschoen: die Breite eines Feldes ist der erste
   Hinweis darauf, was hineingehoert, und wenn alle gleich breit sind, sagt
   dieser Hinweis nichts mehr. Man liest die Beschriftung, statt die Maske zu
   ueberfliegen.

   Die Marken dafuer gibt es schon — der Buchungsassistent setzt sie in seinem
   Anmelderblock (--feld-land, --feld-plz, --feld-telefon). Dieselben Felder
   waren dort also seit Langem richtig breit und in den Stammdatenmasken nicht.

   Die SPALTE bleibt, wie sie ist: begrenzt wird nur das Feld darin. Damit
   stehen die Beschriftungen weiter in einem Raster, und aus der Maske wird kein
   Flickenteppich verschieden breiter Spalten.
   ═══════════════════════════════════════════════════════════════════════════ */
.form-grid .feld-kurz input,
.form-grid .feld-kurz select {
    /* Laenderkuerzel, PLZ, Kuerzel, MwSt-Satz, Kategorie — bis etwa sechs Zeichen. */
    max-width: var(--feld-plz);
}

.form-grid .feld-mittel input,
.form-grid .feld-mittel select {
    /* Suchcode, Telefonnummer, Debitor-, Steuer-, Pass- und Ausweisnummer. */
    max-width: var(--feld-telefon);
}

.form-grid input:not([type="checkbox"]):not([type="radio"]),
.form-grid select,
.form-grid textarea,
/* .edit-row td selbst nutzt var(--color-bg) als Hintergrund (siehe unten) —
   die Eingabefelder darin brauchen deshalb var(--color-surface) (wie die
   Suchbox-Card), sonst verschwimmen Feld und Zeilenhintergrund zur exakt
   gleichen Farbe und das Feld wirkt nicht wie editierbar. */
.inline-edit-form input:not([type="checkbox"]):not([type="radio"]),
.inline-edit-form select {
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: 0.9rem;
    font-family: inherit;
    background: var(--color-surface);
    color: var(--color-text);
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

/* EINE Feldhoehe fuer alle Eingabefelder einer Feldreihe.
   ---------------------------------------------------------------------------
   Ohne sie ist jedes Feld so hoch, wie sein Inhalt es macht, und die drei
   Bauarten sind es unterschiedlich: ein <select> traegt sein Pfeilchen, ein
   <input type="date"> das Kalendersymbol und die Ziffernblaettchen, ein
   Textfeld nur eine Zeile. Bei gleichem padding kamen dabei 33 bis 36 Pixel
   heraus — nebeneinander sichtbar als Kanten, die nicht stimmen (aufgefallen
   an der PNR zwischen zwei Auswahllisten und zwei Datumsfeldern).

   Vorher fiel es nicht auf, weil die Feldreihen RASTER waren: dort streckt
   sich jedes Label auf die Zeilenhoehe und die Unterschiede lagen unter der
   gemeinsamen Unterkante. Seit die langen Zeilen Flexzeilen sind, ist jedes
   Label nur so hoch wie sein Feld — und der Unterschied steht frei.

   Die Hoehe kommt aus --hoehe-feld und steht nicht mehr hier: ein Feld und der
   Knopf daneben muessen gleich hoch sein, und das laesst sich nur an EINER
   Stelle sicherstellen.

   TEXTAREA bleibt aussen vor — ihre Hoehe kommt aus rows. */
.form-grid input:not([type="checkbox"]):not([type="radio"]),
.form-grid select,
.inline-edit-form input:not([type="checkbox"]):not([type="radio"]),
.inline-edit-form select {
    height: var(--hoehe-feld);
}

.form-grid input[readonly] {
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    cursor: not-allowed;
}

/* ---------- Mail-Compose-Formular (Kunde per Mail kontaktieren) ---------- */

.mail-compose-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-width: 640px;
}

.mail-compose-form label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.mail-compose-form input,
.mail-compose-form textarea {
    font-size: 0.95rem;
    font-family: inherit;
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

.mail-compose-form input:disabled {
    background: var(--color-bg);
    color: var(--color-text-muted);
}

.mail-compose-form textarea {
    resize: vertical;
    line-height: 1.5;
}

.mail-compose-form button {
    align-self: flex-start;
    margin-top: 0.25rem;
    padding: 0.6rem 1.25rem;
    border: none;
    border-radius: var(--radius);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    font-size: 0.95rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.mail-compose-form button:hover {
    background: var(--color-primary-hover);
}

.mail-compose-form button:active {
    transform: scale(0.98);
}

/* ---------- Pagination ---------- */

.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    margin: -0.5rem 0 1.5rem;
}

/* Kleine Nebentexte — Trefferzahl, Seitenangabe, Untertitel eines Kopfes.
   Dreimal derselbe Rumpf; sie sollen auch gleich aussehen. */
.pagination-count,
.pagination-info,
.detail-header-sub {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.pagination-nav {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-left: auto;
}

.pagination a,
.pagination-disabled {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--hoehe-symbolknopf);
    height: var(--hoehe-symbolknopf);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.pagination-disabled {
    opacity: 0.35;
}

.pagination a:hover {
    background: var(--color-primary-light);
    border-color: var(--color-primary);
}


/* ---------- Utility ---------- */

/* !important: this utility class must win over more specific contextual rules
   like ".data-table th/td { text-align: left }" (class+type beats a bare
   class), which would otherwise always override it regardless of source order. */
.text-right {
    text-align: right !important;
}

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

/* ---------- List toolbar / export button ---------- */

/* WERKZEUGLEISTE ueber einer Liste (Hinzufuegen, Export, Spalten).

   Der obere Abstand war -0.75rem, also NEGATIV: die Leiste wurde absichtlich an
   die Suchleiste herangezogen. Zusammen mit dem unteren Abstand der Suchleiste
   (12 px) blieb dazwischen genau NICHTS, und die Knoepfe klebten an der Karte.
   Das galt in jeder Liste der Anwendung — Verwaltung, Stammdaten, Buchhaltung.

   Jetzt beidseitig ein Rasterschritt: 16 px Luft nach oben zur Suchleiste und
   16 px nach unten zur Tabelle. */
.list-toolbar {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
    margin: var(--space-4) 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   WHATSAPP-DIALOG: Vorschau und Kopierknoepfe
   ═══════════════════════════════════════════════════════════════════════════ */

/* Beschriftung und Kopierknopf in einer Zeile ueber dem Feld. */
.wa-feld-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
}

.wa-kopieren {
    border: 0;
    background: none;
    padding: 0;
    color: var(--color-primary);
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
}

.wa-kopieren:hover {
    text-decoration: underline;
}

/* Der Knopf, der WhatsApp oeffnet — in dessen Gruen.

   Die Anwendung faerbt ihre primaeren Knoepfe blau; dieser hier fuehrt aber aus
   ihr HINAUS. Dieselbe Ueberlegung wie bei der Vorschaublase: was WhatsApp ist,
   sieht aus wie WhatsApp.

   Die Farben sind fest und folgen NICHT den Marken der Anwendung — sie sind in
   beiden Ansichten dieselben, weil sie nicht zur Oberflaeche gehoeren, sondern
   zu einem fremden Dienst. Weisse Schrift auf #25d366 ergibt 2,5:1 und waere zu
   wenig; #128c7e (das dunklere Gruen der Marke) kommt auf 4,6:1. */
.button-primary.button-whatsapp {
    background: var(--color-whatsapp);
    border-color: var(--color-whatsapp);
}

.button-primary.button-whatsapp:hover {
    background: var(--color-whatsapp-hover);
    border-color: var(--color-whatsapp-hover);
}

/* DERSELBE KNOPF WIE "WhatsApp oeffnen" IM SENDEDIALOG — gefuellt, weisse
   Schrift. Er steht zwar in einer Reihe mit "Download" und "E-Mail" und ist
   ihnen gleichrangig; entscheidend ist aber, dass beide WhatsApp-Knoepfe der
   Anwendung gleich aussehen: sie fuehren zum selben Weg, und derselbe Weg soll
   nicht an zwei Stellen zwei Farben haben.

   Die Auswahl nennt beide Klassen, weil .export-button sonst mit seinem hellen
   Grund gewinnt — gleiche Staerke, spaeter in der Datei. Dieselbe Stelle wie
   bei .export-button.button-danger-fill darueber. */
.export-button.button-whatsapp {
    background: var(--color-whatsapp);
    border-color: var(--color-whatsapp);
    color: #fff;
}

.export-button.button-whatsapp:hover {
    background: var(--color-whatsapp-hover);
    border-color: var(--color-whatsapp-hover);
    color: #fff;
}


/* Textfeld links, Vorschau rechts. auto-fit mit Mindestbreite: passt beides
   nebeneinander, steht es nebeneinander; sonst untereinander — ohne dass dafuer
   eine Bruchstelle als Pixelzahl gepflegt werden muss. */
.wa-schreiben {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--space-4);
    align-items: stretch;
    margin-top: var(--space-4);
}

/* Beide Spalten sind Flexspalten, damit Textfeld und Blase die volle Hoehe der
   Reihe fuellen und unten auf gleicher Kante enden. */
.wa-textfeld,
.wa-vorschau {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

.wa-textfeld textarea {
    flex: 1 1 auto;
    resize: vertical;
}

/* Die Nachricht, wie sie im Gespraech ankommt: eine Sprechblase, an der Seite
   des Absenders (rechts) und in Gruen — die Farben von WhatsApp, nicht die der
   Anwendung, denn genau dieser Eindruck soll geprueft werden.

   pre-wrap haelt die Zeilenumbrueche des Textfeldes; ohne das stuende die
   ganze Nachricht in einem Absatz. */
.wa-blase {
    /* In der eigenen Spalte braucht die Blase keine Ausrichtung mehr: sie
       fuellt sie. Vorher stand sie mit `margin-left: auto` rechts unter dem
       Textfeld, wie im Gespraech. */
    flex: 1 1 auto;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-lg);
    border-bottom-right-radius: var(--radius-sm);
    background: #d9fdd3;
    color: #111b21;
    font-size: 0.88rem;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Im Dunkelmodus bleibt die Blase in ihren Farben — sie zeigt WhatsApp, nicht
   diese Anwendung. Nur der Rahmen tritt zurueck, damit sie nicht leuchtet. */
:root[data-theme="dark"] .wa-blase {
    background: #005c4b;
    color: #e9edef;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) .wa-blase {
        background: #005c4b;
        color: #e9edef;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   HOVERANZEIGE ÜBER EINER BUCHUNGSNUMMER (partials/buchung-vorschau.php)
   ═══════════════════════════════════════════════════════════════════════════
   Eine schwebende Karte, kein Tooltip des Browsers: sie traegt eine Tabelle
   (Leistungen) und eine Liste (Reisende), und der Browser kann in einem `title`
   nur eine Zeile Text.

   position: absolute mit Seitenkoordinaten (nicht fixed): so wandert sie beim
   Rollen nicht ueber den Bildschirm — das Skript schliesst sie ohnehin, sobald
   sich die Seite bewegt.

   pointer-events: none ist wesentlich. Die Karte erscheint UNTER dem Zeiger;
   koennte sie Mausereignisse annehmen, loeste sie im Moment des Erscheinens ein
   mouseout auf der Nummer aus, verschwaende wieder, das mouseover kaeme erneut —
   ein Flackern, das sich nicht von selbst beruhigt.
   ═══════════════════════════════════════════════════════════════════════════ */
.bv-blase {
    position: absolute;
    z-index: 80;
    pointer-events: none;
    /* FESTE Breite, nicht max-content.
       max-content war der Grund, warum die drei Kacheln untereinander standen:
       das Raster darin arbeitet mit `repeat(auto-fit, minmax(11rem, 1fr))`, und
       fuer 1fr braucht es eine BEKANNTE Breite. Bei max-content bestimmt der
       Inhalt die Breite und die Breite den Inhalt — der Browser loest das auf,
       indem er eine Spalte nimmt. Mit einer gesetzten Breite entstehen drei. */
    /* 54rem statt 46: die Zahlungsdaten tragen sechs Zeilen mit Beschriftungen
       wie "Restzahlung fällig" und einem Betrag dahinter — bei 46rem stand die
       Beschriftung an der Zahl. */
    width: min(54rem, calc(100vw - 2rem));
    padding: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    font-size: 0.82rem;
    color: var(--color-text);
}

.bv-kopf {
    font-weight: 700;
    font-size: 0.95rem;
    font-variant-numeric: tabular-nums;
    padding-bottom: var(--space-2);
    margin-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

/* Die drei Angabenbloecke (Reisedaten, Zahlungsdaten, Kontakt) NEBENEINANDER,
   die beiden Tabellen darunter ueber die ganze Breite — dieselbe Ordnung wie im
   Buchungsdetail, nur kleiner. auto-fit statt fester Spaltenzahl: fehlt ein
   Block (eine Buchung ohne Anschrift), teilen sich die uebrigen den Platz. */
.bv-koerper {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* DIE DREI KACHELN TEILEN SICH DIE BREITE NACH IHREM INHALT.

   Flex und nicht Raster: ein Raster mit `repeat(3, 1fr)` gibt jeder Kachel
   genau ein Drittel, egal was darin steht. Die Zahlungsdaten tragen sechs
   Zeilen mit langen Beschriftungen ("Restzahlung fällig") und einem Betrag
   dahinter, die Kontaktdaten oft nur einen Namen — im Drittel brach die eine
   um, waehrend neben der anderen Platz frei blieb.

   `flex: 1 1 auto` heisst: Ausgangsbreite ist der INHALT, und was uebrig
   bleibt, wird verteilt. Damit bekommt die volle Kachel mehr als die leere.

   align-items: stretch (Vorgabe) haelt sie gleich hoch — ohne das waere die
   Reihe eine Treppe. */
.bv-kacheln {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: stretch;
}

.bv-kacheln > .bv-block {
    flex: 1 1 auto;
    min-width: 0;
}

/* Die drei Angabenbloecke sind KACHELN: eigener Grund, feiner Rahmen, Radius —
   dieselbe Bauform wie die Kennzahlkacheln der Listen, nur kleiner. In einer
   Blase ohne Rahmen liefen die drei Bloecke optisch ineinander, und man musste
   an den Ueberschriften abzaehlen, wo einer aufhoert.

   --color-bg als Grund und nicht surface: die Blase SELBST ist schon eine weisse
   Karte; eine weisse Kachel darin waere unsichtbar. */
.bv-kacheln > .bv-block {
    padding: var(--space-3);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

/* Die beiden Tabellen stehen unter den Kacheln, ueber die volle Breite und ohne
   Kachelform — sie tragen ihre eigene Ordnung (Kopfzeile, Trennlinien). Sie sind
   Kinder von .bv-koerper (der Flexspalte), nicht von .bv-kacheln. */

.bv-titel {
    margin: 0 0 var(--space-2);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

/* Beschriftung und Wert je Zeile.

   DIE SPALTEN SIND HERUM: der WERT bekommt `auto` und damit genau die Breite,
   die er braucht; die Beschriftung nimmt den Rest (minmax(0, 1fr)).

   Vorher war es umgekehrt (auto 1fr). Eine lange Beschriftung wie "Restzahlung
   faellig" nahm sich damit die ganze Kachel, fuer den Wert blieb nichts, und da
   Betraege nicht umbrechen duerfen, standen sie ueber dem Rand der Kachel — im
   Bild als "410" statt "410,00" und "28.08.20" statt des vollen Datums.

   minmax(0, 1fr) und nicht 1fr: ohne die Null als Untergrenze waere die
   Mindestbreite der Spalte der laengste Text darin, und die Kachel wuerde
   wieder ueberlaufen statt die Beschriftung umbrechen zu lassen.

   gap: 0.1rem senkrecht, weil die allgemeine dl-Regel 0.5rem setzt und die
   Zeilen hier eng stehen sollen. */
.bv-paare {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0.1rem var(--space-3);
    margin: 0;
}

.bv-paare dt {
    color: var(--color-text-muted);
    /* DARF umbrechen — lieber eine Beschriftung in zwei Zeilen als ein
       abgeschnittener Betrag. */
    min-width: 0;
}

.bv-paare dd {
    margin: 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
    /* Ein Betrag oder ein Datum bricht NIE. */
    white-space: nowrap;
}

.bv-anschrift {
    margin: 0;
    line-height: 1.5;
}

/* Tabelle im Stil der Listen, nur knapper: dieselbe Kopfzeile in Grossbuchstaben
   und dieselben feinen Trennlinien, aber ohne die Zeilenhoehe der Arbeitslisten
   — in einer Blase zaehlt jede Zeile doppelt. */
.bv-tabelle {
    width: 100%;
    border-collapse: collapse;
}

.bv-tabelle th {
    text-align: left;
    padding: 0.15rem var(--space-2) 0.15rem 0;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.bv-tabelle td {
    padding: 0.2rem var(--space-2) 0.2rem 0;
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.bv-tabelle tr:last-child td {
    border-bottom: 0;
}

.bv-tabelle .text-right {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.bv-leer {
    margin: 0;
    color: var(--color-text-muted);
}

/* Die Nummer zeigt, dass an ihr etwas haengt.

   `zoom-in` (Lupe) und nicht `help` (Fragezeichen): das Fragezeichen steht in
   der ganzen Anwendung fuer Hilfe zur Bedienung — das Handbuch, die
   Kontexthilfe in der Kopfzeile. Hier wird nichts erklaert, sondern etwas
   GEZEIGT, das sonst hinter einem Klick liegt. Auch kein `pointer`: die Hand
   verspricht einen Klick, und die Nummer ist kein Verweis. */
.number-badge[data-buchung] {
    cursor: zoom-in;
}

/* Auf der Startseite IST die Nummer der Weg in die Buchung — dort gibt es keine
   eigene Aktionsspalte mehr, die Marke selbst ist der Verweis. Dann zeigt der
   Zeiger auch das an: die Lupe daruber gehoert zur Hovervorschau, die es
   weiterhin gibt, aber ein Verweis ist mehr als eine Vorschau.
   (a { text-decoration: none } gilt global, eine Unterstreichung entsteht
   also nicht.) */
a.number-badge[data-buchung] {
    cursor: pointer;
}

/* Beim Ueberfahren ein Ring in der Markenfarbe, KEINE gefuellte Flaeche mit
   weisser Schrift: im dunklen Modus ist --color-primary ein helles Blau
   (#6e90ff), und Weiss darauf kaeme auf rund 2,3:1. Der Ring liest sich in
   beiden Modi gleich und laesst Schrift- und Grundfarbe der Marke, wie sie
   sind. */
a.number-badge[data-buchung]:hover {
    box-shadow: inset 0 0 0 1px var(--color-primary);
}

/* REISEART MIT SYMBOL: Zeichen und Wort bleiben zusammen.

   Die Zelle traegt "<Symbol> PAUSCHAL". Wird die Spalte eng, brach sie zwischen
   beiden um — das Symbol stand allein in der ersten Zeile, das Wort darunter,
   und die ganze Tabellenzeile wurde zweizeilig. Zusammen gelesen ergeben sie
   eine Angabe, getrennt sehen sie aus wie zwei.

   inline-flex statt nur `nowrap`: damit sitzt das Symbol auf der Mitte des
   Wortes statt auf der Grundlinie, und der Abstand ist ein gesetzter Wert und
   kein Leerzeichen aus der Vorlage.
   ───────────────────────────────────────────────────────────────────────── */
.data-table td.zell-reiseart {
    white-space: nowrap;
}

.data-table td.zell-reiseart > .icon {
    vertical-align: -0.15em;
    margin-right: 0.15rem;
}

/* Spalte ohne Zeilenumbruch. Muss `.data-table th` uebertreffen, das dort
   `white-space: pre-line` setzt (damit "(EUR)" in die zweite Zeile rutscht) —
   deshalb mit Elementname davor, sonst gewinnt die allgemeinere Regel. */
.data-table th.spalte-eng,
.data-table td.spalte-eng {
    white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────────────────
   ZUSAMMENFASSUNG IM AVIS-DIALOG
   Beschriftung links, Wert rechts am Dialogrand, Trennlinie dazwischen. Die
   Werte stehen so in einer Spalte untereinander und lassen sich vergleichen;
   tabular-nums haelt die Ziffern auf gleicher Breite, damit die Kommas
   uebereinander liegen.
   ───────────────────────────────────────────────────────────────────────── */
.avis-zusammenfassung {
    display: grid;
    grid-template-columns: 1fr auto;
    /* gap AUSDRUECKLICH auf 0: die allgemeine dl-Regel setzt 0.5rem 1rem, und
       der Spaltenabstand riss die Trennlinie in zwei Stuecke mit einer Luecke
       vor dem Wert. Der Abstand kommt hier aus dem Innenabstand der Zellen. */
    gap: 0;
    margin: 0;
}

.avis-zusammenfassung dt,
.avis-zusammenfassung dd {
    margin: 0;
    padding: 0.6rem 0;
    border-top: 1px solid var(--color-border);
}

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

.avis-zusammenfassung dd {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* Erste Zeile ohne Linie — darueber steht schon die Trennlinie der Kopfzeile. */
.avis-zusammenfassung dt:first-of-type,
.avis-zusammenfassung dt:first-of-type + dd {
    border-top: 0;
}

/* Offene Summe: der Betrag, um den es in dieser AVIS geht. */
.avis-zusammenfassung .az-offen {
    color: var(--color-danger-text);
}

/* ═══════════════════════════════════════════════════════════════════════════
   KONTOAUSZUG — die Kopfzahlen des Kontenblatts
   ═══════════════════════════════════════════════════════════════════════════
   EINE Karte mit zwei Gruppen statt fuenf gleich aussehender Kacheln (die bei
   fuenf Stueck auf 4 + 1 umbrachen). Links die Rechnung des Zeitraums mit
   "−" und "=" dazwischen, rechts der Kontostand mit einem Pfeil von Anfang zu
   Ende — der Pfeil ist ABSICHTLICH kein Gleichheitszeichen: die beiden Werte
   kommen aus kasse.BESTAND und folgen nur dem Datum, nicht den uebrigen
   Filtern (siehe den Kommentar in der Vorlage).
   ═══════════════════════════════════════════════════════════════════════════ */
.kontoauszug {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--space-6) var(--space-8);
    padding: var(--space-4) var(--space-6);
}

.ka-gruppe {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Die zweite Gruppe (Kontostand) sitzt rechts und traegt links eine Linie —
   sie ist die Trennung, die vorher der Zwischenraum zwischen zwei Kacheln war.
   margin-left: auto schiebt sie an den rechten Rand, solange Platz ist; bricht
   die Karte um, steht sie darunter und die Linie verschwindet. */
.ka-gruppe-bestand {
    margin-left: auto;
    padding-left: var(--space-8);
    border-left: 1px solid var(--color-border);
}

@media (max-width: 1100px) {
    .ka-gruppe-bestand {
        margin-left: 0;
        padding-left: 0;
        border-left: 0;
    }
}

.ka-gruppe-titel {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

/**
 * Das Fragezeichen zum Kontostand. Die Blase kommt aus [data-hinweis] (siehe
 * Kopfzeile der Anwendung) und ist hier BREIT und mehrzeilig, weil der Satz lang
 * ist.
 *
 * SIE HAENGT RECHTS, wie in der Kopfzeile. Vorher stand hier `left: 0`, damit
 * sie nach rechts aufklappt — und genau das machte die KONTENBLATTSEITE
 * WAAGERECHT ROLLBAR: das Fragezeichen sitzt am rechten Rand seiner Karte, die
 * 352 px breite Blase lief darueber hinaus, und der Ueberlauf eines absolut
 * gesetzten Elements vergroessert den Rollbereich der ganzen Seite. Gemessen bei
 * 1600 px Fenster: Seite 1725 px breit; bei 1280: 1405. Unter 1100 px fiel es
 * nicht auf, weil die Gruppe dort unter die Rechnung rutscht.
 *
 * Nach links ist Platz: das Zeichen steht rund 700 px vom linken Kartenrand
 * entfernt.
 */
.ka-hinweis {
    display: inline-flex;
    color: var(--color-text-subtle);
    cursor: help;
}

.ka-hinweis .icon {
    width: 15px;
    height: 15px;
}

.ka-hinweis::after {
    width: 22rem;
    white-space: normal;
}

.ka-rechnung {
    display: flex;
    align-items: baseline;
    gap: var(--space-4);
}

.ka-posten {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.ka-label {
    font-size: 0.78rem;
    color: var(--color-text-muted);
    white-space: pre-line;
}

.ka-wert {
    font-size: 1.15rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

/* Das ERGEBNIS der Rechnung (Saldo, Endbestand) groesser: es ist die Zahl, um
   die es geht, die anderen sind ihre Bestandteile. */
.ka-wert-gross {
    font-size: 1.45rem;
    color: var(--color-primary);
}

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

/* Rechenzeichen zwischen den Posten: auf Hoehe der ZAHLEN, nicht der
   Beschriftungen — deshalb ein eigener oberer Abstand, der die Zeile der
   Beschriftung ueberspringt. */
.ka-op {
    align-self: end;
    padding-bottom: 0.1rem;
    font-size: 1.1rem;
    color: var(--color-text-subtle);
}

.ka-op-pfeil {
    font-size: 1rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ZWEI BESCHRIFTUNGEN IN EINEM SPALTENKOPF
   ═══════════════════════════════════════════════════════════════════════════
   "Vorgang · Beleg" und "Konto · G-Konto": die Zelle darunter zeigt beide
   Werte untereinander, sortieren laesst sich nach jedem einzeln. Vorher standen
   auch die Beschriftungen untereinander (<br> plus kleinere zweite Zeile) —
   der Kopf war dadurch rund 150 px hoch.

   DER UMBRUCH IST HIER ZWEISTUFIG, und das ist der Kern:

   Die einzelne Beschriftung darf NIE brechen — "G-Konto" zerfiel sonst in "G-"
   und "KONTO", weil ein Bindestrich eine erlaubte Bruchstelle ist. Das nowrap
   muss am SORTIER-LINK stehen und nicht nur am <th>: der Link bringt aus
   `.sort-kopf` sein eigenes `white-space: pre-line` mit (das braucht er, damit
   in den Geldspalten "(EUR)" in die zweite Zeile rutscht), und damit war der
   Bruch innerhalb des Wortes wieder erlaubt, obwohl die Zelle nowrap trug.

   Das PAAR darf brechen, aber nur am Mittelpunkt: reicht die Breite nicht,
   steht "Konto ·" oben und "G-Konto" darunter — zwei ganze Woerter statt eines
   zerschnittenen. Deshalb `normal` an der Zelle und `nowrap` an den Links.

   In einer Paarspalte kommt kein "(EUR)" vor, also geht dem Link durch das
   nowrap nichts verloren.
   ═══════════════════════════════════════════════════════════════════════════ */
.data-table th.kopf-paar {
    white-space: normal;
}

.data-table th.kopf-paar .sort-kopf {
    white-space: nowrap;
}

.kopf-trenner {
    margin: 0 0.15rem;
    color: var(--color-text-subtle);
}

/* ---------- Kontenblatt: Kontenliste links, Kontobewegungen rechts ---------- */

/* Zwei Spalten (Konten | Kontenblatt) und zwei Zeilen (Suchen | Inhalt).
   Als Raster statt als Flexzeile, damit die beiden OBEREN Kaesten — die
   Kontensuche links und die Filterbox rechts — dieselbe Hoehe bekommen. Als
   Flexzeile war jeder Kasten so hoch wie sein eigener Inhalt, und die
   Filterbox mit ihren sechs Feldern stand deutlich tiefer als die Suchbox mit
   ihrem einen. */
.kontenblatt-layout {
    display: grid;
    /* Zwei Spalten, aber die LINKE laeuft ueber beide Zeilen: die Kontenliste
       ist EIN Kasten von oben bis unten. Vorher waren es zwei Rasterzeilen
       ("suche" ueber "konten"), weil links eine eigene Suchkarte stand — die ist
       jetzt der Kopf der Liste.

       240 px, dieselbe Breite wie die Menueleiste. Vorher 260 fuer die Liste
       PLUS eine zweite Karte darueber; die gesparte Hoehe und die zwanzig Pixel
       gehen an die Filterleiste, deren Auswahlfelder ("Alle Gegenkonten", "Alle
       Mitarbeiter") vorher abgeschnitten waren. */
    grid-template-columns: var(--breite-sidebar) minmax(0, 1fr);
    grid-template-areas:
        'konten filter'
        'konten ledger';
    align-items: start;
    gap: var(--space-6);
}

.kontenblatt-konten {
    grid-area: konten;
}

.kontenblatt-filter {
    grid-area: filter;
}

.kontenblatt-ledger {
    grid-area: ledger;
    min-width: 0;
}

.kontenblatt-filter .search-form {
    margin-bottom: 0;
}

/* ─────────────────────────────────────────────────────────────────────────
   KONTENLISTE als eine Karte: Filterfeld im Kopf, Liste darunter
   ─────────────────────────────────────────────────────────────────────────
   Der Rahmen sitzt an der KARTE, nicht mehr an der Liste — sonst waeren es
   zwei Rahmen ineinander. Die Liste selbst rollt (max-height am <ul>), das
   Filterfeld bleibt dabei stehen.
   ───────────────────────────────────────────────────────────────────────── */
.konten-karte {
    display: flex;
    flex-direction: column;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

/* Kasten um Lupe und Feld. Dieselbe Bauform wie die Suche im Handbuch: das
   Zeichen sitzt IM Feld (position: absolute), das Feld traegt links Platz
   dafuer. Kein Knopf daneben — die Eingabetaste schickt das Formular ab, und
   ein zweiter "Suchen"-Knopf direkt neben dem der Filterleiste war genau die
   Verdopplung, die die Seite ueberfuellt hat. */
.konten-filterfeld {
    position: relative;
    display: flex;
    padding: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

.konten-filterfeld .icon {
    position: absolute;
    left: calc(var(--space-3) + 0.6rem);
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--color-text-subtle);
    pointer-events: none;
}

/* Das Polster fuer die Lupe steht NICHT hier, sondern hinter dem gemeinsamen
   Block ("Felder mit einem Zeichen darin") — der setzt das Polster und steht
   spaeter in der Datei. */
.konten-filterfeld input {
    width: 100%;
    min-width: 0;
    height: var(--hoehe-feld);
    font-family: inherit;
    font-size: 0.9rem;
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

/* Das Kreuz, mit dem Chromium ein type="search" ausraeumt, sitzt sonst am
   rechten Rand ueber dem Text und bringt eine eigene Groesse mit. */
.konten-filterfeld input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.kontenblatt-account-list {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 640px;
    overflow-y: auto;
    overflow-x: hidden;
}

.kontenblatt-account-list li a {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.65rem 0.9rem;
    color: var(--color-text);
    text-decoration: none;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.9rem;
    transition: background-color var(--duration) var(--ease);
}

.kontenblatt-account-list li:last-child a {
    border-bottom: none;
}

.kontenblatt-account-list li a:hover {
    background: var(--color-primary-soft);
}

.kontenblatt-account-list li a.active {
    background: var(--color-primary-soft);
    color: var(--color-primary);
    font-weight: 600;
}

.kontenblatt-account-list .konto-nummer {
    flex-shrink: 0;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.kontenblatt-account-empty {
    padding: 0.85rem 0.9rem;
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

/* Untereinander schon bei 1100 px und nicht erst bei 768: mit der 240 px
   breiten Kontenliste daneben blieben fuer Filterleiste, Kennzahlen, fuenf
   Reiter und eine Tabelle mit acht Spalten bei 900 px Fensterbreite noch
   332 px — gemessen. Das ist keine schmale Ansicht mehr, das ist keine. */
@media (max-width: 1100px) {
    .kontenblatt-layout {
        grid-template-columns: minmax(0, 1fr);
        /* Auf schmalem Schirm untereinander: Konten, Filter, Kontenblatt. Der
           Bereich 'suche' ist weg — die Kontensuche ist Teil der Kontenkarte. */
        grid-template-areas:
            'konten'
            'filter'
            'ledger';
    }

    .kontenblatt-account-list {
        max-height: 320px;
    }
}

/* CRS-Übernahme: links Grid, rechts Detail-/INHALT-Block der ausgewählten Zeile. */
.crs-layout {
    display: flex;
    align-items: flex-start;
    gap: 1.5rem;
}

/* HALBE UND HALBE. Die Liste hatte 750 px als Ausgangsbreite (flex-basis) und
   die Vorgangskarte nur ihren Inhalt — geteilt wurde also nur, was darueber
   hinaus da war, und die Liste blieb immer die breitere. Auf einem 1920er
   Schirm standen 1100 px Liste neben 600 px Karte, obwohl rechts der Rohtext
   eines Vorgangs steht und links acht schmale Spalten.

   `flex: … 1 0` bei beiden heisst: die Ausgangsbreite ist fuer beide null, und
   der ganze Platz wird nach dem ersten Wert verteilt — unabhaengig vom Inhalt,
   in jeder Fensterbreite.

   ───────────────────────────────────────────────────────────────────────────
   DREI ZU ZWEI UND NICHT HALBE-HALBE
   ───────────────────────────────────────────────────────────────────────────
   Halbe-halbe war zu wenig fuer die Liste. Ihre Tabelle braucht 44rem (704 px),
   damit Kanal, Datum, Name, PNR und Agentur nebeneinander stehen — dazu kommen
   rechts die beiden Knoepfe. Gemessen bei 1500 px Fensterbreite: die Liste bekam
   579 px, die Tabelle wollte 704. Die 125 px Unterschied waren genau die
   Knopfspalte: sie stand hinter der Kante und war nur ueber das waagerechte
   Rollen zu erreichen.

   Mit 1.6 zu 1 bekommt die Liste dort 737 px und die Karte 461 — die Knoepfe
   sind sichtbar, und rechts bleibt genug fuer den Rohtext eines Vorgangs, der
   ohnehin in seinem eigenen Kasten rollt.

   Das Rollen bleibt als Rueckhalt: bei einem noch schmaleren Fenster (oder
   einer Spalte mehr) faengt es den Rest ab, statt eine Spalte umbrechen zu
   lassen. */
.crs-grid {
    flex: 1.6 1 0;
    min-width: 0;
}

.crs-detail {
    flex: 1 1 0;
    min-width: 0;
}

/* DIE LISTE ROLLT WAAGERECHT, statt ihre Spalten umbrechen zu lassen.

   Ohne Mindestbreite verteilt der Browser die halbe Fensterbreite auf acht
   Spalten und bricht dort um, wo es am billigsten ist — aus "TKCONNECT" wurden
   zwei Zeilen ("TKCONNE" / "CT"), und ein Kanalname, der mitten im Wort
   umbricht, ist keiner mehr. Mit der Marke bleiben die Spalten stehen und der
   Kasten darum rollt (.table-scroll bringt das overflow-x mit).

   44rem: gemessen die Breite, ab der Kanal, Datum, Name, PNR und Agentur
   nebeneinander stehen, ohne dass eine Spalte umbricht. */
.crs-grid .data-table {
    min-width: 44rem;
}

/* Die rechte Seite BLEIBT STEHEN, waehrend die Liste laeuft.
   ─────────────────────────────────────────────────────────────────────────────
   Beim Blaettern durch eine lange Liste stand der Vorgang vorher oben und war
   nach drei Zeilen aus dem Bild — man scrollte hinunter, klickte eine Zeile und
   musste zum Lesen wieder hinauf. Mit `sticky` folgt die Karte mit.

   `top: 1rem`: die Kopfzeile dieser Anwendung scrollt selbst weg (position
   static), es ist also kein Platz fuer eine feste Leiste freizuhalten — der
   Abstand ist nur damit die Karte nicht am Fensterrand klebt.

   Die Hoehe ist begrenzt und die Karte rollt INNEN: der Inhalt eines Vorgangs
   ist ein Rohtext, ein SABRE-MIR bringt zweitausend Zeichen mit. Ohne die
   Grenze waere die Karte hoeher als das Fenster, und `sticky` haette nichts zu
   halten — sie waere einfach mitgescrollt. */
.crs-detail {
    /* Breite: siehe .crs-grid, .crs-detail weiter oben — beide je die Haelfte. */
    padding: 1rem 1.25rem;
    position: sticky;
    top: 1rem;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
}

/* Kopf der Auswertung (Vorgangsnummer, Anzahl Passagiere, Anzahl Fluege) —
   dieselben Felder wie oben in der Karte, nur etwas gedraengter: darunter
   stehen zwei Tabellen, und der Reiter soll ohne Rollen lesbar bleiben. */
.crs-auswertung-kopf {
    margin: 0.9rem 0 0.25rem;
}

/* Die zwei Tabellen der Auswertung stehen in einer schmalen Karte: kleinere
   Schrift und engere Zellen, damit acht Flugspalten hineinpassen, ohne dass
   die Karte seitlich rollen muss. */
.crs-auswertung-tabelle {
    font-size: 0.82rem;
}

.crs-auswertung-tabelle td {
    padding: 0.35rem 0.4rem;
    /* Die WERTE sind kurz (Kuerzel, Datum, Uhrzeit) und sollen nicht umbrechen —
       ein "18.09." in einer Zeile und "2026" in der naechsten liest niemand. */
    white-space: nowrap;
}

/* Die BESCHRIFTUNGEN dagegen duerfen umbrechen: "Gesellschaft" und
   "Ticketnummer" sind laenger als ihre Werte, und in der schmalen Karte
   sprengten acht Spalten mit nowrap die Breite — die letzte Spalte stand
   ausserhalb und war nur durch seitliches Rollen zu erreichen. */
.crs-auswertung-tabelle th {
    padding: 0.35rem 0.4rem;
    white-space: normal;
    line-height: 1.2;
}

/* Ueberschrift ueber einer Tabelle der Auswertung — kleiner als die
   Kartenueberschrift, mit Luft darueber. */
.crs-detail h3 {
    margin: 1.1rem 0 0.4rem;
    font-size: 0.9rem;
}

.crs-inhalt {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.85rem 1rem;
    font-size: 0.82rem;
    line-height: 1.5;
    /**
     * KEIN Umbruch: der Rohtext eines Portals ist zeilenweise aufgebaut
     * (`FLUG :DUS-COV  20:40 …`, Tabellen mit Tabulatoren), und eine umgebrochene
     * Zeile liest sich als zwei — genau die Verwechslung, die beim Nachsehen
     * teuer wird. Stattdessen rollt der Block waagerecht.
     */
    white-space: pre;
    max-height: 600px;
    overflow: auto;
}

.crs-row-active {
    background: var(--color-primary-soft);
}

.crs-grid tbody tr {
    cursor: pointer;
}

.crs-grid tbody tr:hover {
    background: var(--color-primary-soft);
}

/* Die PNR ist ein Kuerzel aus sechs bis acht Zeichen — schmal und ohne Umbruch,
   damit sie nicht wie ein Textfeld aussieht und der Name den Platz bekommt. */
.crs-grid .crs-spalte-pnr,
.crs-grid td:nth-child(5) {
    width: 7.5rem;
    white-space: nowrap;
}

.crs-grid .col-actions {
    width: auto;
}

.crs-import-form {
    display: inline-block;
}

.crs-imported-icon {
    display: inline-flex;
    vertical-align: middle;
    margin-left: 0.35rem;
    color: var(--color-success-text);
}

/* ---------------------------------------------------------------------------
   UNTER 1400 PX STEHT DIE KARTE UNTEN
   ---------------------------------------------------------------------------
   Die Grenze lag bei 900 px, und dazwischen war es fuer beide zu eng: die Liste
   bekam bei 1280 px nur 602 der noetigen 704 und schnitt die Knopfspalte ab,
   waehrend die Karte mit 376 px zu schmal fuer den Rohtext war. Zwei Spalten,
   von denen keine ihre Aufgabe erfuellt, sind schlechter als eine.

   Untereinander hat die Liste die GANZE Breite — dort wird nichts mehr
   abgeschnitten —, und die Karte darunter ebenso. 1480 px ist GEMESSEN: dort
   bekommt die Liste 704 px und damit genau, was ihre Tabelle braucht. */
@media (max-width: 1480px) {
    .crs-layout {
        flex-direction: column;
    }

    .crs-detail {
        flex-basis: auto;
        width: 100%;
        /* Untereinander gibt es nichts zum Anheften: die Karte steht hinter der
           Liste und soll mit ihr laufen. */
        position: static;
        max-height: none;
    }
}

.stat-tiles + .crs-layout {
    margin-top: 1.5rem;
}

/* SEKUNDAERKNOPF: weisser Grund, dunkler Text, ein Pixel Rahmen. Er traegt die
   Werkzeugleisten (Export, Spalten, Hinzufuegen) und die Abbrechen-Knoepfe der
   Dialoge.

   So hoch wie der Primaerknopf daneben (--hoehe-knopf-klein zeigt jetzt auf
   dieselbe Marke): "Abbrechen" und "Senden" stehen im Sendedialog
   nebeneinander, und zwei Pixel Unterschied auf einer Grundlinie sieht man. */
/* Die sekundaere Rolle — der Bauplan steht oben bei .button-primary. */
.export-button {
    height: var(--hoehe-knopf-klein);
    padding: 0 var(--space-3);
    /* Der kraeftige Rahmen: ein Knopf ist zum Anfassen da und soll sich von
       einer Trennlinie unterscheiden — siehe --color-border-strong. */
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 0.85rem;
    font-weight: 500;
    box-shadow: var(--shadow-sm);
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease),
        box-shadow var(--duration) var(--ease);
}

.export-button:hover {
    /* Zurueckhaltender als vorher (--color-primary-soft, ein blauer Schleier):
       ein Hover soll zeigen, wo der Zeiger steht, und nicht die Farbe der
       primaeren Aktion aufgreifen.

       Der Rahmen geht dabei auf die GEDAEMPFTE Textfarbe und nicht auf die
       blasse: --color-text-subtle war heller als der Rahmen im Ruhezustand, der
       Knopf wirkte beim Ueberfahren also schwaecher statt kraeftiger. */
    background: var(--color-hover);
    border-color: var(--color-text-muted);
}

.export-button .icon {
    width: 16px;
    height: 16px;
}

/* .button-primary allein ist blau (siehe oben) — kombiniert mit .export-button
   (Toolbar-Look: Rahmen/heller Hintergrund) gewinnt sonst .export-button, weil
   es später in der Kaskade steht. Explizit zurück auf die Primärfarbe. */
.export-button.button-primary {
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    border-color: var(--color-primary);
}

.export-button.button-primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

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

.button-danger:hover {
    background: var(--color-danger-soft);
    border-color: var(--color-danger);
}

/* GEFUELLT rot mit weisser Schrift — fuer Knoepfe, die etwas endgueltig tun
   (Buchung stornieren). Rote Schrift auf weissem Grund ist ein Hinweis; hier
   soll es eine Warnung sein. Die Auswahl nennt beide Klassen, weil
   .button-primary sonst mit seinem Blau gewinnt: gleiche Staerke, spaeter in der
   Datei. */
.button-primary.button-danger {
    background: var(--color-danger);
    border-color: var(--color-danger);
    color: var(--auf-farbflaeche);
}

/* HIER BLEIBT WEISS, und das ist kein Versehen: der Hover setzt eine FESTE
   dunkle Flaeche (#b83a3a), keine aus der Palette. Sie ist in beiden Ansichten
   dieselbe, und weiss darauf traegt 5,4:1 — die Marke --auf-farbflaeche waere
   im Dunkelmodus fast schwarz auf dunkelrot. */
.button-primary.button-danger:hover {
    /* Etwas dunkler beim Ueberfahren — dieselbe Handschrift wie beim blauen
       Primaerknopf. */
    background: #b83a3a;
    border-color: #b83a3a;
    color: #fff;
}

.button-danger-sm {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-danger-text);
    cursor: pointer;
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.button-danger-sm:hover {
    background: var(--color-danger-soft);
    border-color: var(--color-danger);
}

.button-danger-sm .icon {
    width: 17px;
    height: 17px;
}

/* Der quadratische Primaerknopf (ein Zeichen, kein Text) folgt der Marke der
   Symbolknoepfe, statt seine 32 px selbst zu setzen — sonst geht er bei einer
   Aenderung der Dichte als einziger nicht mit. */
.button-primary-sm {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--hoehe-symbolknopf);
    height: var(--hoehe-symbolknopf);
    border: 1px solid var(--color-primary);
    border-radius: var(--radius);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.button-primary-sm:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

.button-primary-sm .icon {
    width: 17px;
    height: 17px;
}

/* ---------- Dokument ansehen: Mit/Ohne Preise ---------- */

.doc-view-menu {
    position: relative;
    display: inline-block;
}

.doc-view-popup {
    /* Breit genug fuer die Gruppenueberschriften ("Dokument drucken") — bei
       170px brachen sie auf zwei Zeilen. */
    min-width: 200px;
    white-space: nowrap;
}

.doc-view-popup-link {
    display: block;
    padding: 0.5rem 0.6rem;
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: 0.85rem;
    text-decoration: none;
    transition: background-color var(--duration) var(--ease);
}

.doc-view-popup-link:hover {
    background: var(--color-primary-soft);
}

/* Ein <button> im Menue muss aussehen wie die <a>-Eintraege daneben. Ohne diese
   Regel brachte er seine Browservorgaben mit — Rahmen, grauer Grund, zentrierter
   Text — und der E-Mail-Eintrag sah aus wie ein eingesetzter Knopf statt wie ein
   Menuepunkt. */
button.doc-view-popup-link {
    width: 100%;
    border: 0;
    background: none;
    font: inherit;
    font-size: 0.85rem;
    text-align: left;
    cursor: pointer;
}

/* ---------- Generische aufklappbare Bearbeiten-Zeile (Kunden-Tabs, Passagier-Grid u. ä.) ---------- */

.edit-row {
    display: none;
}

.edit-row.visible {
    display: table-row;
}

.edit-row td {
    background: var(--color-bg);
    padding: 1.25rem 1.5rem;
}

/* PASSAGIERFORMULAR IM BUCHUNGSDETAIL = dieselbe Karte wie im Assistenten.
   ---------------------------------------------------------------------------
   Im Assistenten ist jeder Passagier eine Karte (.wizard-gast): Rahmen, Radius,
   grauer Grund auf der weissen Flaeche des Blocks. Hier lag das Formular ohne
   Rahmen auf einem grauen Zellenhintergrund und sah dadurch aus wie ein
   aufgerissener Tabellenboden, nicht wie ein Formular.

   Jetzt traegt die ZELLE die weisse Flaeche und das Formular DARIN die Karte —
   dieselben Werte wie .wizard-gast, damit Anlegen und Bearbeiten gleich
   aussehen.

   Eigene Klasse und nicht .edit-row allgemein: dieselbe Aufklappzeile benutzen
   auch die Kunden-, Lieferanten- und Stammdatenmasken. Die sollen sich nicht
   mitaendern, nur weil das Buchungsdetail an den Assistenten angeglichen wird. */
/* Aussen GRAU, innen WEISS — dieselbe Schichtung wie bei den Leistungsbloecken
   (.block-editor-new-karte grau, das Formular darin .wizard-row-sub weiss).

   Vorher war es hier umgekehrt: weisse Zelle, graues Formular. Beides fuer sich
   sah ordentlich aus, nebeneinander in derselben Maske las es sich aber als
   zwei verschiedene Bauarten — der Passagierblock steht direkt unter den
   Leistungen. */
.edit-row-gast td {
    background: var(--color-bg);
    padding: 0.9rem 1rem 1rem;
}

.edit-row-gast .inline-edit-form {
    padding: 0.9rem 1rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.row-action-toggle.is-open {
    background: var(--color-primary-soft);
    color: var(--color-primary);
}

.inline-edit-form {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1rem;
    align-items: flex-end;
}

/* ---------------------------------------------------------------------------
   FORMULARTEXTE: Liste links, Texte rechts

   Dieselbe Aufteilung wie im Delphi-Client. Die Liste bekommt eine feste
   Spalte, die Texte den Rest — sie sind das, was hier Platz braucht. Unter
   900px stapelt es sich, sonst waeren beide Seiten zu schmal zum Lesen.
   --------------------------------------------------------------------------- */
.formtext-layout {
    display: grid;
    grid-template-columns: 280px minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}

/* Die Liste rollt fuer sich, wenn es viele Formulare sind — die Texte rechts
   sollen dabei stehen bleiben.

   IHRE HOEHE IST DIE DES FENSTERS, nicht eine feste Zahl: 32rem endete mitten
   auf der Seite, waehrend darunter noch Platz war und die letzten Formulare
   trotzdem im Rollbereich versteckt blieben. Jetzt reicht sie bis zum unteren
   Rand — abzueglich der Kopfleiste, der Ueberschrift und der Reiterzeile
   darueber, dafuer die 18rem.

   Und dvh statt vh: auf dem Telefon zaehlt vh die Adressleiste mit, die beim
   Rollen verschwindet — die Liste waere dort immer ein Stueck zu lang. */
.formtext-liste {
    max-height: calc(100dvh - 18rem);
    min-height: 20rem;
    overflow-y: auto;
}


.formtext-titel {
    margin: 0 0 0.75rem;
    font-size: 0.95rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Ein Textblock: Beschriftung als Abschnittsname, darunter das Feld.

   Die Beschriftung ist hier KRAEFTIGER als bei einem gewoehnlichen Feld: die
   drei Bloecke sind Abschnitte des Formulars ("Einleitungstext", "Fusstext",
   "Anschreiben"), und in der grauen Feldbeschriftungsfarbe verschwanden sie
   zwischen den Textfeldern. */
.formtext-block {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 1rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text);
}

/* PROSA, keine Tabelle: diese Texte gehen an Kunden und werden gelesen, nicht
   an Spalten ausgerichtet — anders als die Fusszeile der Filiale, die im Beleg
   Zeile fuer Zeile steht und deshalb dort in Festbreite bleibt. */
.formtext-block textarea {
    width: 100%;
    resize: vertical;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 400;
    line-height: 1.5;
}

/* Die gewaehlte Zeile der Liste — wie das aktive Konto im Kontenblatt. */
.formtext-liste .zeile-aktiv {
    background: var(--color-primary-soft);
}

.formtext-liste .zeile-aktiv td {
    font-weight: 600;
}

/* Die ganze Zeile ist der Weg zur Auswahl (data-href) — also auch der Zeiger.
   Der Verweis darin bleibt unauffaellig: zwei verschiedene Klickziele in einer
   Zeile sollen nicht wie zwei Angebote aussehen. */
.formtext-liste .auswahl-zeile {
    cursor: pointer;
}

.formtext-liste .auswahl-zeile:hover {
    background: var(--color-primary-soft);
}

.formtext-liste .auswahl-zeile a {
    color: inherit;
}

/* Die Sprachspalte ist schmal und traegt zwei Buchstaben — mittig gesetzt
   steht sie ruhiger als linksbuendig neben der langen Bezeichnung. */
.formtext-liste td:first-child,
.formtext-liste th:first-child {
    width: 4.5rem;
    text-align: center;
}

/* Der Kopf des rechten Teils: Bezeichnung und dahinter der Schluessel des
   Formulars, kleiner und ruhiger — er ist die Auskunft "welche Zeile ist das",
   nicht die Ueberschrift selbst. */
.formtext-titel code {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--color-text-muted);
    background: var(--color-surface-alt);
    padding: 0.1rem 0.4rem;
    border-radius: 4px;
}

@media (max-width: 900px) {
    .formtext-layout {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Untereinander darf die Liste NICHT das Fenster fuellen — sonst muesste
       man erst an ihr vorbeirollen, um an die Texte zu kommen. Feste Hoehe
       also, und sie schlaegt das calc() oben, weil sie spaeter steht. */
    .formtext-liste {
        max-height: 18rem;
        min-height: 0;
    }
}

/* Die Spalte mit dem Uebernommen-Zeichen: FESTE Breite.

   Sie ist meistens leer und traegt nur bei uebernommenen Vorgaengen ein Haken-
   Symbol. Ohne feste Breite waere sie in einer Liste ohne Uebernahme null Pixel
   breit und in einer mit Uebernahme 30 — die Spalten daneben verschoben sich
   dann von Seite zu Seite. */
.crs-spalte-importiert {
    width: 2.25rem;
    text-align: center;
}

/* Die Kanalspalte: FESTE, schmale Breite mit Umbruch im Wort.

   Die Kanalnamen sind lang und ohne Trennstellen ("SUNEXPRESS_B2B",
   "EUROSTAR"). Ohne Begrenzung nahm die Spalte sich, was sie brauchte, und
   schob die Zeilenaktionen rechts aus dem sichtbaren Bereich — der Löschknopf
   war abgeschnitten. Der Name darf jetzt umbrechen; er ist in zwei Zeilen
   lesbar, ein halber Knopf nicht bedienbar. */
.crs-spalte-kanal {
    width: 8.5rem;
    /* MINDESTBREITE, und die ist der eigentliche Punkt.

       `overflow-wrap: anywhere` erlaubt den Umbruch mitten im Wort — gedacht
       fuer lange Kanalnamen wie "SUNEXPRESS_B2B". Als Nebenwirkung faellt die
       kleinstmoegliche Breite der Spalte damit auf EIN ZEICHEN, und genau das
       nimmt sich der Browser, wenn die Tabelle insgesamt zu wenig Platz hat:
       "CRS-KANAL" und "PEGASUS" standen dann senkrecht, Buchstabe fuer
       Buchstabe. Die 8.5rem oben sind nur ein Wunsch, keine Untergrenze.

       6rem halten "PEGASUS" in einer Zeile und lange Namen in zweien. */
    min-width: 6rem;
    overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
   SCHNELLSUCHE: Wege, Feld, Trefferliste — alles im Dialog
   --------------------------------------------------------------------------- */

/* Der Halter traegt Knopf UND Feld: das Feld haengt absolut an ihm, deshalb
   position:relative genau hier und nicht an der Kopfzeile.

   Dieselbe Klasse benutzt der News-Knopf (.news-knopf-halter setzt sie
   zusaetzlich) — beide Kaesten haengen an ihrem Symbol und nicht in der
   Bildschirmmitte. */


/* Das Suchfeld unter dem Symbol, rechts ausgerichtet — dieselbe Form wie die
   uebrigen Aufklappmenues im Kopf, nur breiter: hier stehen Trefferzeilen mit
   Nummer, Name, Datum und Betrag.

   Auf schmalen Schirmen darf es nicht ueber den Rand hinauslaufen; deshalb
   min() gegen die Fensterbreite. */
.suche-feld-box {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    z-index: 60;
    /* Breit genug fuer eine Trefferzeile MIT Datum, Betrag und Status, ohne dass
       der Name gekuerzt wird — bei 560px stiess die rechte Spalte an den Namen. */
    width: min(680px, calc(100vw - 2rem));
    padding: 0.9rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
}

/* Die Spitze zum Symbol: sie sagt, WOZU der Kasten gehoert. Zwei Vierecke
   uebereinander — das untere in der Flaechenfarbe verdeckt die Rahmenlinie. */
.suche-feld-box::before,
.suche-feld-box::after {
    content: '';
    position: absolute;
    right: 0.75rem;
    width: 10px;
    height: 10px;
    transform: rotate(45deg);
}

.suche-feld-box::before {
    top: -6px;
    background: var(--color-border);
}

.suche-feld-box::after {
    top: -5px;
    background: var(--color-surface);
}

.suche-kopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.suche-kopf h2 {
    margin: 0;
    font-size: 1rem;
}

.suche-untertitel {
    margin: 0.15rem 0 0.75rem;
}

/* Die drei Wege als Schalterreihe. Der gewaehlte ist gefuellt — er entscheidet,
   WAS gesucht wird, und das muss auf einen Blick zu sehen sein. */
.suche-modi {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.suche-modus.active {
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
    color: var(--color-primary);
    font-weight: 600;
}

/* Das Suchfeld mit Lupe links und Knopf rechts, als EIN Element gelesen. */
.suche-feld {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface, transparent);
}

/* Die Lupe LINKS im Feld ist gedämpft — sie ist Verzierung, keine Schaltfläche.

   Nur das direkte Kind: vorher traf die Regel auch das Symbol IM Suchknopf
   daneben, und dort stand es grau auf blauem Grund — praktisch unsichtbar. */
.suche-feld > .icon {
    flex: 0 0 auto;
    color: var(--color-text-muted);
}

/* Der Suchknopf traegt nur ein Symbol: quadratisch statt in Textbreite, und das
   Symbol in der Schriftfarbe des Knopfes (weiss auf blau). */
.suche-feld .button-primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
}

.suche-feld .button-primary .icon {
    color: var(--auf-farbflaeche);
    vertical-align: 0;
}

/* Schriftfarbe AUSDRUECKLICH: das Feld hat weder Rahmen noch eigenen Grund und
   erbt deshalb keine der Feldregeln weiter oben (.form-grid input & Co.). Ohne
   `color` nahm es die Browservorgabe SCHWARZ — im Dunkelmodus stand die Eingabe
   damit schwarz auf dunkelgrauem Grund und war nicht zu lesen.

   Auch die Schriftart wird gesetzt: ein <input> erbt sie nicht von selbst, und
   die Eingabe stand in der Systemschrift des Browsers. */
.suche-feld input {
    flex: 1 1 auto;
    border: 0;
    background: transparent;
    padding: 0.35rem 0;
    font-size: 0.95rem;
    font-family: inherit;
    color: var(--color-text);
}

.suche-feld input::placeholder {
    color: var(--color-text-muted);
}

.suche-feld input:focus {
    outline: none;
}

/* Die Trefferliste rollt fuer sich: der Dialog soll nicht mit jedem Treffer
   wachsen und die Maske darunter verschieben. */
.suche-treffer {
    margin-top: 0.75rem;
    max-height: 18rem;
    overflow-y: auto;
}

.suche-treffer-zeile {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: baseline;
    gap: 0.75rem;
    padding: 0.5rem 0.6rem;
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
}

/* Die aktive Zeile — mit den Pfeiltasten gewaehlt, mit Enter geoeffnet. */
.suche-treffer-zeile.aktiv,
.suche-treffer-zeile:hover {
    background: var(--color-primary-soft);
}

.suche-treffer-rechts {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.suche-tastatur {
    margin-top: 0.75rem;
}

/* ---------------------------------------------------------------------------
   VENTUS-NEWS: Knopf im Kopf mit Zahl, Eintraege im Dialog
   --------------------------------------------------------------------------- */

/* Halter, damit die Zahl am Knopf haengen kann, ohne die Kopfzeile zu
   verschieben — position:relative gehoert an ein Element, das nur den Knopf
   umfasst. */


/* Die Zahl der aktuellen Meldungen: oben rechts AM Knopf, nicht daneben. Sie
   darf die Kopfzeile nicht hoeher machen, deshalb absolut gesetzt. */
.news-zahl {
    position: absolute;
    top: -0.25rem;
    right: -0.25rem;
    min-width: 1.05rem;
    padding: 0 0.2rem;
    border-radius: var(--radius-pill);
    background: var(--color-danger);
    color: var(--auf-farbflaeche);
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 1.05rem;
    text-align: center;
    pointer-events: none;
}

/* Der News-Kasten haengt am Symbol, genau wie das Suchfeld — er erbt dessen
   Aussehen (.suche-feld-box) und begrenzt nur seine Hoehe: drei Meldungen mit
   Text sind laenger als der Schirm, und der Kopf soll nicht mitwandern. */
.news-box {
    max-height: min(32rem, calc(100vh - 6rem));
    overflow-y: auto;
}

/* Ein Eintrag im Dialog. Trennlinie ZWISCHEN den Eintraegen und nicht unter dem
   letzten — sonst steht eine Linie ueber den Knoepfen. */
.news-eintrag + .news-eintrag {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

.news-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.news-kopf h3 {
    margin: 0;
    font-size: 0.95rem;
}

.news-datum {
    flex: 0 0 auto;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

/* "Neu" an einer aktuellen Meldung — dieselbe Farbe wie die Zahl am Knopf,
   damit erkennbar ist, welche Meldungen sie zaehlt. */
.news-marke {
    margin-left: 0.35rem;
    padding: 0.05rem 0.35rem;
    border-radius: 4px;
    background: var(--color-primary-soft);
    color: var(--color-primary);
    font-size: 0.7rem;
    font-weight: 600;
}

.news-eintrag p {
    margin: 0.4rem 0 0;
    font-size: 0.9rem;
    line-height: 1.5;
}

/* Der Suchknopf einer umbrechenden Filterleiste, RECHTS.

   .search-form ist ein umbrechender Flex-Container: der Knopf landet sonst
   direkt hinter dem letzten Feld, also links in der neuen Zeile. margin-left
   auto schiebt ihn an das rechte Ende seiner Zeile — dieselbe Seite, an der
   auch Export und Spalten stehen. */
.search-form .filter-knopf-rechts {
    margin-left: auto;
}

/* Eine RASTERZEILE in einem Bearbeitungsformular nimmt die ganze Breite.

   .inline-edit-form ist ein Flex-Container: ein <div class="form-grid"> darin
   ist ein Flex-Element und bekommt sonst nur seine INHALTSbreite — die vier
   Spalten standen dann links gedraengt, rechts blieb die halbe Seite leer.
   Mit flex-basis 100% belegt die Zeile die Breite, und die Spalten teilen sie
   sich (minmax(0, 1fr) je Spalte, siehe .form-grid.cols-*). */
.inline-edit-form > .form-grid {
    flex: 1 1 100%;
}

.inline-edit-form label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    min-width: 160px;
    flex: 1;
}

/* BETRAGSFELDER schmal: Preis, die fuenf Taxen (CH, TR, XP, RA, YR), Gebuehr und
   der gerechnete Gesamtpreis — acht Felder, die in EINE Reihe gehoeren, weil sie
   EINE Rechnung sind. Mit den 160px der uebrigen Felder brauchten sie 1.400px
   und brachen auf zwei bis drei Reihen um; die Rechnung war dann nicht mehr als
   Rechnung zu lesen.

   `flex: 0 1 6rem` heisst: nicht mitwachsen (sonst waeren sie auf einem breiten
   Bildschirm wieder so breit wie zuvor), aber schrumpfen duerfen — bis 4.5rem,
   damit die Reihe auch in einer schmalen Karte geschlossen bleibt.

   6rem und nicht 6.5rem: mit 104px je Feld brauchten die acht zusammen genau
   944px, und in einem 1.300px breiten Fenster hat die Karte 943 — die Reihe
   brach um einen einzigen Pixel um. Mit 96px sind es 880px. Ein Betrag wie
   "471,25" braucht darin rund 60px, es bleibt also Luft. */
.inline-edit-form label.feld-betrag {
    flex: 0 1 6rem;
    min-width: 4.5rem;
}

/* Betraege rechts, wie in jeder Betragsspalte dieser Anwendung: so stehen die
   Kommastellen der acht Felder untereinander. */
.inline-edit-form label.feld-betrag input {
    text-align: right;
}

/* OHNE PFEILCHEN — sonst wirkt die Ausrichtung nicht.
   ---------------------------------------------------------------------------
   Die Betragsfelder des Buchungsdetails sind <input type="number"> (im
   Assistenten sind es Textfelder mit inputmode="decimal"). Ein Zahlenfeld
   zeichnet rechts seine Auf/Ab-Pfeilchen, und die belegen genau den Platz, an
   dem der rechtsbuendige Betrag stehen soll: der Wert sass davor und sah
   linksbuendig aus, obwohl text-align: right gilt.

   Die Pfeilchen fehlen niemandem: einen Betrag tippt man, man klickt ihn nicht
   in Schritten von einem Cent hoch. Nur fuer die Betragsfelder ausgeblendet —
   bei Zaehlfeldern (Anzahl, Sitze) sind sie sinnvoll und bleiben.

   Zwei Schreibweisen, weil kein Browser beide versteht: die -webkit-Regel fuer
   Chrome und Safari, appearance: textfield fuer Firefox. */
.inline-edit-form label.feld-betrag input[type="number"] {
    appearance: textfield;
    -moz-appearance: textfield;
}

.inline-edit-form label.feld-betrag input[type="number"]::-webkit-outer-spin-button,
.inline-edit-form label.feld-betrag input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
}

/* Flugzeilen des Assistenten auf derselben weissen Flaeche wie Transfer und
   Hotel (.wizard-row-sub). Kopfzeile und Zeilen liegen GEMEINSAM darin, damit
   ihr Spaltenraster denselben Innenabstand hat und die Beschriftungen ueber
   ihren Feldern stehen bleiben.

   Die Kopfzeile bringt selbst ein margin-top mit (sie steht sonst unter einer
   Ueberschrift) — in der Karte ist das ein zweiter Abstand. */
.flug-karte {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.2rem 1rem 0.9rem;
    background: var(--color-surface);
    /* Eine Flugzeile traegt dreizehn Felder. Passt sie nicht in die Breite der
       Karte, ROLLT die Karte — vorher wurde die Zeile gequetscht, bis Felder
       uebereinander lagen und das letzte ausserhalb stand. Kopfzeile und Zeilen
       rollen gemeinsam, weil beide in dieser Karte liegen. */
    overflow-x: auto;
}

.flug-karte .row-grid-head {
    margin-top: 0.6rem;
}

/* DATUMSFELDER HABEN EINE FESTE BREITE — ueberall in der Anwendung.
   ---------------------------------------------------------------------------
   Ein Datumsfeld traegt "31.12.2026" und das Kalendersymbol, mehr nicht. Wo es
   in einem mitwachsenden Feld sass (Geburtsdatum in der Passagierzeile, 160px
   Mindestbreite und flex: 1), war es so breit wie ein Nachname.

   max-width und NICHT width: so wird kein Feld BREITER als vorher. In den
   Rastern, deren Spurbreiten einzeln ausgerechnet sind (.cols-flug,
   .zeitspalten), bleibt alles wie es war; nur wo das Feld sich vorher gedehnt
   hat, hoert es jetzt bei --feld-datum auf.

   Die Optionsfrist ist ein datetime-local und braucht Datum UND Uhrzeit —
   deshalb ihre eigene, groessere Grenze. */
input[type="date"] {
    max-width: var(--feld-datum);
}

input[type="datetime-local"] {
    max-width: var(--feld-frist);
}

/* In FLOW-Layouts muss auch das Label mitschrumpfen: das Feld hoert bei
   --feld-datum auf, das Label belegte aber weiter seine 160px und liess rechts
   daneben eine Luecke. Im Raster entscheidet die Spur, dort gilt das nicht. */
.inline-edit-form label:has(input[type="date"]) {
    flex: 0 1 var(--feld-datum);
    min-width: var(--feld-datum);
}

/* ANREDE so schmal wie ein Betragsfeld: darin steht "Herr", "Frau", "Kind" oder
   "Baby" — vier Woerter, das laengste sechs Zeichen. Mit den 160px der uebrigen
   Felder war es so breit wie ein Nachname und schob die Reihe auseinander.

   Dieselben Werte wie .feld-betrag, aber eine eigene Klasse: das Feld ist kein
   Betrag, es wird nicht rechts ausgerichtet, und wenn die Betragsbreite einmal
   nachgezogen wird, soll die Anrede nicht stillschweigend mitwandern. */
.inline-edit-form label.feld-anrede {
    flex: 0 1 6rem;
    min-width: 4.5rem;
}

/* TICKETNUMMER kleiner: 13 bis 15 Stellen brauchen rund 8rem, nicht die Breite
   eines Namens. `0 1` heisst wie beim Betrag — nicht mitwachsen, aber schrumpfen
   duerfen, damit die Reihe in einer schmalen Karte geschlossen bleibt. */
.inline-edit-form label.feld-ticket {
    flex: 0 1 9rem;
    min-width: 6.5rem;
}

/* Erzwungener Zeilenumbruch in der Feldreihe: ein leeres Element mit voller
   Basisbreite und ohne Hoehe — der uebliche Weg, in einem umbrechenden Flexbox
   eine Reihe zu beenden.

   Gebraucht, weil sonst die FENSTERBREITE entscheidet, welches Feld umbricht:
   auf einem Bildschirm begann die zweite Reihe mit dem Preis, auf dem naechsten
   mit den Notizen. Jetzt stehen die Reihen fest — Person und Tickets, dann die
   Betraege, dann der gerechnete Gesamtpreis. */
.inline-edit-form .feld-umbruch {
    flex: 1 1 100%;
    height: 0;
    margin: 0;
}

/* ---------------------------------------------------------------------------
   PASSAGIERZEILE IM ASSISTENTEN (bookings/create.php, Schritt 3)

   Aufbau wie beim Bearbeiten im Buchungsdetail (.inline-edit-form): jede Zeile
   traegt ihre eigenen Beschriftungen. Vorher war es EIN Raster mit dreizehn
   Spalten und einer gemeinsamen Kopfzeile — die brach um, und welches Feld zu
   welcher Ueberschrift gehoerte, war nicht mehr zu sehen.

   Hier braucht es nur die Abgrenzung ZWISCHEN den Passagieren: im Detail steht
   je Passagier eine eigene aufgeklappte Zeile, im Assistenten stehen sie
   untereinander in einer Karte.
   --------------------------------------------------------------------------- */
/* JEDER Passagier ein eigener Kasten, nicht nur eine Trennlinie: eine Zeile
   traegt sechzehn Felder in zwei Reihen, und bei vier Passagieren standen
   vierundsechzig gleich aussehende Felder untereinander — wo einer anfaengt und
   der naechste aufhoert, war nicht zu sehen.

   Der Grund ist der der Karte darunter (--color-bg), damit die Kaesten sich vom
   weissen Kartengrund abheben; jeder zweite noch eine Spur anders, wie die
   Zebrastreifen der Listen. Das ist bewusst schwach: es soll gliedern, nicht
   Aufmerksamkeit fordern. */
.wizard-gast {
    padding: 0.75rem 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
}

.wizard-gast:nth-of-type(even) {
    background: var(--color-surface-alt);
}

.wizard-gast + .wizard-gast {
    margin-top: 0.6rem;
}

/* Nummer und Loeschknopf stehen ueber der ganzen Breite des Kastens — dieselbe
   Kopfzeile wie bei einer Leistung. `flex-basis: 100%` ist noetig, weil sie in
   einer umbrechenden Flex-Reihe steckt und sonst neben der Anrede stuende. */
.wizard-gast > .wizard-row-head {
    flex: 1 1 100%;
    margin-bottom: 0.25rem;
}

.inline-edit-form input {
    font-size: 0.9rem;
}

/* Speichern steht in Bearbeitungsformularen rechts und mit Luft zum letzten
   Eingabefeld — Passagiere, Leistungen, Kunden-, Lieferanten- und
   Stammdatenmasken einheitlich.

   width: 100% ist der entscheidende Teil: .inline-edit-form ist ein
   flex-wrap-Container, in dem dieser Kasten sonst nur so breit wäre wie sein
   Inhalt und damit direkt hinter dem letzten Feld klebte — justify-content
   richtet nur INNERHALB des Kastens aus und hätte dort nichts zu verschieben
   gehabt. Mit voller Breite bricht er auf eine eigene Zeile um und der Knopf
   rückt tatsächlich nach rechts. In den Formularen ohne Flex (Leistungen) ist
   volle Breite ohnehin der Normalfall. */
.inline-edit-form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    width: 100%;
    margin-top: 1.25rem;
}

/* ---------- Kundendetail: Avatar-Header, Checkboxen, Notizfeld ---------- */

.kunde-header-main {
    flex-direction: row;
    align-items: center;
    gap: 1rem;
}

.kunde-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    flex-shrink: 0;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--color-primary), var(--color-accent2));
    color: var(--auf-farbflaeche);
    font-size: 1.3rem;
    font-weight: 700;
}

.kunde-checkbox-row {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

.kunde-checkbox {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    cursor: pointer;
}

.kunde-checkbox input {
    width: auto;
}

/* Was zu EINEM Beleg gehoert, aber nicht seine eigene Zeile ist: die
   elektronische Fassung unter der Rechnung.

   Eingerueckt und mit einer Linie links — dieselbe Sprache wie eine Antwort
   unter einem Beitrag: "das hier gehoert zu dem darueber". Ohne die Einrueckung
   stand die E-Rechnung wie ein eigener, vierter Beleg da. */
.dokument-unterzeile {
    margin: var(--space-3) 0 0 var(--space-4);
    padding-left: var(--space-4);
    border-left: 2px solid var(--color-border);
}

/* Der Rahmen des Feldblocks darin entfaellt: zwei Rahmen ineinander (die Linie
   links und der Kasten) sind einer zu viel. */
.dokument-unterzeile .mail-anhaenge {
    margin-top: 0;
    border: 0;
    padding-left: 0;
    padding-right: 0;
}

/* Ein Abschnitt im Dokument-Dialog (Voucher, Sicherungsschein): Ueberschrift,
   Liste, Knoepfe. Dieselbe Kachel wie eine Belegzeile — es ist dasselbe: ein
   Beleg, den man erzeugen kann, nur mit mehr darin. */
.dokument-abschnitt {
    margin: 0 0 var(--space-3);
    padding: var(--space-4);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

/* Im Abschnitt steht die Zeile ohne weiteren Abstand — die Kachel gibt ihn. */
.dokument-abschnitt .dokument-wahl {
    margin: 0;
}

.dokument-abschnitt h3 {
    margin: 0 0 var(--space-1);
    font-size: 0.95rem;
}

/* Der Dateiknopf der CRS-Uebernahme ist ein <label> mit verborgenem Feld
   darin — nur so laesst sich ein Dateiwaehler wie ein Knopf zeichnen. Er
   braucht deshalb den Zeiger, den ein Knopf sonst von selbst hat. */
.crs-datei-knopf {
    cursor: pointer;
}

/* Der SEPA-Einzug in den offenen Posten: Datum und Knopf nebeneinander, mit
   Abstand zum Hinweistext darueber. */
.sepa-form {
    margin-bottom: var(--space-4);
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIE ZWEI FRAGEN DES EXPORTDIALOGS — Format und Ziel
   ═══════════════════════════════════════════════════════════════════════════
   Als KACHELN, genau wie die Belege im Dokument-Dialog (.dokument-block):
   heller Grund, feiner Rahmen, Kartenradius. Es ist dieselbe Aufgabe — mehrere
   gleichrangige Bloecke in einem Dialog auseinanderhalten —, und zwei
   Loesungen dafuer waeren eine zu viel.

   Vorher war es ein duenn umrandetes <fieldset> mit der Beschriftung IN der
   Rahmenlinie. Diese Bauform stammt aus einer aelteren Formularwelt und passte
   als einziges Element des Dialogs nicht zu den Kacheln daneben. */
.export-wahl {
    margin: var(--space-4) 0 0;
    padding: var(--space-4);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

/* Die Beschriftung steht UEBER dem Block statt in seiner Rahmenlinie — wie bei
   .crs-block, und aus demselben Grund: ein <legend> laesst sich nicht mit
   display:block aus der Linie loesen, der Browser behandelt es gesondert.
   float ist der Weg, der ueberall wirkt. */
.export-wahl legend {
    float: left;
    width: 100%;
    padding: 0;
    margin-bottom: var(--space-3);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

/* float braucht einen Abschluss, sonst liegt der Inhalt darunter daneben. */
.export-wahl legend + * {
    clear: both;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIE BUCHUNGSMASKE IN REITERN
   ═══════════════════════════════════════════════════════════════════════════
   Die Reiterleiste steht direkt unter dem Buchungskopf und darf nicht hoeher
   sein als noetig — sie ist eine Wegweisung und kein Abschnitt. Deshalb kein
   zusaetzlicher Rand nach oben; die Karte darunter bringt ihren eigenen mit. */
.buchung-reiter {
    margin-top: 0;
}

/* Kopfzeile eines Uebersichtsblocks: Titel links, der Weg in den Fachreiter
   rechts. Dieselbe Form wie die Kopfzeilen der Leistungsbloecke — es ist
   dieselbe Sorte Zeile. */
.uebersicht-kopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
}

.uebersicht-kopf > h2 {
    margin: 0;
}

/* Die Vorschautabellen der Uebersicht sind ZUM LESEN und duerfen enger stehen
   als eine Arbeitsliste: die Zeilenhoehe der kompakten Ansicht, unabhaengig
   davon, ob die kompakte Ansicht eingeschaltet ist. */
.tabelle-kompakt {
    --hoehe-tabellenzeile: var(--hoehe-feld);
}

.tabelle-kompakt td,
.tabelle-kompakt th {
    font-size: 0.85rem;
}

/* Passagiere und Zahlungen nebeneinander — bei knappem Platz untereinander.
   Die Reihe ist eine Flexzeile (.detail-info-row); hier steht nur, ab welcher
   Breite sich zwei Tabellen nebeneinander noch lesen lassen. Darunter bricht
   die zweite um, statt auf 20 Zeichen zusammenzufallen. */
.uebersicht-paar > .card {
    flex: 1 1 28rem;
    min-width: 0;
}

/* Die Passagiertabelle braucht mehr Breite als die Zahlungstabelle daneben
   (sechs Spalten gegen vier, darunter die Ticketnummer). Bei halbe/halbe
   fehlten ihr gemessene 17 Pixel, und die letzten zwei Spalten standen im
   Rollbereich statt im Bild. */
.uebersicht-paar > .card.uebersicht-breit {
    flex: 1.4 1 34rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   HINWEISPUNKTE — "worauf ist zu sehen"
   ═══════════════════════════════════════════════════════════════════════════
   Diese vier Regeln kommen aus der zweiten Buchungsansicht, die es nicht mehr
   gibt (ihre Uebersicht ist jetzt der erste Reiter der Buchungsmaske). Benutzt
   werden sie weiter: der Kontrollschritt des Buchungsassistenten zeigt damit
   "Vor dem Speichern pruefen". Sie heissen deshalb nach ihrer Aufgabe und nicht
   mehr nach einer Ansicht.

   Alles Uebrige jener Ansicht — Kennzahlenstreifen, Zeitleiste, Kopfraster —
   ist mit ihr entfallen; die Klassen trugen alle das Praefix v2-, das Entfernen
   war deshalb eine Suche und keine Archaeologie. */
.hinweispunkte {
    list-style: none;
    margin: 0;
    padding: 0;
}

.hinweispunkt {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3);
    margin-bottom: var(--space-2);
    border-radius: var(--radius);
    background: var(--color-bg);
    border-left: 3px solid var(--color-warning);
}

.hinweispunkt-zeichen {
    flex-shrink: 0;
    color: var(--color-warning-text);
}

.hinweispunkt-inhalt {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

/* Die zwei Wahlzeilen einer Kachel bekommen etwas mehr Luft als eine
   Anhangsliste (dort stehen fuenf bis zehn Zeilen, hier zwei) und eine Linie
   dazwischen — sie sind ZWEI Entscheidungen und nicht eine Aufzaehlung. */
.export-wahl .mail-anhang {
    padding: var(--space-2) 0;
}

.export-wahl .mail-anhang + .mail-anhang {
    border-top: 1px solid var(--color-border);
}

/* Das Adressfeld erscheint eingerueckt unter der Auswahl "Per E-Mail" — es
   gehoert zu ihr und nicht zur Gruppe als Ganzes. */
.export-adresse {
    margin: var(--space-2) 0 0 var(--space-6);
}

/* Das Ausfuehrungsdatum im Einzugsdialog: RECHTS, ueber der Spalte "Offen" und
   dem Einzugsbetrag darunter — also bei den Zahlen, auf die es sich bezieht.
   Links stand es allein in einer sonst leeren Zeile.

   Die Beschriftung steht NEBEN dem Feld und nicht darueber: es ist ein
   einzelnes Feld in einer eigenen Zeile, und "Ausfuehrung am 04.09.2026" liest
   sich als ein Satz. Ueber dem Feld waere es eine Spaltenueberschrift ohne
   Spalte.

   grid-template-columns: auto — die Spalte ist so breit wie Beschriftung plus
   Feld; eine feste Breite muesste die laengste Uebersetzung raten. */
.sepa-datum {
    grid-template-columns: auto;
    justify-content: end;
}

/* .form-grid label ist eine Spalte (Beschriftung ueber dem Feld) — hier eine
   Zeile. Nur das Layout wird gedreht; Schriftgroesse und Farbe der
   Beschriftung bleiben, wie sie ueberall sind. */
.sepa-datum label {
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
}

/* Das Feld traegt ein Datum und waechst nicht mit der Zeile. */
.sepa-datum input {
    width: 11rem;
}

/* Die Zeilenliste im Einzugsdialog: etwas kleiner als eine Listentabelle, sie
   steht in einem Dialog und traegt vier kurze Spalten. */
/* Die kleinen Tabellen IN einem Dialog (Lastschriftmandate, Voucherauswahl) —
   derselbe Rumpf stand zweimal da. */
.sepa-tabelle,
.voucher-tabelle {
    margin-top: var(--space-3);
    margin-bottom: 0;
    font-size: 0.85rem;
}

/* Datum und Knopf nebeneinander, beide auf der LINIE DER FELDER
   (align-items: flex-end) — sonst staende der Knopf auf Hoehe der
   Beschriftung, weil das Label hoeher ist als er.

   .form-grid bleibt am Element und wird hier nur im LAYOUT ueberschrieben
   (grid -> flex): Beschriftung ueber dem Feld, Schriftgroesse, Rahmen und Grund
   der Eingabe haengen daran. Dieselbe Bauart wie .aufgabe-neu-zeile — ohne sie
   stand die Beschriftung neben einem unformatierten Kaestchen. */
.form-grid.sepa-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

/* Das Datumsfeld traegt seinen Inhalt und waechst nicht mit — daneben soll der
   Knopf stehen und nicht ans Ende der Zeile rutschen. */
.sepa-zeile > label {
    flex: 0 0 auto;
}

/* Das Hochladen in der Dokument-Historie: Dateiwahl und Knopf nebeneinander,
   und die Dateiwahl nimmt den Rest der Breite — ein langer Dateiname soll
   lesbar bleiben. Umbrechen darf es, wenn der Dialog schmal wird. */
.upload-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.upload-zeile input[type="file"] {
    flex: 1 1 16rem;
    min-width: 0;
    font-size: 0.85rem;
}

/* Eine ERLEDIGTE Wiedervorlage: blasser, aber lesbar. Nicht durchgestrichen —
   der Text ist die Notiz, und durchgestrichene Prosa liest sich schwer; die
   Statusspalte sagt ohnehin, dass sie erledigt ist. */
.zeile-erledigt {
    color: var(--color-text-muted);
}

/* Das Anlegen-Formular der Wiedervorlage IN DER LISTE: der Knopf sitzt in der
   letzten Rasterzelle und unten, damit er auf einer Linie mit den Feldern steht
   und nicht mit deren Beschriftungen. */
.aufgabe-neu .inline-edit-form-actions {
    display: flex;
    align-items: flex-end;
}

/* Dasselbe Formular IM BUCHUNGSDETAIL — dort sind es nur drei Dinge, und die
   Notiz nimmt allen freien Platz.

   Die Klasse .form-grid BLEIBT am Formular und wird hier nur im LAYOUT
   ueberschrieben (grid -> flex). Alles andere haengt daran: Beschriftung ueber
   dem Feld, Schriftgroesse, Rahmen und Grund der Eingabefelder. Ohne sie stand
   die Beschriftung neben einem unformatierten Kaestchen — nachgestellt und
   genau so eingetreten.

   Eine Zeile statt eines Rasters: im Vierer-Raster bekam die Notiz zwei von
   vier Spalten und damit die halbe Breite, waehrend rechts daneben nichts
   stand. Termin und Knopf sind so breit, wie sie sein muessen, der Rest gehoert
   dem Text.

   align-items: flex-end setzt alle drei auf DIE LINIE DER FELDER — ohne das
   staende der Knopf auf Hoehe der Beschriftungen, weil die beiden Labels
   hoeher sind als er. */
.form-grid.aufgabe-neu-zeile,
.form-grid.aufgabe-neu {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

/* Die Notiz nimmt den Rest — mindestens 14rem, sonst quetscht sie sich auf
   schmalen Fenstern zusammen, statt umzubrechen. min-width: 0, damit sie in
   einem Flex-Element auch wirklich schrumpfen darf. */
.aufgabe-neu-zeile .aufgabe-notiz,
.aufgabe-neu .aufgabe-notiz {
    flex: 1 1 14rem;
    min-width: 0;
}

/* Die uebrigen Felder tragen ihren Inhalt und wachsen nicht mit. */
.aufgabe-neu-zeile > label:not(.aufgabe-notiz),
.aufgabe-neu > label:not(.aufgabe-notiz) {
    flex: 0 0 auto;
}

/* TERMIN UND BUCHUNGSNUMMER GLEICH BREIT.
   ─────────────────────────────────────────────────────────────────────────────
   Beide tragen eine kurze, feste Angabe und stehen untereinander, wenn die
   Zeile umbricht. Ohne feste Breite richtete sich jedes nach seinem Feldtyp:
   das Datumsfeld bringt mit Kalendersymbol seine eigene Breite mit, das
   Textfeld nahm die volle Rasterspalte — nebeneinander sahen sie aus wie zwei
   verschiedene Sorten Feld.

   13rem ist die Breite, die "tt.mm.jjjj, --:--" samt Symbol braucht. */
/* MIT `> label`, weil die Regel darueber `:not(.aufgabe-notiz)` traegt und
   damit einen Punkt mehr wiegt: ohne den Elementnamen hier blieb es bei
   `flex: 0 0 auto`, und beide Felder richteten sich nach ihrem Inhalt —
   gemessen 200 px fuer das Datum und 190 fuer die Nummer. Gleich aussehen
   sollten sie aber. */
.aufgabe-neu > label.aufgabe-feld-schmal {
    flex: 0 0 13rem;
}

.aufgabe-neu > label.aufgabe-feld-schmal input {
    width: 100%;
}

/* Der Knopf haengt hinten an der Zeile und nimmt nur seine eigene Breite.
   Ohne das war er ein Flexkind ohne Basis, wurde ueber die ganze Breite
   gezogen und stand allein auf einer zweiten Zeile — mit einem Streifen Leere
   darueber. */
.aufgabe-neu .inline-edit-form-actions {
    flex: 0 0 auto;
    /* width UND margin-top zuruecknehmen: die allgemeine Regel setzt
       `width: 100%` und einen Abstand nach oben (fuer Formulare, in denen der
       Knopf unter den Feldern steht). Hier steht er DANEBEN, und `flex: 0 0
       auto` allein haette gegen eine gesetzte Breite nichts ausgerichtet. */
    width: auto;
    margin: 0 0 0 auto;
}

/* Die beiden Textfelder teilen sich, was uebrig bleibt. 12rem als Basis und
   nicht 14: mit 14 passte der Knopf nicht mehr in dieselbe Zeile. */
.aufgabe-neu .aufgabe-notiz {
    flex: 1 1 12rem;
}

/* Ein Feld ueber ZWEI Rasterspalten — fuer eine Angabe, die laenger ist als
   ihre Nachbarn (die Anschrift des Absicherers neben Name und Policennummer).
   Ohne das stuende sie in Drittelbreite und waere beim Lesen abgeschnitten. */
.form-grid .feld-breit-2 {
    grid-column: span 2;
}

/* Die Voucher-Tabelle im Dialog: schmaler als eine Listentabelle, denn sie
   steht in einem Kasten und traegt sechs kurze Spalten. Der Rahmen der
   .data-table bleibt — es soll dieselbe Tabelle sein wie ueberall. */


/* Das Kaestchen sitzt mittig in seiner Spalte und traegt keinen eigenen
   Abstand — die Zelle gibt ihn vor. */
.voucher-tabelle input[type="checkbox"] {
    width: auto;
    margin: 0;
}

/* Die Beschriftung nimmt die ganze Zelle, damit der Klick auf die Reiseart
   das Kaestchen trifft und nicht nur das Wort. */
.voucher-tabelle label {
    display: block;
    cursor: pointer;
}

/* Die drei Wege stehen unter der Liste, rechtsbuendig wie die Knoepfe der
   Dialoge — sie schliessen den Abschnitt ab, statt ihn anzufuehren. */
.voucher-knoepfe {
    justify-content: flex-end;
    margin-top: var(--space-3);
}

/* ═══════════════════════════════════════════════════════════════════════════
   RECHTEMATRIX in der Mitarbeitermaske — Modul, "Aktiv", "Bearbeiten"
   ═══════════════════════════════════════════════════════════════════════════
   Drei Spalten, und die beiden Hakenspalten sind FEST breit: sie tragen ein
   Kaestchen und ein kurzes Wort, und ein Raster aus Anteilen liesse sie mit dem
   laengsten Modulnamen mitwachsen. Der Modulname nimmt den Rest — minmax(0,1fr),
   damit ein langer Name die Spalte nicht aufblaeht, sondern umbricht. */
.rechte-gruppe {
    margin-top: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
}

.rechte-kopf,
.rechte-zeile {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 7.5rem 8.5rem;
    align-items: center;
    gap: var(--space-2);
    padding: 0.4rem var(--space-3);
}

/* Der Gruppenkopf traegt die "alles an/aus"-Haken und hebt sich deshalb ab —
   sonst liest er sich wie die erste Modulzeile. */
.rechte-kopf {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    font-weight: 600;
    font-size: 0.8rem;
}

.rechte-zeile + .rechte-zeile {
    border-top: 1px solid var(--color-border);
}

.rechte-zeile:hover {
    background: var(--color-hover);
}

.rechte-gruppenname,
.rechte-modul {
    min-width: 0;
    overflow-wrap: break-word;
}

.rechte-modul {
    font-size: 0.85rem;
}

.rechte-zelle {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    cursor: pointer;
}

.rechte-zelle input {
    width: auto;
    margin: 0;
}

/* Die Beschriftung STEHT in jeder Zeile, ist aber nur fuer Hilfsmittel da: auf
   dem Bildschirm sagt der Gruppenkopf, welche Spalte welche ist, und vierzig
   Mal "Aktiv Bearbeiten" untereinander waere eine Wand. Ein Kaestchen ohne
   jede Beschriftung waere dagegen fuer einen Screenreader eine Frage ohne Text. */
.rechte-zeile .rechte-zelle-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Häkchen innerhalb eines Feldrasters.

   Ohne diese Regel gewinnt `.form-grid label` mit seinem
   `flex-direction: column` — das ist für Textfelder richtig (Beschriftung über
   dem Feld), beim Häkchen stand das Kästchen dadurch MITTIG ÜBER seiner
   Beschriftung statt davor. Betrifft jedes .kunde-checkbox in einem .form-grid,
   also auch das Aktiv-Kennzeichen der Hotelmaske. */
.form-grid .kunde-checkbox {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
}

.kunde-notiz {
    width: 100%;
    min-height: 140px;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    color: var(--color-text);
    font-family: inherit;
    font-size: 0.9rem;
    resize: vertical;
}

/* ---------- Sidebar footer links (copyright + legal) ---------- */

.sidebar-footer-links {
    display: flex;
    justify-content: center;
    gap: 0.75rem;
    margin-bottom: 0.35rem;
}

.sidebar-footer-links a {
    font-size: 0.7rem;
    color: var(--color-sidebar-text);
    opacity: 0.85;
}

.sidebar-footer-links a:hover {
    opacity: 1;
    text-decoration: underline;
}

.auth-footer .sidebar-footer-links a {
    color: var(--color-text-muted);
}

/* ---------- Legal pages (Impressum/Datenschutz) ---------- */

.legal-card {
    position: relative;
    width: 100%;
    max-width: 640px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: 2rem;
    text-align: left;
}

.legal-close {
    position: absolute;
    top: 1.25rem;
    right: 1.25rem;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    color: var(--color-text);
    font-size: 0.8rem;
    cursor: pointer;
    transition: background-color var(--duration) var(--ease);
}

.legal-close:hover {
    background: var(--color-border);
}

.legal-card h1 {
    margin-top: 0;
}

.legal-card h2 {
    font-size: 1rem;
    margin: 1.5rem 0 0.5rem;
}

.legal-license-note {
    margin-bottom: 1.5rem;
    padding: 0.85rem 1rem;
    background: var(--color-primary-soft);
    border-radius: var(--radius);
    font-size: 0.85rem;
    line-height: 1.5;
}

/* ---------- Detail page header ---------- */

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

.detail-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: 1.25rem 1.5rem;
    margin-bottom: 1.5rem;
}

.detail-header-main {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.3rem;
}

.detail-header-main h1 {
    margin: 0;
    font-size: 1.3rem;
}

.detail-header-main .status-badge {
    margin: 0;
}


.detail-header-amounts {
    display: flex;
    gap: 1.5rem;
}

.amount-pill {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    text-align: right;
}

.amount-label {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.amount-value {
    font-size: 1.05rem;
    font-weight: 600;
}

.detail-section {
    margin-bottom: 1.5rem;
}

.detail-section .data-table {
    margin-bottom: 0;
    box-shadow: none;
    border: none;
}

/* Generisches Label/Wert-Raster für Detailseiten-Infoboxen (z. B. Agenturdaten im Avis). */
.info-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 0.85rem 1.5rem;
}

.info-field {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.info-field dt {
    margin: 0;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
}

.info-field dd {
    margin: 0;
    font-size: 0.88rem;
    word-break: break-word;
}

.form-grid input.text-right {
    text-align: right;
}

/* ---------- Pie chart (Gesellschaft / Reiseart breakdowns) ---------- */

.pie-chart {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.75rem;
    min-height: 0;
    flex: 1 1 auto;
}

.pie-svg {
    width: auto;
    max-width: 65%;
    height: 100%;
    max-height: 100%;
    aspect-ratio: 1 / 1;
    overflow: visible;
    flex-shrink: 0;
}

.pie-slice {
    stroke: var(--color-surface);
    stroke-width: 2;
    cursor: pointer;
    transition: opacity 0.1s ease;
}

.pie-slice:hover,
.pie-slice.chart-hover {
    opacity: 0.82;
}

.pie-color-1 { fill: var(--series-1); background-color: var(--series-1); }
.pie-color-2 { fill: var(--series-2); background-color: var(--series-2); }
.pie-color-3 { fill: var(--series-3); background-color: var(--series-3); }
.pie-color-4 { fill: var(--series-4); background-color: var(--series-4); }
.pie-color-5 { fill: var(--series-5); background-color: var(--series-5); }
.pie-color-6 { fill: var(--series-6); background-color: var(--series-6); }
.pie-color-7 { fill: var(--series-7); background-color: var(--series-7); }
.pie-color-other { fill: var(--series-other); background-color: var(--series-other); }

.pie-legend {
    list-style: none;
    margin: 0;
    padding: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.3rem;
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    max-height: 100%;
    overflow-y: auto;
}

.pie-legend-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.78rem;
    color: var(--color-text);
}

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

/* ═══════════════════════════════════════════════════════════════════════════
   DER RING (Verteilung der Startseite) — Torte mit Loch und Zahl darin
   ═══════════════════════════════════════════════════════════════════════════
   Dieselben Farben und dieselbe Legende wie die volle Torte; neu sind nur die
   Zahl in der Mitte und die dreispaltige Legende (Name | Wert | Anteil).

   Die MITTE ist der Bezug: ein Ring zeigt Anteile, und "37,5 %" ohne die
   Gesamtzahl daneben ist eine halbe Aussage. Deshalb steht sie im Loch und
   nicht in der Ueberschrift — dort liest man sie mit dem Bild zusammen.
   ═══════════════════════════════════════════════════════════════════════════ */
.pie-mitte-wert {
    fill: var(--color-text);
    /* 22 und nicht 26: das Loch ist bei 58 Innenradius rund 88 px breit, wenn
       das Bild 167 px gross gezeichnet wird — "5.090" bei 26 px war 90 px breit
       und lag auf dem Ring. */
    font-size: 22px;
    font-weight: 700;
    text-anchor: middle;
}

.pie-mitte-text {
    fill: var(--color-text-muted);
    font-size: 13px;
}

/* Der Trennstrich zwischen zwei Ringstuecken ist die FLAECHENFARBE der Karte,
   nicht grau: so sieht er in Hell und Dunkel gleich aus und wirkt als Fuge,
   nicht als eigene Linie. Bei einem Ring ist er sichtbarer als bei einer Torte,
   weil er auch am Innenrand entlanglaeuft — deshalb schmaler. */
.pie-chart-ring .pie-slice {
    stroke: var(--color-surface);
    stroke-width: 1.5;
}

/* ---------------------------------------------------------------------------
   DREI SPALTEN IN DER LEGENDE
   ---------------------------------------------------------------------------
   Name links, Wert und Anteil rechtsbuendig — untereinander ausgerichtet, damit
   die Zahlen vergleichbar sind. Der Name darf kuerzen (Zielgebiete und
   Reisearten sind Freitext aus dem Bestand), die Zahlen nie: sie haben feste
   Mindestbreiten.
   --------------------------------------------------------------------------- */
.pie-legend-spalten {
    display: grid;
    /* Punkt | Name (kuerzt) | Code | Wert | Anteil — fuenf Spalten, damit der
       Code hinter dem Namen nicht mit ihm weggekuerzt wird. Wo kein Code steht,
       ist die Spalte leer und nimmt keine Breite. */
    grid-template-columns: 10px minmax(0, 1fr) auto auto auto;
    gap: 0.4rem;
    align-items: center;
}

.pie-legend-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Der Code hinter dem Lieferantennamen ("TUI Deutschland TUI"): kleiner und
   gedaempft. Er ist die zweite Schreibweise derselben Sache, nicht eine zweite
   Angabe — deshalb tritt er zurueck. Kuerzt der Name, verschwindet der Code mit
   ihm; beides steht vollstaendig im Titel der Zeile. */
.pie-legend-code {
    font-size: 0.9em;
    color: var(--color-text-subtle);
}

.pie-legend-wert {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.pie-legend-anteil {
    min-width: 2.6rem;
    text-align: right;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   DIE DREI FELDER DER VERTEILUNG WACHSEN MIT IHREM INHALT
   ---------------------------------------------------------------------------
   .chart-mini hat eine feste Hoehe von 260 px — richtig fuer die
   Verkaufsstatistik, in der zwei Torten nebeneinander gleich hoch sein sollen.
   Hier stehen aber ein Ring, eine Tabelle und noch ein Ring: mit fester Hoehe
   war die Rangliste bei fuenf Zielen unten angeschnitten.

   Deshalb Hoehe nach Inhalt und ein Mindestmass, damit die drei Felder bei
   wenig Inhalt nicht unterschiedlich hoch stehen. Das SVG richtet sich dann
   nach seiner Breite (aspect-ratio) statt nach der Kartenhoehe.
   --------------------------------------------------------------------------- */
.verteilung-raster .chart-mini {
    height: auto;
    min-height: 15rem;
}

.verteilung-raster .pie-chart {
    align-items: center;
}

/* 40 % statt 45: die drei Felder sind rund 400 px breit, und die Legende
   braucht den Rest fuer Namen wie "PAUSCHAL" — bei 45 % blieben 28 px, und in
   der Legende stand "PA…". */
.verteilung-raster .pie-svg {
    width: 36%;
    max-width: 36%;
    height: auto;
    max-height: none;
}

.pie-legend-swatch {
    width: 10px;
    height: 10px;
    border-radius: 2px;
    flex-shrink: 0;
}

.pie-empty {
    padding: 2rem 0;
    text-align: center;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* ---------- Detail page toolbar (back link + print button) ---------- */

.detail-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.detail-toolbar p {
    margin: 0;
}

/* Dokument- und Bearbeiten-Menue gehoeren zusammen und stehen rechts. Ohne die
   Gruppe verteilt space-between drei Kinder ueber die ganze Breite, und
   "Dokument" stand einzeln in der Mitte. */
.detail-toolbar-menues {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

/* ---------- Print (Buchungsdetail -> DIN A4) ---------- */

.only-print {
    display: none;
}

@media print {
    /* Force light values regardless of the viewer's dark-mode toggle — a printed
       document is always black-on-white, never dark-mode. */
    :root,
    :root[data-theme="dark"] {
        --color-bg: #ffffff;
        --color-surface: #ffffff;
        --color-text: #111111;
        --color-text-muted: #444444;
        --color-border: #999999;
        --color-border-strong: #999999;
        --color-primary: #111111;
        --color-primary-light: #ffffff;
        --color-hover: #ffffff;
        --color-surface-alt: #ffffff;
        --color-text-subtle: #444444;
        --color-danger: #111111;
        --color-danger-text: #111111;
        --color-success: #111111;
        --color-success-text: #111111;
        --color-warning: #111111;
        --color-warning-text: #111111;
        --color-accent2: #111111;
        --color-accent2-text: #111111;
        --color-danger-soft: #ffffff;
        --color-success-soft: #ffffff;
        --color-warning-soft: #ffffff;
        --color-accent2-soft: #ffffff;
        --shadow-sm: none;
        --shadow-md: none;
        --shadow-lg: none;
        /* Der Fokusring hat auf Papier nichts zu suchen: gedruckt wird, was auf
           dem Bildschirm stand, samt dem Feld, in dem gerade der Cursor war. */
        --fokus-ring: none;
    }

    .sidebar,
    .topbar,
    .no-print {
        display: none !important;
    }

    .only-print {
        display: block;
    }

    .app {
        display: block;
        min-height: 0;
    }

    .main,
    .content {
        display: block;
        padding: 0;
    }

    /* DIESELBE SCHRIFT WIE AM BILDSCHIRM. Hier stand die Systemschrift — aus
       der Zeit, als die Anwendung eine Schrift benutzte, die sie nicht selbst
       ausliefert. IBM Plex liegt beim Server und ist geladen, wenn gedruckt
       wird; ein Ausdruck in einer anderen Schrift als die Maske ist ein zweites
       Erscheinungsbild fuer denselben Inhalt. Die Systemschriften bleiben als
       Rueckfall (siehe --schrift). */
    body {
        background: #fff;
        color: #000;
        font-family: var(--schrift);
    }

    .print-header {
        text-align: center;
        margin-bottom: 10mm;
        padding-bottom: 5mm;
        border-bottom: 2px solid #000;
    }

    .print-header-agent {
        font-size: 0.85rem;
        line-height: 1.5;
        margin-bottom: 6mm;
    }

    .print-header-title {
        font-size: 1.2rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.08em;
    }

    /* Document look: no cards/pills/shadows — plain sections with hairline rules. */
    .detail-header,
    .card,
    .detail-section {
        background: none !important;
        box-shadow: none !important;
        border: none !important;
        border-radius: 0 !important;
        padding: 0 !important;
        margin-bottom: 6mm;
        break-inside: avoid;
    }

    .detail-header {
        display: flex;
        border-bottom: 1px solid #000 !important;
        padding-bottom: 3mm !important;
    }

    .card h2,
    .detail-section h2 {
        font-size: 0.95rem;
        border-bottom: 1px solid #000;
        padding-bottom: 1.5mm;
        margin-bottom: 3mm;
    }

    .card h2 .icon,
    .detail-section h2 .icon,
    .amount-pill .icon {
        display: none;
    }

    .detail-info-row {
        display: block;
    }

    .detail-info-row .card {
        margin-bottom: 5mm;
    }

    .status-badge {
        background: none !important;
        color: #000 !important;
        font-weight: 700;
        padding: 0;
        border-radius: 0;
    }

    .amount-value,
    .text-danger,
    .text-success {
        color: #000 !important;
    }

    .data-table {
        border-collapse: collapse;
        width: 100%;
        box-shadow: none;
        border: none;
    }

    .data-table th,
    .data-table td {
        border: 1px solid #999;
        padding: 1.5mm 2mm;
    }

    /* Der Kopf traegt sein Band auch auf Papier — am Bildschirm hat er seit dem
       Wechsel auf das Erscheinungsbild des Flight-Importers eines, und ein
       Ausdruck, der die Liste anders gliedert als die Maske, ist eine zweite
       Auskunft ueber dieselben Daten. Der Wert steht hart und nicht als Marke:
       die Druckpalette darueber setzt alle Flaechen auf Weiss, damit nichts
       Buntes auf dem Blatt landet — dieses eine Grau ist gewollt. */
    .data-table th {
        background: #eeeeee !important;
        color: #000;
    }

    @page {
        size: A4;
        margin: 18mm 15mm;
    }
}

/* ==================== Responsive / Mobile ==================== */

/* ---------- Data tables: horizontal scroll instead of squeezing columns ---------- */

/* ═══════════════════════════════════════════════════════════════════════════
   DER ROLLBEHAELTER — und warum er eine HOEHE braucht
   ═══════════════════════════════════════════════════════════════════════════
   Hier stand `overflow-x: auto` allein, mit der Begruendung, der geheftete
   Spaltenkopf darunter wirke dann gegen den SEITEN-Bildlauf, weil dieser Kasten
   ja nur waagerecht rolle.

   DAS IST NICHT SO, und der Kopf hat an keiner der 72 so gefassten Tabellen
   gehalten: schreibt man eine Achse auf `auto`, rechnet der Browser die andere
   von `visible` auf `auto` hoch — andere Kombinationen sind nicht darstellbar
   (CSS Overflow, "Computed values"). Der Kasten war also ohnehin ein
   Rollbereich, nur einer ohne Hoehe, in dem nie etwas rollt. Der Kopf heftete
   sich an seine Oberkante, und die wanderte mit der Seite nach oben.

   Also bekommt der Kasten eine Hoehe und rollt selbst. Dann heftet der Kopf an
   seine Oberkante — und die steht. Der Nebengewinn: die Blaetterleiste unter
   der Tabelle bleibt sichtbar, statt am Listenende zu liegen.

   Die Hoehe als `calc(100vh - 15rem)`: das ist ungefaehr, was ueber einer Liste
   steht (Kopfzeile, Ueberschrift, Suchleiste, Kachelreihe). Es ist eine
   OBERGRENZE — eine kurze Liste bleibt so hoch, wie sie ist, und bekommt keine
   Rollleiste.
   ═══════════════════════════════════════════════════════════════════════════ */
.table-scroll {
    overflow: auto;
    max-height: calc(100vh - 15rem);
    -webkit-overflow-scrolling: touch;
    /* Am Listenende nicht die Seite mitziehen. */
    overscroll-behavior: contain;
}

/* Der Tabellenkopf bleibt beim Blaettern stehen. In den Offenen Posten stehen
   bis zu 1000 Zeilen auf einer Seite; ohne das weiss man nach dem dritten
   Bildlauf nicht mehr, welche Spalte welche ist.

   Geheftet wird gegen den Bildlauf des .table-scroll-Kastens (siehe dort) — ein
   Rahmen als box-shadow, weil border-collapse die Rahmenlinie beim Heften
   wegwirft. */
.data-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    box-shadow: inset 0 -1px 0 var(--color-border);
}

@media print {
    .data-table thead th {
        position: static;
    }
}

/* ---------------------------------------------------------------------------
   KOMPAKTE ANSICHT — inzwischen die VORGABE (partials/dichte-init.php); der
   Umschalter in der Kopfzeile schaltet sie aus, nicht mehr ein.
   Fuer Arbeitsplaetze, an denen den ganzen Tag Zeilen gelesen und angehakt
   werden. Es verschwindet nichts und es verschiebt sich nichts; nur Abstaende
   und Schriftgroessen werden knapper. Auf 1600x1000 zeigen die Offenen Posten
   damit 18 statt 13 Zeilen (vor der Umstellung waren es neun).
   --------------------------------------------------------------------------- */

/* Die kompakte Ansicht setzt die MARKEN herunter, nicht die einzelnen Regeln.
   Damit folgt ihr alles, was auf den Marken sitzt — Tabellenzeilen,
   Eingabefelder, Knoepfe, Symbolknoepfe, die Sammelliste im Zahlungsdialog —,
   und eine neue Komponente ist automatisch mit dabei.

   ALLE BEDIENELEMENTE SIND HIER 34 PX HOCH — dieselbe Zahl wie im
   Flight-Importer. Es waren einmal drei (34 / 30 / 26); was davon blieb, ist
   die eine Marke, an der alle haengen. */
[data-dichte="kompakt"] {
    --hoehe-tabellenzeile: 38px;
    /* NUR die Feldhoehe: Knopf, kleiner Knopf und Symbolknopf haengen als
       var(--hoehe-feld) daran und gehen von selbst mit (siehe :root).

       34 PX IST DIE HOEHE DES FLIGHT-IMPORTERS. Sie ist dort nicht auf den
       ersten Blick zu sehen: seine gestapelten Formularfelder haben gar keine
       gesetzte Hoehe und werden aus dem Polster 39 px hoch, seine Knoepfe sind
       34. Wo aber beides NEBENEINANDER steht — die Suchleiste —, setzt er das
       Feld ausdruecklich auf die Hoehe des Knopfes (`.search .field-input {
       height: 34px }`). 34 ist also der gemeinte Wert, und 39 nur das, was ein
       Feld ohne Nachbarn von selbst wird.

       Hier steht die Hoehe als Zahl und nicht als Polster, weil ein Datumsfeld
       mit Kalendersymbol und ein Auswahlfeld mit Pfeil sonst ihre eigene
       Zeilenhoehe mitbringen und neben einem Textfeld nicht mehr stimmen. */
    --hoehe-feld: 34px;
}

[data-dichte="kompakt"] .data-table th,
[data-dichte="kompakt"] .data-table td {
    padding: 0.15rem 0.6rem;
    font-size: 0.82rem;
}

[data-dichte="kompakt"] .data-table th {
    padding-top: 0.3rem;
    padding-bottom: 0.3rem;
}

[data-dichte="kompakt"] .stat-tile {
    padding: 0.45rem 0.8rem;
}

/* Auch kompakt bleibt die Zahl gross — hier wird an ABSTAENDEN gespart und
   nicht an der Auskunft. Die Kachel ist deshalb enger als vorher (Polster
   darueber), die Zahl darin aber nicht kleiner als eine Zeile Text. */
[data-dichte="kompakt"] .stat-value {
    font-size: 1.45rem;
}

[data-dichte="kompakt"] .search-form {
    padding: 0.55rem 0.8rem;
    margin-bottom: 0.6rem;
}

[data-dichte="kompakt"] .cards {
    gap: 0.5rem;
    /* Knapper als in der normalen Ansicht — die kompakte soll Zeilen gewinnen —,
       aber oben und unten gleich, aus demselben Grund wie dort. */
    margin-top: var(--space-3);
    margin-bottom: var(--space-3);
}

[data-dichte="kompakt"] .content > h1,
[data-dichte="kompakt"] .page-title-row h1 {
    font-size: 1.3rem;
}

[data-dichte="kompakt"] .content {
    padding: 0.8rem 1.25rem 1.25rem;
}

/* Der Umschalter selbst zeigt an, dass er greift. */
.dichte-toggle.active {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

@media print {
    .table-scroll {
        overflow: visible;
        max-height: none;
    }
}

/* ---------- Mobile menu button (hidden on desktop, shown ≤880px) ---------- */

.topbar-menu-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    cursor: pointer;
    transition: background-color var(--duration) var(--ease);
}

.topbar-menu-toggle:hover {
    background: var(--color-surface-alt);
}

.topbar-menu-toggle .icon {
    width: 18px;
    height: 18px;
    vertical-align: 0;
}

.sidebar-backdrop {
    display: none;
}

/* ---------- Detail header amounts: allow wrapping on narrow screens ---------- */

.detail-header-amounts {
    flex-wrap: wrap;
}

/* ---------- OTP boxes: fluid width so all 6 boxes always fit ---------- */

.otp-inputs {
    gap: clamp(0.3rem, 1.6vw, 0.5rem);
}

.otp-box {
    width: clamp(2rem, 12vw, 2.6rem) !important;
    height: clamp(2.3rem, 13vw, 3rem);
    font-size: clamp(1.05rem, 5.5vw, 1.4rem) !important;
}

/* ==================== Breakpoint: tablet (≤880px) — off-canvas sidebar ==================== */

@media screen and (max-width: 880px) {
    .content {
        padding: 1.25rem;
    }

    .topbar {
        flex-wrap: wrap;
        gap: 0.6rem;
        padding: 0.6rem 1rem;
    }

    .topbar-menu-toggle {
        display: inline-flex;
    }

    /* Off-canvas drawer instead of the sticky, always-visible desktop sidebar. */
    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        width: 240px;
        transform: translateX(-100%);
        z-index: 100;
        box-shadow: var(--shadow-lg);
        transition: transform 0.2s ease, background-color var(--duration) var(--ease);
    }

    html[data-sidebar-mobile="open"] .sidebar {
        transform: translateX(0);
    }

    html[data-sidebar-mobile="open"] .sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(var(--color-sidebar-overlay-rgb), 0.45);
        z-index: 90;
    }

    html[data-sidebar-mobile="open"] body {
        overflow: hidden;
    }

    /* The icon-only "collapsed rail" is a desktop affordance — on the mobile
       drawer it must always show the full menu with labels, regardless of
       whatever collapse state was last saved during a desktop session
       (same selectors as the desktop collapse rules above, repeated here so
       they win on source order at this breakpoint — width is the only thing
       that changed, not specificity). */
    html[data-sidebar="collapsed"] .sidebar {
        width: var(--breite-sidebar);
    }

    html[data-sidebar="collapsed"] .sidebar-brand {
        justify-content: space-between;
        padding: 1.125rem 1.125rem 1rem;
    }

    html[data-sidebar="collapsed"] .sidebar-brand .brand-logo {
        display: inline-flex;
    }

    html[data-sidebar="collapsed"] .menu-label {
        display: inline;
    }

    /* Zurueck auf die Masse des ausgeklappten Menues — die Regeln oben haben
       sie fuer die 64-px-Schiene ueberschrieben. */
    html[data-sidebar="collapsed"] .menu-dashboard-link {
        justify-content: flex-start;
        gap: 0.625rem;
        padding-left: 0.625rem;
        padding-right: 0.625rem;
    }

    html[data-sidebar="collapsed"] .menu-group summary {
        justify-content: flex-start;
        gap: 0.625rem;
        padding-left: 0.5rem;
        padding-right: 0.5rem;
    }

    html[data-sidebar="collapsed"] .menu-group li a {
        justify-content: flex-start;
        gap: 0.625rem;
        padding-left: 0.625rem;
        padding-right: 0.625rem;
    }

    html[data-sidebar="collapsed"] .menu-chevron {
        display: inline-block;
    }

    html[data-sidebar="collapsed"] .sidebar-footer {
        display: block;
    }

    html[data-sidebar="collapsed"] .menu-group[open] > ul {
        position: static;
        left: auto;
        top: auto;
        min-width: auto;
        background: none;
        border-radius: 0;
        box-shadow: none;
        padding: 0;
        z-index: auto;
    }

    html[data-sidebar="collapsed"] .menu-group[open] > ul li a {
        padding: 0.5rem 0.625rem;
    }

    /* Auf dem Telefon ist die Schublade das ausgeklappte Menue — die Linie der
       aktiven Gruppe gehoert also zurueck (siehe .menu-group.active > ul). */
    html[data-sidebar="collapsed"] .menu-group.active > ul {
        margin-left: 0.625rem;
        padding-left: 0.5rem;
        border-left: 2px solid var(--color-primary-soft);
    }

    /* Der Hausname kann lang sein — abschneiden, statt die Knoepfe der
       Kopfzeile aus dem Bild zu schieben.

       40vw und nicht mehr 60: mit 60 blieb fuer die sieben Knoepfe zu wenig
       uebrig, sie rutschten in eine zweite Reihe und die Kopfzeile war 107 px
       hoch statt 60. Gemessen bei 768 px. */
    .topbar-company {
        max-width: 40vw;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
}

/* ==================== Breakpoint: phone (≤560px) ==================== */

@media screen and (max-width: 560px) {
    .content {
        padding: 1rem;
    }

    .auth-card,
    .legal-card {
        padding: 1.5rem;
    }

    .chart-mini {
        height: 220px;
    }

    /* Anchored dropdown (PDF-Ansicht) doesn't have enough room to hang off its
       button on a narrow screen — pin it as a small fixed sheet near the top
       instead of letting it overflow sideways. */
    .doc-view-popup {
        position: fixed;
        top: 4.25rem;
        left: 1rem;
        right: 1rem;
        min-width: 0;
        width: auto;
        max-height: 70vh;
        overflow-y: auto;
    }

    .modal-backdrop {
        padding: 0;
    }

    .modal {
        max-width: none;
        max-height: 100vh;
        height: 100vh;
        border-radius: 0;
    }
}

/* ---------- Buchungs-Wizard (bookings/create.php) ---------- */

/* Klassen wie .export-button setzen display selbst und schlagen damit die
   [hidden]-Regel des Browser-Stylesheets — hidden muss deshalb explizit
   gewinnen, sonst bleiben ausgeblendete Buttons sichtbar. */
[hidden] {
    display: none !important;
}

.wizard-errors {
    border-left: 3px solid var(--color-danger);
    margin-bottom: 1rem;
}

.wizard-errors ul {
    margin: 0.5rem 0 0;
    padding-left: 1.1rem;
    font-size: 0.85rem;
    color: var(--color-danger-text);
}

.wizard-errors strong {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.wizard-errors strong .icon {
    flex-shrink: 0;
    color: var(--color-danger);
}

/* JEDER EINTRAG IST EIN KNOPF, der an seine Fundstelle springt. Er sieht aus
   wie der Satz, der dort vorher stand, und nicht wie ein Knopf: die Liste soll
   weiter eine Liste von Meldungen sein. Dass er anklickbar ist, sagen der
   Zeiger, die Unterstreichung beim Ueberfahren und der Hinweistext. */
.wizard-error-link {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.wizard-error-link:hover,
.wizard-error-link:focus-visible {
    text-decoration: underline;
}

/* Abgehakt, sobald in einem der bemaengelten Felder etwas geaendert wurde.
   Der Eintrag BLEIBT stehen — er verschwinden zu lassen hiesse, die Liste
   waehrend des Arbeitens umzubauen, und man verliert die Stelle, an der man
   war. Geprueft wird beim naechsten Absenden ohnehin neu. */
.wizard-error-link.erledigt {
    color: var(--color-text-subtle);
    text-decoration: line-through;
}

/* Die Meldung AM FELD. Unter einem beschrifteten Feld steht sie im Etikett,
   unter einer Leistungszeile als eigener Absatz — beides hier gleich
   aussehend, damit es dieselbe Sorte Hinweis bleibt. */
.feld-fehler {
    margin: var(--space-1) 0 0;
    font-size: 0.78rem;
    line-height: 1.35;
    color: var(--color-danger-text);
}

/* In einem Raster (oder einer Flexzeile) bekommt die Meldung eine EIGENE volle
   Zeile direkt unter dem Feld. Ohne das stuende sie in der Spalte des Feldes,
   waere dort drei Zeilen hoch und wuerde die Nachbarspalten verschieben. */
.form-grid > .feld-fehler,
.vorgang-kopf > .feld-fehler {
    grid-column: 1 / -1;
    flex: 1 0 100%;
    margin-top: calc(-1 * var(--space-2));
}

/* Ein bemaengeltes Feld traegt aria-invalid — daran haengt auch das Aussehen.
   EINE Quelle fuer beides: ein Rahmen ohne aria-invalid waere eine Markierung,
   die nur Sehende bemerken, und ein aria-invalid ohne Rahmen eine, die nur
   Vorlesehilfen bemerken. */
.wizard-panel [aria-invalid="true"] {
    border-color: var(--color-danger);
    background: var(--color-danger-soft);
}

/* Der ROTE Fokusrahmen muss den allgemeinen blauen schlagen. Ueber die
   Formularkennung (#wizard-form) statt ueber die Klasse: die gemeinsame
   Feldregel nennt vier Klassen und gewinnt sonst mit ihrer Staerke, und dann
   saehe ein bemaengeltes Feld beim Hineinklicken aus wie jedes andere. */
#wizard-form [aria-invalid="true"]:focus {
    border-color: var(--color-danger);
    box-shadow: 0 0 0 3px var(--color-danger-soft);
}

/* Fehlermarke an der Schrittleiste: Zeichen UND Zahl. Die Farbe kommt dazu,
   sie traegt die Aussage nicht allein. */
.wizard-step-fehler {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.15rem;
    color: var(--color-danger-text);
    font-size: 0.78rem;
    font-weight: 600;
}

.wizard-step-fehler .icon {
    width: 14px;
    height: 14px;
}

.wizard-step.hat-fehler .wizard-step-no {
    border-color: var(--color-danger);
    color: var(--color-danger-text);
}

/* ---------------------------------------------------------------------------
   Schrittleiste des Buchungsassistenten (create.php)

   Vorher vier Pillen, der aktive Schritt ganz violett gefuellt. Jetzt eine
   Leiste in einer Karte: Nummernkreis, daneben zweizeilig Name und Inhalt,
   dazwischen eine Linie. Der Unterschied ist nicht nur Geschmack — die Pillen
   standen gleichberechtigt nebeneinander und sagten nicht, dass es eine ABFOLGE
   ist. Die Linie tut das, und die zweite Zeile sagt, was hinter jedem Schritt
   liegt, ohne dass man hineinklicken muss.

   Nur der Kreis ist beim aktiven Schritt gefuellt, nicht die ganze Fläche: bei
   vier Schritten war ein violetter Block ein Drittel der Leiste und zog den
   Blick von den Feldern darunter weg.
   --------------------------------------------------------------------------- */
.wizard-steps {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0;
    list-style: none;
    margin: 1.25rem 0;
    /* Die Karte bringt ihr eigenes Innenmass mit; hier nur die Liste zuruecksetzen. */
    padding: 1rem 1.4rem;
}

.wizard-step {
    display: flex;
    align-items: center;
    color: var(--color-text-muted);
    transition: color var(--duration) var(--ease);
}

/* Der Schritt selbst ist ein KNOPF (siehe create.php): das Aussehen bleibt, wie
   es war — die Knopfvorgaben des Browsers werden dafuer abgeraeumt. Er traegt
   die Reihe aus Kreis und Text, die vorher das <li> getragen hat. */
.wizard-step-knopf {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

/* Gesperrter Schritt: nicht anklickbar, aber auch nicht ausgegraut bis zur
   Unlesbarkeit — er sagt weiterhin, was dort kommt. */
.wizard-step-knopf:disabled {
    cursor: default;
    opacity: 0.75;
}

.wizard-step-knopf:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 3px;
    border-radius: var(--radius);
}

/* Die Verbindungslinie gehoert zum FOLGENDEN Schritt und wird ueber ::before
   gezeichnet — kein zusaetzliches Element im Markup, damit die Liste vier
   Kinder behaelt und das Skript weiter ueber `.wizard-step` zaehlen kann.

   Der Schritt darf dafuer wachsen (flex: 1), die Linie darin nimmt den Platz
   auf. Der erste Schritt wächst nicht, sonst stünde er nicht am linken Rand. */
.wizard-step + .wizard-step {
    flex: 1 1 auto;
    min-width: 0;
}

.wizard-step + .wizard-step::before {
    content: '';
    flex: 1 1 auto;
    /* Nie ganz verschwinden: bei vier langen Beschriftungen bliebe sonst ein
       Strich von zwei Pixeln, der wie ein Zeichenfehler aussieht. */
    min-width: 1.5rem;
    height: 1px;
    margin-right: 0.7rem;
    background: var(--color-border);
}

.wizard-step-no {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: 0.82rem;
    font-weight: 600;
    transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.wizard-step-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
}

/* Name des Schritts: klein und gesperrt, damit die zweite Zeile die groessere
   von beiden bleibt — gelesen wird "was steht hier drin", die Nummer ordnet nur
   ein. */
.wizard-step-name {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.wizard-step-sub {
    font-size: 0.88rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.wizard-step.active .wizard-step-no {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
}

.wizard-step.active .wizard-step-name {
    color: var(--color-primary);
}

.wizard-step.active .wizard-step-sub {
    color: var(--color-text);
}

/* Erledigter Schritt: der Kreis bleibt gefuellt, aber blass — er ist erreichbar
   und war schon dran, konkurriert aber nicht mit dem aktuellen um den Blick. */
.wizard-step.done .wizard-step-no {
    border-color: var(--color-primary);
    background: var(--color-primary-soft);
    color: var(--color-primary);
}

.wizard-step.done .wizard-step-sub {
    color: var(--color-text);
}

/* Auf schmalen Fenstern untereinander: vier zweizeilige Beschriftungen neben
   drei Linien gehen quer nicht auf. Die Linien fallen dann weg — untereinander
   verbinden sie nichts mehr. */
@media (max-width: 900px) {
    .wizard-steps {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.75rem;
    }

    .wizard-step + .wizard-step {
        flex: 0 0 auto;
    }

    .wizard-step + .wizard-step::before {
        display: none;
    }
}

.wizard-panel {
    display: none;
}

/* Beim Schrittwechsel bekommt die Ueberschrift des neuen Schritts den Fokus
   (create.php) — sonst bliebe er auf "Weiter", und die naechste Tabulatortaste
   liefe an allem vorbei, was gerade erschienen ist.

   SICHTBAR ist der Rahmen nur bei Tastaturbedienung: `:focus-visible` greift
   bei einem programmatisch gesetzten Fokus nicht, wenn gerade mit der Maus
   gearbeitet wird. Ohne diese Unterscheidung staende nach jedem Klick auf
   "Weiter" ein Kasten um die Ueberschrift. */
.wizard-panel [tabindex="-1"]:focus {
    outline: none;
}

.wizard-panel [tabindex="-1"]:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 4px;
    border-radius: var(--radius);
}

.wizard-panel.active {
    display: block;
}

.wizard-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.wizard-section-head h2,
.wizard-section-head h3 {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 0.45rem;
}

.wizard-section-head h3 {
    font-size: 0.95rem;
    color: var(--color-text);
}

.wizard-hint {
    margin: 0.4rem 0 0.9rem;
    font-size: 0.82rem;
    color: var(--color-text-muted);
}

/* Vollbreites Feld (Notizen) innerhalb des auto-fit-Grids. */
.wizard-notes label {
    grid-column: 1 / -1;
}

/* ═══════════════════════════════════════════════════════════════════════════
   RECHTE SPALTE IN SCHRITT 1: Reisedaten oben, Bemerkungen darunter
   ═══════════════════════════════════════════════════════════════════════════
   Die Bemerkungen-Karte DEHNT SICH bis auf die Hoehe des Anmelders links. Ohne
   das blieb rechts unter den Reisedaten eine Luecke stehen — die Reisedaten
   brauchen eine Feldzeile, der Anmelder fuenf.

   Vier Stufen, und jede ist noetig, weil Hoehe in CSS nicht von sich aus
   durchreicht: die Karte waechst in der Spalte (flex: 1), wird selbst eine
   Flexspalte, das Raster darin waechst mit, und das Textfeld fuellt es.

   Nur in DIESER Spalte (.wizard-kopf-spalte): .detail-info-col steht auch im
   Buchungsdetail, und dort sollen die Karten ihre natuerliche Hoehe behalten
   (.detail-info-col .card { flex: none }).
   ═══════════════════════════════════════════════════════════════════════════ */
.wizard-kopf-spalte > .card:last-child {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
}

.wizard-kopf-spalte > .card:last-child .wizard-notes {
    flex: 1 1 auto;
}

/* Das Raster ist einspaltig (.wizard-notes label spannt 1/-1), die Zeile darf
   also die ganze Hoehe nehmen. */
.wizard-kopf-spalte > .card:last-child .wizard-notes label {
    height: 100%;
}

.wizard-kopf-spalte > .card:last-child textarea {
    height: 100%;
    /* Nicht kleiner als die zwei Zeilen, die rows="2" vorgibt — sonst
       schrumpfte das Feld auf schmalem Schirm, wo die Spalte umbricht und keine
       Hoehe mehr zu verteilen ist. */
    min-height: 3.5rem;
    resize: vertical;
}

/* Leistungszeile (Schritt 2): neun Felder in EINER Zeile.
   ---------------------------------------------------------------------------
   FLEX und nicht Grid, aus demselben Grund wie bei .reisedaten-zeile: die
   Breiten sind hier sehr verschieden, und eine Flexzeile bricht von selbst um,
   wenn das Fenster nicht mehr reicht — ohne dass eine Bruchstelle als Zahl im
   Stylesheet stehen muss, die beim naechsten neuen Feld nicht mehr stimmt.

   NICHT gleich breit: die Auswahllisten tragen Reiseartnamen und Lieferanten
   ("TK – Turkish Airlines") und brauchen Platz, ein Zaehlfeld fuer Babys
   braucht zwei Stellen. Gleich breit bekam das Zaehlfeld genauso viel wie die
   Auswahl, und die Auswahl wurde dabei zu schmal fuer ihre Eintraege.

   Datum und Zaehlfelder haben FESTE Breiten, die Bemerkung nimmt den Rest —
   dieselbe Idee wie .zeitspalten in den Leistungsbloecken. */
.vorgang-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
}

/* Vorgabe: mitwachsen, aber nicht unter zehn Zeichen fallen. Gilt fuer die
   Auswahllisten und die PNR. */
.vorgang-kopf > label {
    flex: 1 1 10rem;
    min-width: 0;
}

.vorgang-kopf > label:has(input[type="date"]) {
    flex: 0 0 var(--feld-datum);
}

.vorgang-kopf > label:has(input[type="number"]) {
    flex: 0 0 var(--feld-zahl);
}

/* Die Bemerkung waechst DOPPELT so schnell wie die Auswahllisten: sie ist die
   einzige Freitextangabe der Zeile, alle uebrigen haben eine bekannte Laenge. */
.vorgang-kopf > .feld-flex {
    flex: 2 1 12rem;
}

/* Anmelder-Karte: fuenf Zeilen, je ein Raster mit ENTSCHIEDENEN Spaltenbreiten
   (siehe den Kommentar an der Karte in create.php).

   Erste Spalte durchgehend --feld-anrede, damit "Anmelder" und "Anrede"
   dieselbe Breite haben und die linke Kante ueber alle Zeilen steht. Was
   danebensteht, nimmt den Rest: der gewaehlte Kunde, der Name, der Ort, die
   E-Mail — alles Angaben, die lang werden koennen. */
.anmelder-zeile1 {
    grid-template-columns: var(--feld-anrede) minmax(0, 1fr);
}

.anmelder-zeile2 {
    grid-template-columns: var(--feld-anrede) minmax(0, 1fr) minmax(0, 1fr);
}

/* Land nur so breit wie sein Kuerzel, PLZ fuenf Stellen, der Ort bekommt den
   Rest — ein Ortsname ist von den dreien der einzige, der lang wird. */
.anmelder-zeile3 {
    grid-template-columns: var(--feld-land) var(--feld-plz) minmax(0, 1fr);
}

.anmelder-zeile4 {
    grid-template-columns: minmax(0, 1fr);
}

/* Reisedaten-Zeile: Status, (Optionsfrist), Buchungsdatum, Erfasst.
   ---------------------------------------------------------------------------
   FLEX und nicht Grid — der Grund steht am Markup in create.php: die
   Optionsfrist erscheint nur bei einer Option, und in einem Raster mit festen
   Spalten waere "Erfasst" beim Einblenden aus der flexiblen Spur gerutscht.

   .form-grid bleibt am Element, weil dessen gap und die Label-Form gebraucht
   werden; nur die Anordnung wird hier ueberschrieben. */
.reisedaten-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
}

/* Vorgabe fuer die festen Felder: so breit wie ein Datum. Das Buchungsdatum
   braucht genau das, und mehr steht in keinem der drei. */
.reisedaten-zeile > label {
    flex: 0 0 var(--feld-datum);
    min-width: 0;
}

.reisedaten-zeile > .feld-status {
    flex: 0 0 var(--feld-status);
}

.reisedaten-zeile > #opt-datum-feld {
    flex: 0 0 var(--feld-frist);
}

/* Erfasst nimmt, was uebrig ist. Der Anwendername ist kurz ("admin"), aber das
   Feld ist das letzte in der Zeile — laesst man es fest, endet die Zeile mit
   einer Luecke, und die sieht aus wie ein Feld, das nicht geladen hat. */
.reisedaten-zeile > .feld-flex {
    flex: 1 1 8rem;
}

.anmelder-zeile5 {
    grid-template-columns: var(--feld-telefon) minmax(0, 1fr);
}

/* Schmales Fenster: feste Breiten passen nicht mehr nebeneinander, jede Angabe
   bekommt eine eigene Zeile. Untereinander braucht keine Kante mehr zu stimmen. */
@media (max-width: 700px) {
    .anmelder-zeile1,
    .anmelder-zeile2,
    .anmelder-zeile3,
    .anmelder-zeile5 {
        grid-template-columns: minmax(0, 1fr);
    }
}

.wizard-row {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.9rem 1rem 1rem;
    margin-top: 0.9rem;
    background: var(--color-bg);
}

/* Untergeordnete Zeilen (Flug/Hotel innerhalb eines Vorgangs) heben sich durch
   die Flächenfarbe ab, damit die Verschachtelung sichtbar bleibt. */
.wizard-row-sub {
    background: var(--color-surface);
}

/* Kopf einer Blockzeile: links die Leistungsnummer, RECHTS die Knoepfe.

   `space-between` verteilte alles gleichmaessig ueber die Breite — mit drei
   Auswahlknoepfen (Hotel, Zimmer, Verpflegung) standen sie quer ueber die
   ganze Zeile verstreut, jeder an einer anderen Stelle. Jetzt bilden sie eine
   Gruppe am rechten Rand: der erste Knopf schiebt sich mit `margin-left: auto`
   dorthin, die uebrigen folgen ihm im Abstand des gap. */
.wizard-row-head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: 0.75rem;
}

/* Alles ab dem ersten Knopf steht rechts — egal ob das die Auswahlknoepfe sind
   (Hotel) oder gleich die Zeilenaktionen (Bahn, Bus, ohne Auswahl). */
.wizard-row-head > .auswahl-knopf:first-of-type,
.wizard-row-head > .row-actions:first-of-type {
    margin-left: auto;
}

.wizard-row-title {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text);
    white-space: nowrap;
}

/* Was in der Zeile steht, im Kopf: leiser als der Titel und einzeilig. Sie ist
   eine Wiedererkennung, keine Zusammenfassung — laeuft sie ueber, wird sie
   abgeschnitten statt die Kopfzeile umzubrechen. */
.wizard-row-kopfinfo {
    min-width: 0;
    overflow: hidden;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Eine EINZELNE Zeilenaktion (der Papierkorb an Leistung und Reisendem) steht
   rechts wie die Knopfgruppen der uebrigen Kopfzeilen — vorher klebte sie am
   Titel, und damit stand dieselbe Aktion je nach Block an einer anderen
   Stelle. Kopfzeilen mit Auswahlknoepfen regelt die Regel darueber; dort ist
   der Papierkorb nicht der erste Knopf. */
.wizard-row-head > .row-action:first-of-type {
    margin-left: auto;
}

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

.wizard-sub {
    margin-top: 1.1rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--color-border);
}

/* Navigation des Assistenten: ALLE Knoepfe rechts.

   Vorher standen "Zurueck" und "Weiter" links und nur "Speichern" wurde per
   margin-left:auto nach rechts geschoben. Damit lagen die Knoepfe eines
   Vorgangs an zwei Enden des Bildschirms, und im letzten Schritt sprang die
   Reihe von links nach rechts.

   Rechts, weil dort auch die Knoepfe der Dialoge stehen (.zahlung-dialog-actions)
   und die Werkzeugleisten der Listen — die Stelle, an der man in dieser
   Anwendung nach der naechsten Aktion sucht. */
.wizard-nav {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
    margin: var(--space-6) 0 var(--space-8);
    flex-wrap: wrap;
}

/* ABBRECHEN steht LINKS und abgesetzt, die weiterfuehrenden Aktionen rechts.
   Als Textlink und nicht als Knopf: es ist der Ausgang, nicht der Weg — und
   drei gleich aussehende Knoepfe nebeneinander machen den einen, auf den es
   ankommt ("Weiter", "Buchung speichern"), zu einem von dreien. */
.wizard-abbrechen {
    margin-right: auto;
    color: var(--color-text-muted);
    font-size: 0.9rem;
    text-decoration: none;
}

.wizard-abbrechen:hover,
.wizard-abbrechen:focus-visible {
    color: var(--color-text);
    text-decoration: underline;
}

/* Kontrollschritt: Ueberschrift links, "Bearbeiten" rechts — an JEDER Karte an
   derselben Stelle, damit man den Verweis nicht sucht. */
.kontroll-kartenkopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.kontroll-kartenkopf > h2 {
    margin: 0;
}

.wizard-edit-link {
    flex-shrink: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-primary);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.wizard-edit-link:hover,
.wizard-edit-link:focus-visible {
    text-decoration: underline;
}

/* Die Hinweiskarte steht VOR der Zusammenfassung: sie sagt, worauf zu sehen
   ist. Die Punkte darin sehen aus wie die offenen Punkte der zweiten
   Buchungsansicht (.hinweispunkt) — es ist dieselbe Sorte Aussage. */
.kontroll-hinweise {
    margin-bottom: var(--space-4);
}

.kontroll-leer {
    margin: var(--space-2) 0 0;
    color: var(--color-text-muted);
}


/* Der "hinzufügen"-Button darf im space-between-Kopf nicht schrumpfen, sonst
   bricht seine Beschriftung um und läuft aus der Karte heraus. */
.wizard-section-head > button {
    flex-shrink: 0;
    white-space: nowrap;
}

/* GROSS ANGEZEIGT, waehrend man tippt — fuer alle Felder, die auch gross
   GESPEICHERT werden (Typ 'upper': Flughafen VON/NACH, Airline, Klasse, Status,
   PNR). Ohne das stand im Feld "ist" und nach dem Speichern "IST".

   BlockField::input() vergibt die Klasse am TYP, nicht an einer Liste von
   Feldnamen — was gross gespeichert wird, wird gross gezeigt. */
.input-gross {
    text-transform: uppercase;
}

/* Kurzcode-Felder (Flughafen VON/NACH im Assistenten): dasselbe, zusaetzlich
   ein Breitendeckel — ein Flughafencode hat drei Zeichen. */
.input-code {
    text-transform: uppercase;
    max-width: 7rem;
}

/* PNR ist ein Kurzcode-Feld (gross dargestellt), aber KEIN Kurzcode: der
   Buchungscode einer Gesellschaft hat sechs Zeichen und mehr. Der Breitendeckel
   von .input-code — 7 rem, gedacht fuer DUS/AYT/XQ — muss deshalb weg.

   Sonst flext die SPALTE und das FELD darin nicht: die Rasterspur wird breiter,
   das Eingabefeld bleibt bei 7 rem stehen und laesst rechts eine Luecke. Genau
   so ist es aufgefallen. */
.input-pnr {
    max-width: none;
}

/* Datensatz-Zeilen im Wizard (Passagiere, Flüge): je Datensatz genau EINE Zeile,
   die Beschriftungen stehen einmalig als Kopfzeile darüber. Kopf- und Datenzeile
   teilen dasselbe Grid-Template, damit die Spalten exakt untereinander stehen —
   das Template selbst kommt aus der jeweiligen Modifier-Klasse unten. */
.row-grid-head,
.row-grid {
    display: grid;
    gap: 0.5rem;
    align-items: center;
}

.row-grid-head.cols-pax,
.row-grid.cols-pax {
    grid-template-columns: 7rem 1.4fr 1.4fr 9.5rem 1fr 6.5rem 6.5rem 7.5rem 2rem;
}

/* Durchgehend feste Breiten (kein 1fr): die Zeile besteht fast nur aus kurzen
   Codes, eine mitwachsende Spalte würde unverhältnismäßig breit werden. Die
   Zeitspalten sind großzügig bemessen, weil <input type="time"> je nach
   Browsersprache auch "06:45 AM" darstellen muss. */
/* DREIZEHN SPUREN, nicht zwoelf:
   Lfnr, Datum, Von, Nach, Ab, An, Airline, Flugnr., PNR, Klasse, Sitze, Status,
   Aktion.

   Die LFNR fehlte. Der Blockeditor (Buchungsdetail) stellt sie vorne dazu, das
   Raster kannte sie nicht — die dreizehnte Zelle (die Zeilenaktionen) rutschte
   damit in eine zweite Rasterzeile und war nicht mehr zu sehen, und die
   Beschriftungen im Kopf standen um eine Spalte versetzt: "PNR" lag ueber
   "Klasse" und die beiden Woerter ueberdeckten sich.

   Die PNR ist die einzige Spur mit 1fr — sie traegt einen Buchungscode der
   Gesellschaft von wechselnder Laenge, alle uebrigen Felder haben eine bekannte.
   Ihr MINDESTMASS ist neu (5rem statt 0): bei minmax(0, 1fr) fiel sie auf null
   zusammen, sobald der Platz knapp wurde, und die Beschriftung lief in die
   Nachbarspalte.

   min-width: die Summe der festen Spuren. Passt die Zeile nicht in die Karte,
   rollt die Karte waagerecht (siehe .flug-karte) — vorher wurde sie schmaler
   gequetscht, bis Felder uebereinander lagen und der letzte abgeschnitten war. */
.row-grid-head.cols-flug,
.row-grid.cols-flug {
    /* FLUGNUMMER 7rem statt 5.5: die Spur war 80 px breit, ihre Ueberschrift
       braucht 88 — gemessen. Die fehlenden acht Pixel liefen in den Spalten-
       abstand, und im Kopf stand "FLUGNUMMERPNR" als ein Wort. Nicht die
       Ueberschrift kuerzen: "Flugnr." waere eine Abkuerzung, die man erst
       lernen muss, und die Spalte daneben ist die PNR — verwechseln kostet ein
       Telefonat mit der Gesellschaft. */
    grid-template-columns: 3.5rem var(--feld-datum) 4rem 4rem var(--feld-zeit) var(--feld-zeit)
        4.5rem 7rem minmax(4.5rem, 1fr) 4rem 3.5rem 4rem 2.5rem;
    min-width: 64.5rem;
    justify-content: start;
}

/* ═══════════════════════════════════════════════════════════════════════════
   FLUGZEILE IM ASSISTENTEN — ZWOELF SPUREN, OHNE LAUFNUMMER
   ═══════════════════════════════════════════════════════════════════════════
   Die allgemeine Regel oben beginnt mit der LAUFNUMMER (3.5rem): im
   Buchungsdetail steht sie vorn, weil eine Flugzeile dort zu einer Leistung
   gehoert. Im Assistenten gehoert die Zeile immer zu DER Leistung, in deren
   Block sie steht — sie hat keine Laufnummernspalte, und ihr Kopf hat zwoelf
   Zellen statt dreizehn.

   Gegriffen hat trotzdem die dreizehnspurige Regel. Damit sass jede Zelle eine
   Spur zu weit links: das Datumsfeld in den 3.5rem der Laufnummer (im Bild
   stand darin "01." und der Rest war abgeschnitten), die Ueberschrift
   "Flugnummer" in einer 4.5rem-Spur, und "PNR" klebte daran. Gemessen: 72 px
   Spur fuer eine Ueberschrift, die 88 braucht.

   Deshalb hier dieselben Spuren wie oben, nur ohne die erste. */
#wizard-form .row-grid-head.cols-flug,
#wizard-form .row-grid.cols-flug {
    grid-template-columns: var(--feld-datum) 4rem 4rem var(--feld-zeit) var(--feld-zeit)
        4.5rem 7rem minmax(4.5rem, 1fr) 4rem 3.5rem 4rem 2.5rem;
    min-width: 61rem;
}

/* Ohne die letzte Spur — fuer Kopf und Zeile des Neu-Formulars, dessen
   Speichern-Knopf eine eigene Zeile darunter hat. */
.row-grid-head.cols-flug.row-grid-ohne-aktion,
.row-grid.cols-flug.row-grid-ohne-aktion {
    grid-template-columns: 3.5rem var(--feld-datum) 4rem 4rem var(--feld-zeit) var(--feld-zeit)
        4.5rem 7rem minmax(4.5rem, 1fr) 4rem 3.5rem 4rem;
    min-width: 62rem;
}

/* WIEDERVORLAGE im Buchungsdetail: Notiz, Termin, Zustaendig, Erledigt,
   Loeschen.

   Die NOTIZ nimmt den freien Platz — sie traegt den Satz, alles andere traegt
   eine kurze Angabe. minmax(0, 1fr) und nicht 1fr: sonst waechst die Spalte mit
   ihrem laengsten Inhalt statt umzubrechen, und die Zeile laeuft rechts aus dem
   Block heraus.

   Die beiden letzten Spalten sind so breit wie ihre Knoepfe. */
.row-grid-head.cols-aufgabe,
.row-grid.cols-aufgabe {
    grid-template-columns: minmax(0, 1fr) 10.5rem 8rem 5rem 2.5rem;
}

/* Die Notiz darf umbrechen — der zweite Teil (die laengere Bemerkung) steht
   ohnehin als eigene Zeile darunter (.zell-zweite). */
.cols-aufgabe .aufgabe-text {
    min-width: 0;
    overflow-wrap: anywhere;
}

.row-grid-head {
    margin-top: 1rem;
    padding: 0 0 0.4rem;
    border-bottom: 1px solid var(--color-border);
    /* Wie .data-table th — siehe die Begruendung dort. */
    font-family: var(--schrift-cond);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

.row-grid {
    padding: 0.45rem 0;
    border-bottom: 1px solid var(--color-border);
}

.row-grid input,
.row-grid select {
    width: 100%;
    min-width: 0;
    font-family: inherit;
    font-size: 0.85rem;
}

/* Berechnete/feste Werte: sichtbar nicht editierbar, aber lesbar (nicht ausgegraut
   wie ein deaktiviertes Feld sonst wirkt). */
.input-readonly {
    background: var(--color-bg) !important;
    color: var(--color-text) !important;
    font-weight: 500;
    cursor: default;
    opacity: 1;
}

@media (max-width: 1400px) {
    /**
     * ────────────────────────────────────────────────────────────────────────
     * KOPFZEILE WEG — ABER NUR, WO DIE ZEILE DARUNTER AUCH UMBRICHT
     * ────────────────────────────────────────────────────────────────────────
     * Hier stand `.row-grid-head { display: none }` fuer ALLE Kopfzeilen. Das
     * passte zu der Regel gleich darunter, die cols-pax und cols-flug in zwei
     * Spalten umbricht: umgebrochene Felder tragen ihre Bedeutung im aria-label,
     * eine Kopfzeile darueber waere falsch zugeordnet.
     *
     * Es passte aber NICHT zu den Zeilen, die in dieser Breite einzeilig
     * bleiben, weil sie eigene Spaltenbreiten mit mehr Gewicht haben — die
     * Flugzeilen im Buchungsdetail (.block-editor, drei Klassen) und im
     * Assistenten (#wizard-form, Kennung). Die standen zwischen 1201 und 1400 px
     * als Reihe von zwoelf Feldern OHNE JEDE BESCHRIFTUNG da. Gemessen bei
     * 1350 px: Kopfzeile 0 px hoch, Zeile weiterhin zwoelf Spalten.
     *
     * Deshalb: verborgen wird namentlich, was umbricht — und die beiden
     * Ausnahmen holen sich ihre Kopfzeile zurueck. Unter 1200 px nimmt sie ihnen
     * die Regel bei .block-editor wieder weg, dort bricht die Zeile dann auch um.
     */
    .row-grid-head.cols-pax,
    .row-grid-head.cols-flug,
    .row-grid-head.cols-preis {
        display: none;
    }

    .block-editor .row-grid-head.cols-flug,
    #wizard-form .row-grid-head.cols-flug {
        display: grid;
    }

    .row-grid.cols-pax,
    .row-grid.cols-flug {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        padding: 0.75rem 0;
    }
}

/* Feste Spaltenzahl je Zeile im Wizard. .form-grid verteilt sonst per auto-fit
   nach verfügbarer Breite — in der schmalen Reisedaten-Karte würde eine
   Dreier-Zeile dadurch als 2+1 umbrechen und die vorgegebene Zeilenstruktur
   (Status|Agentur / Datum×3 / Pax×3 / Bemerkung) zerfallen. */
/* Eine Spalte: für Felder, die allein über die volle Breite laufen (Bemerkung,
   Extras). Ohne diese Regel griffe der auto-fit-Default von .form-grid — der
   liefert bei einem einzelnen Feld zwar zufällig dasselbe Ergebnis, aber sobald
   ein zweites Feld in die Reihe käme, stünde es unerwartet daneben. */
.form-grid.cols-1 {
    grid-template-columns: 1fr;
}

.form-grid.cols-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.form-grid.cols-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.form-grid.cols-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.form-grid.cols-5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

.form-grid.cols-6 {
    grid-template-columns: repeat(6, minmax(0, 1fr));
}

/* Sieben bis neun Spalten: für Blöcke, deren Felder in möglichst wenige Zeilen
   sollen (Bahn, Bus, Transfer und Fähre mit neun, Hotel mit acht, Leistung und
   Versicherung mit sieben). Bei weniger Spalten bräche die Zeile um und die
   gewonnene Kompaktheit wäre wieder aufgezehrt. */
.form-grid.cols-7 {
    grid-template-columns: repeat(7, minmax(0, 1fr));
}

.form-grid.cols-8 {
    grid-template-columns: repeat(8, minmax(0, 1fr));
}

.form-grid.cols-9 {
    grid-template-columns: repeat(9, minmax(0, 1fr));
}

/* ---------------------------------------------------------------------------
   Feldreihen, die mit Datums- und Zeitfeldern beginnen (Hotel, Transfer, Bahn,
   Bus, Faehre, Extras, Mietwagen, Versicherung). Die Abfolge der Breiten stellt
   _block-editor.php aus den Feldtypen zusammen und uebergibt sie als --spalten;
   die Werte selbst stehen oben bei den Farbvariablen.

   Felder unten ausgerichtet: laengere Beschriftungen brauchen zwei Zeilen, und
   ohne das saesse ihr Eingabefeld tiefer als das der Nachbarn.
   --------------------------------------------------------------------------- */
.form-grid.zeitspalten {
    grid-template-columns: var(--spalten);
    align-items: end;
}

/* Gruppe "Das Hotel": hinter dem Hotelcode steht der Auswahlknopf, und der
   braucht keine ganze Spalte. Der Hotelname bekommt den freien Platz, die
   Kategorie ("4*") kaum. */
.form-grid.hotel-stammdaten {
    grid-template-columns:
        8.5rem               /* Hotelcode samt Auswahlknopf */
        minmax(9rem, 2fr)    /* Hotel */
        5rem                 /* Kategorie */
        minmax(6rem, 1fr)    /* Land */
        minmax(6rem, 1fr)    /* Region */
        minmax(6rem, 1fr);   /* Zielgebiet */
    align-items: end;
}

/* Gruppe "Unterbringung": "Zimmer" und "Verpflegung" tragen Klartext
   ("Doppelzimmer", "All Inclusive") und bekommen den freien Platz; die zwei
   Kuerzel und die drei Belegungszahlen brauchen wenig und bleiben schmal.

   Die beiden Kuerzelspalten sind SCHMALER als frueher: sie trugen einen
   Auswahlknopf am Feld, der ist jetzt oben im Kopf der Zeile. */
.form-grid.hotel-unterbringung {
    grid-template-columns:
        4.75rem              /* Anzahl */
        5rem                 /* Zimmer Kuerzel */
        minmax(8rem, 1.6fr)  /* Zimmer */
        5rem                 /* Verpflegung Kuerzel */
        minmax(8rem, 1.6fr)  /* Verpflegung */
        5rem 5rem 5rem;      /* Erwachsene, Kinder, Babys */
    /* Die Felder unten ausrichten: "Verpflegung Kuerzel" braucht zwei Zeilen
       Beschriftung, und ohne das saesse sein Eingabefeld tiefer als die Nachbarn —
       die Reihe sah aus wie zwei halbe Reihen. */
    align-items: end;
}

/* Viele Spalten brauchen Breite — darunter erst auf drei, dann auf eine. */
@media (max-width: 1200px) {
    .form-grid.cols-5,
    .form-grid.cols-6,
    .form-grid.cols-7,
    .form-grid.cols-8,
    .form-grid.cols-9,
    .form-grid.hotel-stammdaten,
    .form-grid.hotel-unterbringung {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .form-grid.cols-4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Die Zeitraum-Reihen behalten ihre festen Breiten: Datum und Uhrzeit
       brauchen zusammen rund 520 Pixel und passen damit auch auf ein kleines
       Notebook — drei oder zwei gleiche Spalten waeren hier BREITER statt
       schmaler, und genau das sollten die festen Breiten abstellen.

       Diese Regel steht bewusst NACH cols-4/cols-5: sie ist gleich stark, und
       im Zweifel soll die spaetere gewinnen. Eine Reihe traegt beide Klassen
       (`form-grid cols-4 zeitspalten`). */
    .form-grid.zeitspalten {
        grid-template-columns: var(--spalten);
    }
}

/* Schmales Fenster: die feste Abfolge waere jetzt breiter als der Inhaltsbereich.
   Statt sie zu strecken, laufen die Felder paarweise um — Datum mit seiner
   Uhrzeit, darunter das naechste Paar. Die Breiten bleiben dieselben. */
@media (max-width: 980px) {
    .form-grid.zeitspalten {
        grid-template-columns: var(--feld-datum) var(--feld-zeit);
    }
}

@media (max-width: 720px) {
    .form-grid.cols-2,
    .form-grid.cols-3,
    .form-grid.cols-4,
    .form-grid.cols-5,
    .form-grid.cols-6,
    .form-grid.cols-7,
    .form-grid.cols-8,
    .form-grid.cols-9,
    .form-grid.hotel-stammdaten,
    .form-grid.hotel-unterbringung,
    .form-grid.zeitspalten {
        grid-template-columns: 1fr;
    }
}

/* ---------- Auswahl-Popup (Kundenauswahl im Buchungs-Wizard) ---------- */

.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 4rem 1rem 2rem;
    background: rgba(15, 20, 40, 0.45);
    overflow-y: auto;
}

.modal-box {
    width: min(920px, 100%);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: 0 18px 48px rgba(15, 20, 40, 0.28);
}

.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--color-border);
}

.modal-head h2 {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    font-size: 1.05rem;
}

.modal-body {
    padding: 1.25rem;
}

/* Ein Feldraster gleich unter einem Hinweistext braucht Luft — sonst klebt die
   Beschriftung des ersten Feldes am Satz darueber. */
.modal-body .form-hint + .form-grid,
.modal-body .form-hint + .export-wahl {
    margin-top: var(--space-4);
}

.modal-search {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.modal-search input {
    flex: 1;
    min-width: 0;
    font-family: inherit;
    font-size: 0.9rem;
}

/* Trefferliste begrenzen, damit Kopf- und Fußbereich des Dialogs sichtbar bleiben. */
.modal-results {
    max-height: 45vh;
    overflow-y: auto;
}

.modal-foot {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

.modal-error {
    margin: 0.75rem 0 0;
    color: var(--color-danger-text);
    font-size: 0.85rem;
}

/* Anklickbare Ergebniszeile (Kundenauswahl) */
.row-clickable {
    cursor: pointer;
}

.row-clickable:hover {
    background: var(--color-primary-soft);
}

/* Feld mit direkt anschließendem Aktionsknopf (z. B. Kunde + Suche-Button) */
.input-with-button {
    display: flex;
    gap: 0.4rem;
    align-items: stretch;
}

.input-with-button input {
    flex: 1;
    min-width: 0;
}

.input-with-button .export-button {
    flex-shrink: 0;
    padding: 0.45rem 0.6rem;
}

/* Verkaufs- und Einkaufspreise nebeneinander unter jeder Leistung. */
.preis-blocks {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
}

/* Verkauf und Einkauf sind zwei eigene Bloecke IM Rahmen der Leistung — dieselbe
   Behandlung wie im Buchungsdetail (.vk-ek-block), und aus demselben Grund:
   eigene weisse Flaeche auf dem grauen Grund der Leistung, eigener Rahmen,
   Kopfzeile mit Trennlinie.

   Ohne das gingen sie in der grauen Flaeche unter — man sah eine lange Reihe von
   Feldern und musste an den Ueberschriften ablesen, wo der eine Block endet und
   der andere beginnt. Der Assistent hatte das noch nicht; das Detail schon.

   overflow-x ebenfalls uebernommen: acht Spalten in halber Breite werden eng,
   und waagerecht scrollen ist besser, als eine Spalte unlesbar zu quetschen. */
/* DER PREISBLOCK — im Buchungsassistenten (.preis-block) und im Blockeditor
   der Buchungsmaske (.vk-ek-block) dasselbe: eine Flaeche mit Rahmen, die bei
   schmalem Fenster seitlich rollt statt die Maske zu sprengen. Es waren zwei
   Regeln mit demselben Rumpf, an zwei weit auseinanderliegenden Stellen der
   Datei. */
.preis-block,
.vk-ek-block {
    min-width: 0;
    overflow-x: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.7rem 0.85rem 0.8rem;
}

.preis-block .wizard-section-head {
    margin-bottom: 0.6rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--color-border);
}

/* Das Symbol der Kopfzeile in der Kennfarbe — dasselbe Mittel, mit dem sich die
   Abschnittsueberschriften voneinander abheben (siehe .vk-ek-title .icon). */
.preis-block .wizard-section-head h3 .icon {
    color: var(--color-primary);
}

/* Die Kopfzeile der Preiszeilen beginnt direkt unter der Trennlinie — ihr
   margin-top von 1rem waere hier ein zweiter Abstand. */
.preis-block .row-grid-head {
    margin-top: 0;
}

/* Preiszeile: Text, Einzelpreis, Anzahl, Gesamt, Rabatt, Prov., (Zeigen), Löschen.
   Die Einkaufsseite hat kein "Zeigen" — b_zusatzleistung_ek führt die Spalte nicht. */
.row-grid-head.cols-preis,
.row-grid.cols-preis {
    /* Text, Einzelpreis, Anzahl, Gesamt, Rabatt, Zeigen, Loeschen — die
       Provisionsspalte ist entfallen (siehe BookingWizardBlocks::priceBlocks). */
    grid-template-columns: minmax(0, 1fr) 5.5rem 3.5rem 6rem 5rem 3rem 2rem;
}

.row-grid.cols-preis.ohne-zeigen,
.preis-block:last-child .row-grid-head.cols-preis {
    grid-template-columns: minmax(0, 1fr) 5.5rem 3.5rem 6rem 5rem 2rem;
}

.row-grid-check {
    display: flex;
    align-items: center;
    justify-content: center;
}

.row-grid-check input {
    width: auto !important;
}

/* Untereinander statt nebeneinander — dieselbe Grenze wie im Buchungsdetail
   (.vk-ek-pair, 1700 px) und aus demselben Grund: die Preiszeile hat sieben
   feste Spalten von zusammen gut 500 px. Zu zweit nebeneinander blieb fuer die
   Bezeichnung so wenig, dass die Kopfzeile ueber ihren Nachbarn lief
   ("BEZEICHNUNZELPREIS"). Untereinander hat sie die ganze Breite. */
@media (max-width: 1700px) {
    .preis-blocks {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Noch schmaler taugen die festen Breiten nicht mehr: die Zeile wird zum
   zweispaltigen Raster. Dieselbe Grenze wie die Kopfzeile weiter oben, die ab
   1400 px ausgeblendet wird — die Beschriftungen stuenden sonst nicht mehr ueber
   den passenden Feldern. */
@media (max-width: 1400px) {
    .row-grid.cols-preis,
    .row-grid.cols-preis.ohne-zeigen {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Noch nicht erreichbarer Wizard-Schritt: sichtbar, aber nicht anklickbar —
   der Nutzer sieht den Weg, kann ihn aber nicht überspringen. */
.wizard-step.locked {
    opacity: 0.45;
    cursor: not-allowed;
}

/* Der RAHMEN muss mit zurueck: seit der Kreis einen hat, behielte ein Schritt,
   der einmal erledigt war und wieder gesperrt wird, sonst seinen violetten Ring
   und saehe erreichbar aus. */
.wizard-step.locked .wizard-step-no {
    border-color: var(--color-border);
    background: var(--color-bg);
    color: var(--color-text-muted);
}

#wizard-next:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Kleineres Popup für reine Detailanzeige (Anmelder-Stammdaten). */
.modal-box-sm {
    width: min(680px, 100%);
}

/* Schließen-Knopf im Popup: dezent, wird beim Überfahren deutlich. */
.modal-close {
    color: var(--color-text-muted);
    border-radius: var(--radius-sm);
    transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease);
}

.modal-close:hover {
    background: var(--color-primary-soft);
    color: var(--color-text);
}

/* ---------------------------------------------------------------------------
   Bearbeitbare Leistungsblöcke im Buchungsdetail (_block-editor.php)

   Das Layout ist bewusst das des Wizards — dieselbe Leistung soll beim Anlegen
   und beim Bearbeiten gleich aussehen. Die Zeilenraster heissen deshalb gleich
   (.row-grid.cols-flug, .cols-preis-edit) und werden hier nur um die beiden
   Spalten erweitert, die es im Wizard nicht gibt: vorn die Leistungsnummer,
   hinten Speichern und Löschen.
   --------------------------------------------------------------------------- */

.form-hint {
    margin: 0.75rem 0 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* Zahl der abgelegten Dokumente am Menueeintrag "Dokument-Historie" — dieselbe
   Form wie die Zeilenzahl an einem Blocktitel. */
.doc-view-popup-zahl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.3rem;
    margin-left: 0.4rem;
    padding: 0 0.3rem;
    border-radius: var(--radius-pill);
    background: var(--color-bg);
    color: var(--color-text-muted);
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Mail-Dialog: Anhaenge aus dem Archiv (bookings/_senden-dialog.php)
   --------------------------------------------------------------------------- */
/* Zwei Klassen als Auswahl: .zahlung-dialog-box steht weiter unten in der Datei
   und gewinnt bei gleicher Staerke — der Dialog blieb sonst bei 720 px. */
.modal-box.mail-dialog-box {
    /* Traegt zusaetzlich die Anhangsliste — mit 720 px stand jede Zeile dort
       zweizeilig. */
    width: min(860px, 100%);
}

.mail-anhaenge {
    margin: 1rem 0 0;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.mail-anhaenge legend {
    padding: 0 0.35rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* Je Anhang eine Zeile: Haken, Nummer, Bezeichnung, Zeitpunkt. Hoehe begrenzt —
   eine Buchung kann ein Dutzend Dokumente haben, und dann waere die Liste der
   ganze Dialog. */
.mail-anhaenge {
    max-height: 11rem;
    overflow-y: auto;
}

/* AUSNAHME: der Feldsatz der E-Rechnung im Dokument-Dialog.
   ─────────────────────────────────────────────────────────────────────────────
   Er tragt dieselbe Klasse, ist aber KEINE Liste, die wachsen kann: ein Haken,
   zwei Auswahlfelder, zwei Hinweise — eine feste, kurze Form. Die Grenze von
   11rem lag genau vier Pixel unter seinem Inhalt (176 gegen 180), und damit war
   die letzte Zeile ("Steuernummer … und IBAN … kommen aus der Filiale") mitten
   durchgeschnitten. Zu sehen war sie nur, wenn man IM Feldsatz rollte — dass
   dort etwas rollt, sieht man an vier Pixeln nicht.

   Die Grenze bleibt fuer die Anhangslisten (Mail, WhatsApp, Quittung), wo sie
   gemeint ist. */
#erechnung-felder {
    max-height: none;
    overflow: visible;
}

.mail-anhang {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.25rem 0;
    font-size: 0.88rem;
}

.mail-anhang input {
    width: auto;
    flex-shrink: 0;
}

.mail-anhang code {
    margin-right: 0.35rem;
}

/* ---------------------------------------------------------------------------
   Dialog "Dokument" (bookings/_dokument-dialog.php)
   Je Beleg eine Zeile: links was es ist, rechts was man damit tun kann.
   --------------------------------------------------------------------------- */
/* ═══════════════════════════════════════════════════════════════════════════
   JEDER BELEG IST EINE KACHEL
   ═══════════════════════════════════════════════════════════════════════════
   Der Dialog traegt inzwischen vier Dinge: Rechnung, Reiseinformation, Voucher
   und Sicherungsschein — dazu die elektronische Fassung unter der Rechnung.
   Getrennt waren sie nur durch eine duenne Linie, und untereinander gelesen
   verschwamm alles zu einer langen Liste; wo der eine Beleg aufhoert und der
   naechste anfaengt, musste man suchen.

   Jetzt hat jeder seinen eigenen Grund: helle Flaeche, feiner Rahmen,
   Kartenradius. DIESELBE Bauform wie .crs-block im Uebernahme-Dialog — es ist
   dieselbe Aufgabe, und zwei Loesungen dafuer waeren eine zu viel.

   KEINE Farbe je Beleg: vier verschiedene Toene waeren ein Farbkasten und
   behaupteten eine Bedeutung ("gelb heisst was?"), die es nicht gibt. Die
   Trennung macht die Flaeche, nicht der Farbton. */
.dokument-block {
    margin-bottom: var(--space-3);
    padding: var(--space-4);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

/* Die Zeile SELBST traegt keinen Grund mehr — den hat die Kachel um sie
   herum. Sie ordnet nur noch Text und Knoepfe. */
.dokument-wahl {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.dokument-wahl-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

/* Die zwei Knoepfe nebeneinander; jeder steht in seinem eigenen Formular
   (Drucken) bzw. ist ein Knopf (Senden) — deshalb kein gap am Elternteil
   allein. */
.dokument-wahl-knoepfe {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Schmales Fenster: die Knoepfe unter den Text. */
@media (max-width: 640px) {
    .dokument-wahl {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* ---------------------------------------------------------------------------
   Dialog "Buchung uebernehmen" (bookings/_crs-uebernahme-dialog.php)

   Breiter als die uebrigen Dialoge: er traegt vier Abschnitte, und die
   Passagier- und Flugzeilen haben sieben bzw. acht Felder nebeneinander. Enger
   stuenden sie zweizeilig, und dann ist die Zuordnung Feld -> Spalte weg.
   --------------------------------------------------------------------------- */
/* Dieser Dialog beginnt DICHT AM FENSTERRAND, nicht mit den 4rem Abstand der
   uebrigen. Der Abstand ist dort richtig — ein kurzer Dialog schwebt sonst am
   oberen Rand —, hier sind es 64 Pixel, die dem laengsten Dialog der Anwendung
   fehlen. Unten bleibt der uebliche Abstand, damit die Knoepfe nicht an der
   Fensterkante kleben. */
#crs-uebernahme-dialog {
    padding-top: 1rem;
    padding-bottom: 1.5rem;
}

.crs-uebernahme-box {
    width: min(1180px, 100%);
    /* Hoehe begrenzt: bei zehn Passagieren waere der Dialog sonst laenger als
       der Bildschirm und die Knoepfe unten unerreichbar. */
    max-height: 94vh;
    display: flex;
    flex-direction: column;

    /* ───────────────────────────────────────────────────────────────────────
       IM DIALOG GILT DIE KOMPAKTE HOEHE
       ───────────────────────────────────────────────────────────────────────
       Diese Maske traegt fuenf Abschnitte mit bis zu zwanzig Zeilen — mit der
       normalen Feldhoehe war sie laenger als der Bildschirm, und man musste
       im Dialog scrollen, um zu sehen, was man gleich speichert.

       Gesetzt wird DIESELBE Marke, die auch der Dichteschalter der Kopfzeile
       setzt (--hoehe-feld, siehe partials/dichte-init.php). Damit bleibt die
       Regel des Hauses erhalten: EINE Groesse fuer alles Bedienbare, Feld und
       Knopf gleich hoch — nur eben die kleinere. Wer ohnehin kompakt
       eingestellt hat, sieht keinen Unterschied. */
    --hoehe-feld: 34px;
}

/* ---------------------------------------------------------------------------
   DIE KNOPFLEISTE BLEIBT STEHEN
   ---------------------------------------------------------------------------
   "Abbrechen" und "Buchung speichern" sollen IMMER zu sehen sein — auch auf
   einem kurzen Fenster und auch bei zwoelf Passagieren. Die Kappung der langen
   Listen allein reicht dafuer nicht: der Rest der Maske kann immer noch
   laenger sein als das Fenster.

   Geheftet an den unteren Rand des rollenden Bereichs (position: sticky im
   .modal-body, der die Rolle uebernimmt). Die negativen Raender ziehen die
   Leiste ueber das Polster des Koerpers nach aussen, damit ihre Trennlinie von
   Kante zu Kante geht und darunter kein Streifen Inhalt durchscheint. */
.crs-uebernahme-box .modal-body {
    /* Das Polster unten traegt die geheftete Leiste selbst. Bliebe es hier,
       klebte die Leiste 20 Pixel ueber der Unterkante — und in dem Streifen
       darunter schoebe sich der Inhalt durch. */
    padding-bottom: 0;
}

/* MIT .modal-body im Weg: weiter unten in dieser Datei steht
   `.modal-body .zahlung-dialog-actions { padding: 0 }` — gleich stark und
   spaeter, also gewinnt es. Ohne den dritten Namen hier blieb die Leiste ohne
   Polster, und die Knoepfe sassen EINEN Pixel von der Kante entfernt.
   Nachgemessen: unten 1px, rechts 1px. */
.crs-uebernahme-box .modal-body .zahlung-dialog-actions {
    position: sticky;
    bottom: 0;
    z-index: 1;
    margin: var(--space-3) -1.25rem 0;
    /* Unten dasselbe Polster wie an den Seiten (1.25rem): die Leiste liegt auf
       der Kante des Dialogs, und mit den 12px von oben sassen die Knoepfe
       sichtbar dichter am Rahmen als am rechten Rand. Gleicher Abstand nach
       unten und nach rechts — dann sitzen sie in der Ecke und nicht an ihr. */
    padding: var(--space-3) 1.25rem 1.25rem;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    /* Die Leiste liegt auf der UNTERSTEN Kante des Dialogs und muss dessen
       Rundung mitmachen. Ohne das stand sie mit zwei rechten Winkeln in einer
       runden Ecke — unten rechts fehlten sichtbar ein paar Pixel Grund. */
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* Der Koerper darf waagerecht nicht rollen: die Leiste ragt per negativem
   Rand ueber sein Polster hinaus, und ohne diese Zeile entstuende daraus eine
   waagerechte Rollleiste ueber die ganze Maske. */
.crs-uebernahme-box .modal-body {
    overflow-x: hidden;
}

/* Enger als die uebrigen Dialoge, aus demselben Grund: jeder gesparte Abstand
   ist eine Zeile mehr, die ohne Scrollen zu sehen ist. */
.crs-uebernahme-box .crs-block {
    padding: var(--space-3);
    margin-bottom: var(--space-3);
}

.crs-uebernahme-box .crs-kopf-reihe {
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.crs-uebernahme-box .crs-block legend {
    margin-bottom: var(--space-2);
}

.crs-uebernahme-box .crs-zeilen {
    gap: 0.25rem;
}

/* Der freistehende Spaltenkopf braucht den Abstand, den ihm vorher der
   Zeilenabstand der Liste gab. */
.crs-uebernahme-box .crs-zeile.crs-kopf {
    margin-bottom: 0.25rem;
}

/* ---------------------------------------------------------------------------
   LANGE LISTEN ROLLEN IN SICH
   ---------------------------------------------------------------------------
   Passagiere und Preispositionen sind die beiden Abschnitte ohne Obergrenze:
   eine Gruppenbuchung hat zwoelf Reisende, eine Pauschalreise ein Dutzend
   Positionen. Bisher wuchs der Dialog mit ihnen, bis er laenger war als der
   Bildschirm — und dann rollte man an den Knoepfen vorbei und suchte den
   Speichern-Knopf.

   Jetzt bleibt der RAHMEN stehen: Kopf, alle Abschnitte und die Knoepfe sind zu
   sehen, und nur die lange Liste rollt in ihrem Kasten. Die Hoehe ist so
   gewaehlt, dass die ueblichen Faelle ganz hineinpassen (sieben Zeilen) und
   erst darueber gerollt wird.

   Die Summe steht ausserhalb dieses Kastens (siehe Vorlage) — sonst waere sie
   genau das, was beim Rollen verschwindet. */
.crs-uebernahme-box .crs-block .crs-zeilen {
    /* SIEBEN Zeilen: 29px Feldhoehe plus 4px Abstand, mal sieben.

       Die Spaltenkoepfe stehen dafuer AUSSERHALB dieses Kastens (siehe
       Vorlage). Zuerst lagen sie darin — dann rollte "NAME / VORNAME /
       GEBURTSDATUM" beim ersten Dreh nach oben weg, und man sah acht Felder
       ohne Beschriftung. Nebenbei war die Kappung damit um eine Kopfzeile
       verschoben und schnitt mitten in die letzte Zeile. */
    max-height: 14.5rem;
    overflow-y: auto;
    /* Fokusrahmen der ersten und letzten Zeile nicht anschneiden. */
    padding: 2px;
    margin: -2px;
}

/* DREI Zeilen bei den Preisen — die knappste Liste des Dialogs, und mit Absicht.
   Sie ist die einzige, die BEIDE Seiten untereinander haette wachsen lassen:
   eine Pauschalreise bringt ein Dutzend Positionen mit, und mit ihnen wanderten
   "Abbrechen" und "Buchung speichern" aus dem Fenster. Drei Zeilen zeigen, WAS
   fuer Positionen es sind; wer alle sehen will, rollt in der Liste. */
.crs-uebernahme-box .crs-preis-reihe .crs-zeilen {
    max-height: 6.2rem;
    overflow-y: auto;
    /* Fokusrahmen der ersten und letzten Zeile nicht anschneiden. */
    padding: 2px;
    margin: -2px;
}

/* Der Hinweis unter den Bloecken: kleiner und dichter am Text darueber. Er ist
   eine Fussnote und keine Zeile der Maske. */
.crs-uebernahme-box .form-hint {
    margin: 0 0 var(--space-2);
    font-size: 0.78rem;
}

.crs-uebernahme-box .modal-body {
    overflow-y: auto;
}

/* ANMELDER UND VORGANG NEBENEINANDER — die beiden Bloecke, die den Kopf der
   Buchung beschreiben. auto-fit mit Mindestbreite: wird der Dialog schmal
   (kleines Fenster, Tablet), stehen sie wieder untereinander, ohne dass dafuer
   eine Bruchstelle als Pixelzahl gepflegt werden muss. */
.crs-kopf-reihe {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
    gap: var(--space-4);
    align-items: start;
    /* ABSTAND NACH UNTEN zum Passagierblock.
       Jeder .crs-block traegt ihn selbst als margin-bottom — die beiden in
       dieser Reihe aber nicht, dort macht ihn das Raster (siehe unten). Damit
       hatte die REIHE als Ganzes keinen, und der Passagierblock klebte an
       ihrer Unterkante. Derselbe Wert wie zwischen zwei Bloecken, damit die
       Abstaende ueber den ganzen Dialog gleich sind. */
    margin-bottom: var(--space-4);
}

/* Die Bloecke sind KACHELN und keine Formularrahmen mehr: eigener Grund, feiner
   Rahmen, Kartenradius. Der duenne Rahmen mit der Beschriftung IN der Linie
   (die Bauform eines <fieldset>) stammt aus einer aelteren Formularwelt und
   passte als einziges Element der Anwendung nicht mehr zu den Karten.

   <fieldset> BLEIBT als Element: es fasst zusammengehoerende Felder, und das ist
   die richtige Auszeichnung — nur das Aussehen wechselt. */
.crs-block {
    margin: 0 0 var(--space-4);
    padding: var(--space-4);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

.crs-kopf-reihe .crs-block {
    /* In der Reihe macht den Abstand das Raster. */
    margin-bottom: 0;
    height: 100%;
}

/* Die Beschriftung steht UEBER dem Block statt in seiner Rahmenlinie — wie die
   Abschnittstitel der uebrigen Masken (Grossbuchstaben, gesperrt, gedaempft). */
.crs-block legend {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    float: left;
    width: 100%;
    padding: 0;
    margin-bottom: var(--space-3);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

/* float braucht einen Abschluss, sonst liegt der Inhalt darunter daneben.
   (Ein <legend> laesst sich nicht mit display:block aus der Rahmenlinie loesen —
   der Browser behandelt es gesondert; float ist der Weg, der ueberall wirkt.) */
.crs-block legend + * {
    clear: both;
}

/* Die Zeilen: ein Raster statt einer Tabelle. In einer Tabelle waeren die
   Felder an Zellen gebunden, und ein <form> darf nicht zwischen <tr> und <td>
   stehen — dieselbe Einschraenkung wie bei den Mahngebuehren. */
.crs-zeilen {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.crs-zeile {
    display: grid;
    gap: 0.35rem;
    align-items: center;
}

/* Anrede, Name, Vorname, Geburtsdatum, Ticket, Preis, Tax, Gebuehr */
.crs-zeile.cols-pax {
    grid-template-columns: 5rem minmax(0, 1.3fr) minmax(0, 1.3fr) 8.5rem minmax(0, 1fr) 6.5rem 6.5rem 6.5rem;
}

/* Kopfzeile: dasselbe Raster, damit Beschriftung und Feld untereinander stehen.
   Kleiner und gedaempft — sie ist Beschriftung, nicht Inhalt. */
.crs-zeile.crs-kopf {
    padding: 0 0.5rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

/* Eine zu lange Beschriftung wird ABGESCHNITTEN, nicht in die Nachbarspalte
   geschoben: sonst steht sie ueber dem falschen Feld, und das ist schlimmer als
   ein fehlendes Wortende. */
.crs-zeile.crs-kopf > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Der Text der Kopfzelle folgt der Ausrichtung ihrer Spalte: ueber einem
   rechtsbuendigen Betrag steht die Beschriftung ebenfalls rechts. */
.crs-zeile.crs-kopf .text-right {
    text-align: right;
}

/* Gesellschaft, Nummer, von, nach, Datum, ab, an, Klasse

   Die erste Spalte ist breiter als ihr Feld ("XQ") — sie muss die Beschriftung
   tragen. Vorher lief "GESELLSCHAFT" in die naechste Spalte hinein. */
.crs-zeile.cols-flug {
    grid-template-columns: 6.5rem 5.5rem 4rem 4rem 8.5rem 7.5rem 7.5rem 4rem;
}

/* Position, Einzelpreis, Anzahl, Gesamt.

   Die Position nimmt den Rest: dort steht "DTM-ADB LUFTVERKEHRSSTEUER", und
   sie ist die einzige Spalte, deren Laenge nicht vorhersehbar ist. */
/* Verkauf und Einkauf stehen NEBENEINANDER (.crs-preis-reihe). Jede Seite hat
   damit nur die halbe Dialogbreite, und die Spalten sind entsprechend enger:
   die Position nimmt, was uebrig ist, die drei Zahlenspalten stehen fest.

   Keine Leerspur wie bei den breiten Rastern darueber — hier ist nichts
   uebrig, was aufzunehmen waere. */
.crs-zeile.cols-preis {
    grid-template-columns: minmax(0, 1fr) 6.5rem 4rem 6.5rem;
}

/* Betraege rechtsbuendig — Kommastellen stehen damit untereinander. */
.crs-zeile.cols-preis input.feld-betrag,
.crs-zeile.cols-preis input.feld-zahl {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Der Gesamtpreis ist zur Ansicht: er wird beim Speichern aus Einzelpreis mal
   Anzahl neu gerechnet. Sichtbar unbedienbar ist ehrlicher als ein Feld, das
   sich beschreiben laesst und den Wert dann verwirft. */
.crs-zeile.cols-preis input[readonly] {
    background: var(--color-bg);
    color: var(--color-text-muted);
    border-style: dashed;
}

.crs-zeile.crs-summe {
    padding: 0.35rem 0.5rem 0;
    border-top: 1px solid var(--color-border);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.crs-zeile.crs-summe > span:last-child {
    text-align: right;
    padding-right: 0.6rem;
}

.crs-zeile input,
.crs-zeile select {
    width: 100%;
    font-family: inherit;
    font-size: 0.85rem;
}

/* Schmales Fenster: die Zeilen brechen um. Die Zuordnung geht dabei verloren,
   aber ein waagerechtes Rollen im Dialog ist schlimmer. */
@media (max-width: 1100px) {
    .crs-zeile.cols-pax,
    .crs-zeile.cols-flug {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* ---------------------------------------------------------------------------
   CRS-Uebernahme: der Knopf "Zwischenablage einlesen" (bookings/crs-import.php)
   Eine Zeile ueber der Liste, rechtsbuendig wie die Werkzeugzeilen der Listen.
   --------------------------------------------------------------------------- */
/* Der Knopf "Zwischenablage einlesen" steht LINKS: er ist der Einstieg in diese
   Maske — hier faengt die Arbeit an, und der Blick beginnt links. Die
   Zeilenaktionen (uebernehmen, loeschen) sitzen dagegen rechts an ihrer Zeile. */
.crs-clipboard-zeile {
    display: flex;
    justify-content: flex-start;
    margin-bottom: 1rem;
}

/* ---------------------------------------------------------------------------
   Mahngebuehren im Dialog "Zahlungsdaten bearbeiten"
   Stufe, Datum, Betrag, Bedienung — je Zeile ein Formular (.row-grid).
   --------------------------------------------------------------------------- */
.row-grid-head.cols-mahn,
.row-grid.cols-mahn {
    grid-template-columns: 3rem minmax(8rem, 1fr) 8rem 4.75rem;
}

.mahn-liste {
    /* Der Dialog hat oben schon einen gepolsterten Bereich; dieser zweite
       braucht nur die Trennlinie dazwischen. */
    border-top: 1px solid var(--color-border);
    padding-top: 1rem;
}

.mahn-liste h3 {
    margin: 0 0 0.5rem;
    font-size: 0.95rem;
}

/* Im Mahnung-Dialog steht die Liste des Bisherigen unter den Eingabefeldern —
   sie braucht Abstand, sonst klebt der Spaltenkopf am Feld darueber. */
#mahnung-dialog .table-scroll {
    margin-top: 1rem;
}

/* ---------------------------------------------------------------------------
   Dialog "Angaben der Kanzlei" (accounting/fibu-export.php)
   Sechs kurze Felder — die 920 px der grossen Dialoge waeren hier eine leere
   Flaeche, und die Knopfreihe stand ohne Seitenrand am Rand der Box.
   --------------------------------------------------------------------------- */
.fibu-dialog-box {
    width: min(640px, 100%);
}

/* Der DOKUMENT-Dialog ist breiter und hoeher als der FIBU-Dialog, obwohl er
   dessen Kasten benutzt: er traegt drei Belegzeilen mit je drei Knoepfen und
   darunter den Block der E-Rechnung. Bei 640px brach die Knopfreihe um, und der
   Kasten rollte innen, obwohl auf dem Schirm Platz war.

   max-height statt einer festen Hoehe: auf einem kleinen Notebook soll er nicht
   ueber den Rand hinauslaufen. */
/* Dieser Dialog beginnt HOEHER als die uebrigen: der Schleier haelt oben 4rem
   Abstand (fuer kleine Dialoge richtig, damit sie nicht am Fensterrand kleben),
   und die kosten hier Hoehe, die der Inhalt braucht. 2rem oben und unten geben
   dem Kasten die ganze Fensterhoehe minus 4rem — mehr ist nicht zu holen, ohne
   dass sein unterer Rand aus dem Bild laeuft. */
#dokument-dialog {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

.dokument-dialog-box {
    width: min(860px, 100%);
    /* Die ganze verfuegbare Hoehe: Fenster minus die 1rem Schleierabstand oben
       und unten. MEHR IST NICHT ZU HOLEN — ohne diesen Rest lief der untere Rand
       des Kastens aus dem Fenster.

       Vorher 88vh bei 4rem Abstand: die Grenze lag damit mitten im Feldsatz der
       E-Rechnung, und die Zeile mit Steuernummer und IBAN war nur durch Rollen
       zu lesen. Auf einem 900px hohen Fenster sind es jetzt 868 statt 792 —
       76 Pixel mehr, gut zwei Textzeilen. */
    max-height: calc(100vh - 2rem);
    /* Und wenn die Grenze doch greift, rollt der Kasten INNEN. Mit
       `overflow: visible` (der Vorgabe) laeuft der Inhalt ueber den weissen
       Grund hinaus und steht auf dem grauen Schleier — sichtbar, aber nicht mehr
       erreichbar, weil der Hintergrund den Rollbefehl bekommt. */
    overflow-y: auto;
}

/* Etwas mehr Luft unter der letzten Zeile als daneben: unter dem Feldsatz der
   E-Rechnung steht noch ein Hinweissatz, und mit den gleichen 1.25rem wie oben
   klebte er am unteren Rand. */
.dokument-dialog-box .modal-body {
    padding-bottom: 1.75rem;
}

.fibu-dialog-hinweis {
    /* form-hint bringt margin-top mit; im Dialog steht der Hinweis oben und
       braucht stattdessen Abstand nach UNTEN zu den Feldern. */
    margin: 0 0 1.25rem;
}

/* Festschreibung im FIBU-Dialog: Ankreuzfeld UND Text in einer Zeile, nicht
   untereinander wie die Feldreihen darueber. */
.fibu-festschreibung {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1rem;
    font-size: 0.85rem;
    color: var(--color-text);
}

.fibu-festschreibung input {
    width: auto;
}

/* Stern hinter der Beschriftung eines Pflichtfeldes. Kraeftige Farbe, aber keine
   eigene Zeile und kein Symbol: er soll die Beschriftung nicht auseinanderziehen
   und im Ausdruck erhalten bleiben. */
.pflicht-stern {
    /* Abstand ueber margin, NICHT als Leerzeichen im Text: ein Leerzeichen ist
       eine Umbruchstelle, und in den schmalen Spalten der Unterbringungsreihe
       ("Anzahl", "Erwachsene") rutschte der Stern dadurch in eine zweite Zeile
       und machte die ganze Reihe 20 Pixel hoeher. */
    margin-left: 0.15rem;
    color: var(--color-danger-text);
    font-weight: 700;
}

/* Zeilenzahl neben dem Blocktitel — auf einen Blick, ob der Block belegt ist. */
.block-editor-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.5rem;
    padding: 0 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    font-size: 0.78rem;
    font-weight: 600;
}

.block-rows {
    margin-top: 0.9rem;
}

/* Die einzeilige Form uebernimmt die festen Spaltenbreiten des Wizards; mit
   Leistungsnummer und zwei Aktionsknoepfen ist eine Flugzeile rund 71rem breit
   und passt auf schmaleren Bildschirmen nicht in den Inhaltsbereich. Der Bereich
   scrollt deshalb selbst — vorher tat das die Tabellenhuelle. Die Felder statt-
   dessen zu quetschen waere schlechter: Uhrzeiten und Datum brauchen ihre Breite.
   Unter 1200px greift weiter unten der Umbruch auf zwei Spalten. */
.block-editor .block-rows,
.block-editor .block-editor-new {
    overflow-x: auto;
}

/* Die einzeiligen Formulare (Flug, Preise) stehen direkt untereinander. */
.block-rows > .row-grid + .row-grid {
    margin-top: 0.5rem;
}

/* Speichern und Löschen als Paar am Zeilenende. */
.row-actions {
    display: flex;
    gap: 0.35rem;
    align-items: center;
}

.row-action-save {
    color: var(--color-primary);
}

.row-action-save:hover {
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
}

/* Leistungsnummer im Kopf der mehrreihigen Karten — kompakt, damit Titel,
   Auswahl und Knöpfe in eine Zeile passen. */
/* ---------------------------------------------------------------------------
   Laufnummer im Kopf einer Blockzeile — GANZ VORNE, wie die erste Spalte der
   einzeiligen Form (Flug, Preiszeilen). Feste Breite, damit die Nummer bei allen
   Zeilen des Blocks an derselben Stelle steht, auch wenn eine zweistellig ist.
   --------------------------------------------------------------------------- */
.block-lfnr-badge {
    min-width: 2.25rem;
    text-align: center;
    flex-shrink: 0;
}

/* Neue Zeile: dieselbe Spalte, dasselbe Abzeichen. Die Nummer ist nicht
   eingebbar — sie kommt aus der Leistungsauswahl oben (siehe
   _block-editor.php und _leistung-auswahl.php). */
.block-lfnr-neu {
    flex-shrink: 0;
}

/* Flugzeile im Editor: wie .cols-flug im Wizard, aber mit Leistungsnummer vorn
   und zwei Aktionsknoepfen statt einem hinten.

   DIESE Regel ist staerker als die allgemeine .cols-flug weiter oben (drei
   Klassen gegen zwei) — wer dort Breiten aendert, aendert das Buchungsdetail
   NICHT mit. Genau daran lag der ueberlappende Kopf: die Korrektur oben griff,
   hier stand weiter das alte Raster.

   ZWEI Aenderungen:

   PNR hat ein MINDESTMASS (4.5rem statt minmax(0, 1fr)). Die festen Spuren waren
   zusammen breiter als die Karte; eine Spur mit Untergrenze 0 faellt dann auf
   null zusammen, und die Beschriftung "PNR" lag ueber "Klasse".

   Die uebrigen Spuren sind knapper und nehmen die Marken des Design-Systems fuer
   Datum und Uhrzeit — ein Datumsfeld ist ueberall in der Anwendung gleich breit.

   Passt die Zeile trotzdem nicht, ROLLT die Karte waagerecht (.flug-karte,
   overflow-x). Vorher lief sie einfach ueber den Rand hinaus: die beiden
   Zeilenknoepfe am Ende waren dann nicht mehr zu sehen und nicht erreichbar. */
/* ZWEI BREITEN FUER DIESELBEN SPALTEN — und das ist der Kern:

   Die UEBERSICHTSZEILE (.block-summary-row) und ihre Kopfzeile in der Flugkarte
   zeigen TEXT: "26.04.2025", "10:15", "TK". Die NEU-ZEILE darunter zeigt
   EINGABEFELDER: ein date-Feld traegt das Kalendersymbol, ein time-Feld die Uhr,
   beide brauchen deutlich mehr Platz.

   Bisher galten fuer beide die Feldbreiten. Die Uebersichtszeile war damit rund
   80 px breiter als die Karte, und was hinten herausfiel, war die Aktionsspalte:
   der Bearbeiten-Knopf stand noch halb im Bild, der Loeschen-Knopf gar nicht
   mehr. Genau das war zu sehen.

   Die Aktionsspalte ist ausserdem von 4.75 auf 5rem gewachsen: zwei
   Symbolknoepfe zu je 36 px plus 0.35rem Abstand sind 78 px, in 76 px passten
   sie nicht. */
.block-editor .row-grid-head.cols-flug,
.block-editor .row-grid.cols-flug {
    /* FLUGNUMMER 6.5rem statt 5: gemessen brauchte die Ueberschrift 88 px und
       hatte 80 — die acht Pixel liefen in den Spaltenabstand, im Kopf stand
       "FLUGNUMMERPNR" als ein Wort. Dieselbe Korrektur wie an der allgemeinen
       Regel weiter oben; sie greift hier NICHT mit (drei Klassen gegen zwei),
       und genau davor warnt der Kommentar darueber. */
    grid-template-columns: 3rem 6.5rem 4rem 4rem 4.5rem 4.5rem 4rem 6.5rem
        minmax(4.5rem, 1fr) 4rem 3rem 3.5rem 5rem;
    min-width: 56.5rem;
    justify-content: start;
}

/* Neu-Formular: EINGABEFELDER, also die Feldbreiten des Design-Systems — und
   ohne Aktionsspalte, der Speichern-Knopf steht eine Zeile darunter. */
.block-editor .row-grid-head.cols-flug.row-grid-ohne-aktion,
.block-editor .row-grid.cols-flug.row-grid-ohne-aktion {
    grid-template-columns: 3.5rem var(--feld-datum) 4rem 4rem var(--feld-zeit) var(--feld-zeit)
        4.5rem 7rem minmax(4.5rem, 1fr) 4rem 3.5rem 4rem;
    min-width: 62rem;
}

/* Preiszeile im Editor: zusätzlich zum Wizard der Rabattpreis (RB_PREIS), weil er
   bei Bestandsdaten vom berechneten Wert abweichen kann und dann sichtbar
   bleiben muss. */
.block-editor .row-grid-head.cols-preis-edit,
.block-editor .row-grid.cols-preis-edit {
    grid-template-columns: 4rem minmax(0, 1fr) 5.5rem 3.5rem 6rem 5rem 6rem 3rem 4.75rem;
}

/* Leistungen: Übersichtszeile mit Lfnr, Reiseart, PNR, Zielgebiet, Zeitraum,
   Summe und den beiden Knöpfen — das vollständige Formular klappt darunter auf
   (.block-detail). Zeitraum und Summe sind reine Anzeige, sie werden hier nicht
   bearbeitet. Das Zielgebiet waechst mit, der Rest steht fest. */
.block-editor .row-grid-head.cols-leistung,
.block-editor .row-grid.cols-leistung {
    grid-template-columns: 3.5rem 6.5rem 6.5rem 7rem minmax(0, 1fr) 6.75rem 6.75rem 7.5rem 4.75rem;
}

/* Die Übersichtszeile enthält Text, keine Eingabefelder: etwas Luft und eine
   Trennlinie, damit die Zeilen als Liste lesbar bleiben. */
.block-summary-row {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.9rem;
}

.block-summary-row > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   Auswahl einer Leistung (_leistung-auswahl.php): die angeklickte Zeile
   bestimmt, welche Detailblöcke darunter stehen. Sie muss deshalb erkennbar
   bleiben, auch wenn man weiter unten arbeitet und sie aus dem Blick gerät.
   --------------------------------------------------------------------------- */

.block-summary-row[data-leistung] {
    cursor: pointer;
}

.block-summary-row[data-leistung]:hover {
    background: var(--color-surface-alt, rgba(99, 102, 241, 0.04));
}

.block-summary-row[data-leistung]:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: -2px;
}

.block-summary-row.leistung-aktiv {
    /* Farbige Kante links statt eines Rahmens: der Rahmen würde die Zeile um
       seine Breite verschieben und das Spaltenraster gegen die Kopfzeile
       verrutschen lassen. */
    box-shadow: inset 3px 0 0 0 var(--color-primary);
    background: var(--color-surface-alt, rgba(99, 102, 241, 0.06));
    font-weight: 600;
}


/* Aufgeklappter Bereich unter einer Übersichtszeile.
   EIN Rahmen um alles, was zu dieser Leistung gehört: ihre Felder UND ihre
   Verkaufs- und Einkaufspreise. Der Rahmen sitzt deshalb hier und nicht am
   Formular — die Preiszeilen sind eigene Formulare (HTML erlaubt keine
   Verschachtelung) und standen vorher sichtbar außerhalb des Rahmens, als
   dritter und vierter Kasten unter dem der Leistung.
   Flächenfarbe wie eine Leistung im Wizard (.wizard-row): grau, damit der offene
   Bereich sich von der Liste darüber abhebt. */
.block-detail {
    display: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    padding: 0.9rem 1rem 1rem;
    margin: 0.9rem 0;
}

.block-detail.visible {
    display: block;
}

/* Das Formular der Leistung trägt in diesem Bereich keinen eigenen Rahmen und
   keine eigene Fläche mehr: beides gehört jetzt dem Bereich als Ganzem. */
.block-detail > form.wizard-row {
    border: 0;
    background: none;
    padding: 0;
    margin-top: 0;
}

/* Einkaufspreise führen kein "Zeigen" — eine Spalte weniger. */
.block-editor .row-grid-head.cols-preis-edit.ohne-zeigen,
.block-editor .row-grid.cols-preis-edit.ohne-zeigen {
    grid-template-columns: 4rem minmax(0, 1fr) 5.5rem 3.5rem 6rem 5rem 6rem 4.75rem;
}

/* Preiszeilen INNERHALB einer Leistung: ohne Lfnr-Spalte, weil die Leistung schon
   durch ihre Gruppe benannt ist. Sie stehen zu zweit nebeneinander (Verkauf/Einkauf)
   und damit in etwa halber Breite — deshalb schmaler als im Blockeditor. */
/* Die Bezeichnung hat eine MINDESTbreite, keine reine 1fr-Spalte: die acht
   festen Spalten daneben füllen die halbe Breite fast aus, und 1fr fiel dadurch
   auf wenige Pixel zusammen — das Eingabefeld war rund 30 px breit und die
   Spaltenköpfe liefen ineinander ("BezeichnuEinzelpreis"). Wird es wirklich zu
   eng, scrollt der Block waagerecht (.vk-ek-block: overflow-x: auto), statt eine
   Spalte unlesbar zu machen. */
.vk-ek-pair .row-grid-head.cols-preis-lfnr,
.vk-ek-pair .row-grid.cols-preis-lfnr {
    display: grid;
    gap: 0.4rem;
    align-items: center;
    grid-template-columns: minmax(7rem, 1fr) 4.75rem 3rem 5rem 4.25rem 5rem 2.5rem 4.75rem;
}

/* Einkaufspreise führen kein "Zeigen" — eine Spalte weniger. */
.vk-ek-pair .row-grid-head.cols-preis-lfnr.ohne-zeigen,
.vk-ek-pair .row-grid.cols-preis-lfnr.ohne-zeigen {
    grid-template-columns: minmax(7rem, 1fr) 4.75rem 3rem 5rem 4.25rem 5rem 4.75rem;
}

/* Verkauf und Einkauf nebeneinander im aufgeklappten Bereich der Leistung. */
.vk-ek-pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

/* Verkauf und Einkauf sind zwei eigene Bloecke IM Rahmen der Leistung: eigene
   weisse Flaeche auf dem grauen Grund, eigener Rahmen, Kopfzeile mit Trennlinie.
   Ohne das gingen sie in der grauen Flaeche unter — man sah eine lange Reihe von
   Feldern und musste an den Ueberschriften ablesen, wo der eine Block endet und
   der andere beginnt. Der GEMEINSAME Rahmen bleibt der der Leistung. */


.vk-ek-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.6rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--color-border);
}

.vk-ek-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
    font-weight: 600;
}

/* Das Symbol der Kopfzeile in der Kennfarbe — dasselbe Mittel, mit dem sich die
   Abschnittsueberschriften der Maske voneinander abheben. */
.vk-ek-title .icon {
    color: var(--color-primary);
}

/* Summe der Zeilen — bei den Verkaufspreisen der Betrag, der als VER_SUMME in der
   Leistung steht. Schiebt den Hinzufügen-Knopf ans Ende. */
.vk-ek-sum {
    margin-left: auto;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

.vk-ek-pair .row-grid-head {
    font-size: 0.72rem;
}

.vk-ek-pair .row-grid + .row-grid {
    margin-top: 0.4rem;
}

/* Untereinander statt nebeneinander, solange nicht genug Breite da ist.
   Die Grenze liegt bei 1700 px und nicht bei 1400: eine Preiszeile hat neun
   Spalten, davon acht mit fester Breite (zusammen gut 500 px). Zu zweit
   nebeneinander blieb der Bezeichnung darunter so wenig, dass der Block
   waagerecht scrollen musste — untereinander hat sie die ganze Breite. */
@media (max-width: 1700px) {
    .vk-ek-pair {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Die Leistungsauswahl in der einzeiligen Form muss in ihre schmale Spalte
   passen, ohne das Raster zu sprengen. */
.block-editor .row-grid > select {
    min-width: 0;
    padding: 0.5rem 0.35rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    font-family: inherit;
    font-size: 0.9rem;
}

/* Formular für eine neue Zeile. Bewusst NICHT .edit-row: das ist ein div, und
   .edit-row.visible würde es zur Tabellenzeile machen. */
.block-editor-new {
    display: none;
    margin-top: 0.9rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--color-border);
}

.block-editor-new.visible {
    display: block;
}

/* Neu-Formular eines Leistungsblocks auf derselben Flaeche wie das
   Aufklappformular einer bestehenden Zeile (.block-detail) — dieselben Werte,
   damit "neu anlegen" und "bearbeiten" gleich aussehen.

   Die obere Trennlinie entfaellt dabei: der Rahmen der Karte leistet, was sie
   leisten sollte, und beides zusammen waere eine Linie direkt ueber einer
   Rahmenkante. */
.block-editor-new-karte {
    /* border ersetzt die border-top der Grundregel — alle vier Seiten, damit es
       eine Karte ist und keine Linie darueber. */
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    padding: 0.9rem 1rem 1rem;
    /* Passt die einzeilige Flugzeile nicht (sie hat ein Mindestmass von
       56.5rem), rollt die Karte waagerecht — Kopfzeile und Eingabezeile
       gemeinsam, weil beide darin liegen. Dieselbe Loesung wie bei den
       bestehenden Zeilen darueber (.flug-karte). Vorher lief die Zeile aus der
       Karte hinaus, und der Speichern-Knopf sass unter dem Nichts. */
    overflow-x: auto;
}

/* Folgt der Neu-Bereich DIREKT auf die Kopfzeile, gibt es keine Zeilen zwischen
   ihnen — dann waere seine obere Trennlinie die zweite unmittelbar unter der des
   Kopfes. Zwei Linien im Abstand von zwei Millimetern lesen sich als Fehler.

   Der Nachbar-Selektor trifft genau diesen Fall: sobald eine Zeile dazwischen
   steht, greift die Regel nicht mehr und die Trennlinie ist wieder richtig. */
.vk-ek-head + .block-editor-new {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

/* Preisblöcke stehen zu zweit nebeneinander (siehe .detail-info-row) und dürfen
   die Zeile nicht sprengen. */
.block-editor-compact {
    min-width: 0;
}

/* Auf schmalen Fenstern taugen die festen Spaltenbreiten nicht mehr: die Zeile
   wird zum zweispaltigen Raster, die Beschriftungen der Kopfzeile entfallen
   (sie stehen dann nicht mehr über den passenden Feldern). */
@media (max-width: 1200px) {
    /* :not(.row-grid-ohne-aktion) — die Kopfzeile des NEU-Formulars bleibt.
       Seine Zeile bricht naemlich nicht um: sie hat eine eigene Regel mit vier
       Klassen (.block-editor .row-grid.cols-flug.row-grid-ohne-aktion) und
       behaelt ihre zwoelf Spalten in jeder Breite. Ohne diese Ausnahme stand
       das Formular unter 1200 px wieder ohne Beschriftungen da — derselbe
       Fehler wie zwischen 1200 und 1400, nur eine Stufe tiefer. Gerollt wird
       dann waagerecht, Kopf und Zeile gemeinsam
       (.block-editor-new-karte, overflow-x). */
    .block-editor .row-grid-head.cols-flug:not(.row-grid-ohne-aktion),
    .block-editor .row-grid-head.cols-preis-edit,
    .block-editor .row-grid-head.cols-preis-edit.ohne-zeigen,
    .block-editor .row-grid-head.cols-leistung {
        display: none;
    }

    /* Auch hier :not(.row-grid-ohne-aktion) — und nicht nur wegen der Spalten:
       diese Regel gibt der Zeile ausserdem Polster und Rahmen. Beim
       NEU-Formular, dessen Spalten eine Regel mit vier Klassen festhaelt, kam
       davon nur das Polster durch — die Eingabezeile sass 13 px weiter rechts
       als ihre Kopfzeile darueber. Gemessen bei 1150 px: Kopf ab 314, Zeile ab
       327. */
    .block-editor .row-grid.cols-flug:not(.row-grid-ohne-aktion),
    .block-editor .row-grid.cols-preis-edit,
    .block-editor .row-grid.cols-preis-edit.ohne-zeigen,
    .block-editor .row-grid.cols-leistung {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        padding: 0.75rem;
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        background: var(--color-bg);
    }
}

/* ---------------------------------------------------------------------------
   Bestätigungsfenster (partials/confirm-dialog.php)
   Ersetzt die Systemabfrage confirm() im ganzen Programm.
   --------------------------------------------------------------------------- */

/* Anders als die Auswahl-Popups mittig statt oben: eine Rückfrage ist kurz und
   soll dort stehen, wo der Blick ohnehin ist. */
.confirm-dialog {
    align-items: center;
    padding: 1rem;
}

.confirm-dialog-box {
    width: min(520px, 100%);
}

/* Etwas mehr Luft um die Frage als in den Auswahl-Popups: hier steht ein einzelner
   Satz, der sonst am Rand klebt. */
.confirm-dialog .modal-body {
    padding: 1.5rem;
}

.confirm-dialog-text {
    margin: 0;
    font-size: 0.95rem;
    line-height: 1.5;
    color: var(--color-text);
}

/* .modal-foot bringt nur padding-top mit — im Wizard sitzt es innerhalb von
   .modal-body und erbt dessen seitliche Polsterung. Hier steht es direkt in der
   Box, deshalb die Polsterung ausdrücklich. Ohne sie kleben die Knöpfe am unteren
   und rechten Rand. */
.confirm-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    margin-top: 0;
    padding: 1.25rem 1.5rem;
}

/* ---------------------------------------------------------------------------
   Dialog "Zahlung erfassen" (_zahlung-dialog.php). Baut auf .modal-* auf, setzt
   nur die Breite und die Knopfreihe — die Felder stehen in .form-grid-Rastern
   wie in den uebrigen Masken.
   --------------------------------------------------------------------------- */

.zahlung-dialog-box {
    width: min(720px, 100%);
}

/* Zahlungsdaten: FUENF Felder in einer Zeile (Anzahlung, ihre Frist, die Frist
   der Restzahlung, Rabatt, Gebuehr). Mit 720px blieben davon rund 125px je
   Spalte — ein Datumsfeld mit Kalenderzeichen steht darin am Rand des
   Lesbaren. */
#zahlungsdaten-dialog .zahlung-dialog-box {
    width: min(980px, 100%);
}

/* ---------------------------------------------------------------------------
   Frist der OPTION im Reisedatenblock (bookings/detail.php).

   Die Zeile steht als letztes dt/dd-Paar in der Beschreibungsliste der
   Reisedaten und ist die einzige darin, die man aendern kann. Damit sie wie
   eine Zeile der Liste aussieht und nicht wie ein eingesetztes Formular:
   Datum und Speicherzeichen NEBENEINANDER, kein eigener Rahmen, keine eigene
   Beschriftung (die steht im <dt> und traegt damit dieselbe Rasterspalte wie
   "Gebucht am" darueber).

   .form-grid liefert nur die Feldgestaltung (Rahmen, Polsterung, Fokus); das
   display: grid daraus wird hier ueberschrieben.
   --------------------------------------------------------------------------- */
.option-frist {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* Das Datumsfeld nicht ueber die ganze Spaltenbreite ziehen — es braucht so
   viel, wie ein Datum braucht, und das Zeichen sitzt direkt daneben.

   Der Waehler `.form-grid.option-frist` ist genauso stark wie die allgemeine
   Feldregel oben (`.form-grid input:not([type="checkbox"]):not([type="radio"])`)
   und steht spaeter in der Datei — mit `.option-frist input[type="datetime-local"]`
   allein blieb die Polsterung von 0.5rem stehen und das Feld war 37px hoch.

   Der Typ ist ein datetime-local, seit OPT_DATUM ein DATETIME ist. */
.form-grid.option-frist input[type="datetime-local"] {
    /* Flacher als die Felder im Wizard (0.5rem/0.9rem): die Zeile soll so hoch
       bleiben wie die Listenzeilen darueber. */
    padding: 0.15rem 0.4rem;
    font-size: 0.85rem;
}

/* Das Speicherzeichen kleiner als die 28px der Listen: hier steht es in einer
   Textzeile und nicht in einer Tabellenzeile — mit 28px war die Zeile der
   Option um sieben Pixel hoeher als jede andere Zeile der Liste. */
.option-frist .row-action {
    width: 22px;
    height: 22px;
}

.option-frist .row-action .icon {
    width: 14px;
    height: 14px;
}

/* Beschriftung und Wert MITTIG zueinander: die letzte Zeile dieser Liste
   traegt ein Eingabefeld und ist damit hoeher als eine Textzeile. Ohne das
   sass "Option gueltig bis" am oberen Rand seiner Zelle und stand sichtbar
   ueber dem Datum daneben. */
.reisedaten-liste {
    align-items: center;
}

/* ---------------------------------------------------------------------------
   Lieferantenzahlung: Auswahlgitter der Leistungen oben im Dialog
   (_lieferantenzahlung-dialog.php). Eine Zahlung gehoert zu genau einem
   b_vorgang; die Zeile ist das Auswahlfeld.
   --------------------------------------------------------------------------- */

/* Der Dialog traegt die Leistungstabelle und ist deshalb breiter als der
   Kundendialog — mit 720 px stand die Tabelle unter einem Balken. */
#lieferantenzahlung-dialog .zahlung-dialog-box {
    width: min(1040px, 100%);
}

/* Dokument-Historie: dieselbe Begruendung. Die Zeile traegt Datum, Art, Nummer,
   Betrag und zwei Knoepfe, und beim Senden klappt darunter noch eine Adresszeile
   auf — mit 720 px brach die Art auf drei Zeilen um. */
#dokument-historie-dialog .zahlung-dialog-box {
    width: min(1040px, 100%);
}

/* Hoehe begrenzt: eine Buchung kann viele Leistungen haben, und dann waere die
   Tabelle der ganze Dialog und die Felder darunter ausser Sicht. */
.lz-leistungen {
    max-height: 13rem;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    margin-bottom: 1rem;
}

.lz-leistungen .data-table {
    font-size: 0.82rem;
}

.lz-leistung {
    cursor: pointer;
}

.lz-leistung:hover {
    background: var(--color-surface-alt, rgba(99, 102, 241, 0.04));
}

/* Die gewaehlte Zeile: farbige Kante links statt eines Rahmens — ein Rahmen
   wuerde die Zeile um seine Breite verschieben. Dasselbe Mittel wie bei der
   gewaehlten Leistung im Buchungsdetail. */
.lz-leistung-aktiv {
    box-shadow: inset 3px 0 0 0 var(--color-primary);
    background: var(--color-surface-alt, rgba(99, 102, 241, 0.06));
    font-weight: 600;
}

.lz-wahl {
    width: 2.25rem;
    text-align: center;
}

/* Beschriftung ueber einem Block, der kein einzelnes Feld ist (das Gitter) —
   sieht aus wie die Beschriftung eines Feldes daneben. */
.modal-label {
    margin: 0 0 0.35rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIE KNOPFLEISTE EINES DIALOGS
   ═══════════════════════════════════════════════════════════════════════════
   Sie steht in ZWEI Bauformen im Haus:

     a) INNERHALB von .modal-body (der Zahlungsdialog: das <form> IST die Body)
     b) DANEBEN, als Geschwister der .modal-body (Sammelzahlung, SEPA, Export)

   In Fall b hatte sie nur einen margin-top und sonst nichts — die Knoepfe
   klebten am unteren und rechten Fensterrand. Das Polster steht deshalb jetzt
   an der Leiste selbst, mit DENSELBEN 1.25rem wie .modal-body, damit "Abbrechen"
   und "Speichern" auf einer Linie mit dem Inhalt darueber enden.

   In Fall a nimmt die Body das Polster schon mit; dort wird es unten wieder
   abgezogen, sonst stuende es doppelt. */
.zahlung-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    margin-top: 1.5rem;
    padding: 0 1.25rem 1.25rem;
}

.modal-body .zahlung-dialog-actions {
    padding: 0;
}

/* Stornierte Zeile und Stornobuchung bleiben lesbar, sind aber als erledigt zu
   erkennen — geloescht wird in der Buchhaltung nichts. */
.zahlung-storniert {
    color: var(--color-text-muted);
    font-style: italic;
}

/* Erfolgsmeldung nach dem Versand — dieselbe Stelle wie die Fehlermeldung,
   aber in Gruen: eine verschickte Mail ist keine Warnung. */
.send-erfolg {
    margin: 0 0 1rem;
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--color-success, #16a34a);
    border-radius: var(--radius);
    color: var(--color-success-text);
    background: rgba(22, 163, 74, 0.08);
    font-size: 0.9rem;
}

/* Überschrift einer Gruppe im Dokument-Menü (Drucken / Senden). Kein Eintrag,
   sondern eine Beschriftung — deshalb kein Zeigefinger und keine Hover-Farbe,
   sonst sieht sie aus wie etwas Anklickbares. */
.doc-view-popup-gruppe {
    display: block;
    padding: 0.55rem 0.9rem 0.25rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    cursor: default;
}

/* Trennlinie über jeder Gruppe außer der ersten. */
.doc-view-popup-gruppe:not(:first-child) {
    margin-top: 0.25rem;
    border-top: 1px solid var(--color-border);
}

/* Zweiter Wert eines Spaltenpaars, das untereinander steht (Kontenblatt-
   Tagesliste: Einnahme/Ausgabe, Konto/Gegenkonto, Vorgang/Beleg). Gedämpft, damit
   auf einen Blick erkennbar ist, welcher der beiden Werte der obere ist — sonst
   sehen zwei gleichrangige Zeilen aus wie zwei Datensätze. */
.zell-zweite {
    display: inline-block;
    margin-top: 0.15rem;
    font-size: 0.8em;
    color: var(--color-text-muted);
}

/* ROT muss hier ausdruecklich gewinnen.
   ---------------------------------------------------------------------------
   `.text-danger` (weiter oben in der Datei) und `.zell-zweite` sind gleich
   stark — beides eine Klasse —, und bei gleicher Staerke gewinnt die SPAETERE
   Regel. Das ist diese hier. Die abgelaufene Optionsfrist in der Buchungsliste
   trug die Klasse also, blieb aber grau: nachgemessen rgb(145,152,171) statt
   der Warnfarbe. Aufgefallen ist es beim Umstellen auf DATETIME — der Fehler
   war schon vorher da und hat nie jemand gesehen, weil grau eben grau ist. */
.zell-zweite.text-danger {
    color: var(--color-danger-text);
}

/* AUSGABE-Betrag im Kontenblatt: immer rot, in den Zeilen und in der
   Summenzeile. Einnahme und Ausgabe stehen dort in EINER Spalte untereinander —
   ohne die Farbe muss man den Spaltenkopf mitlesen, um zu wissen, welche der
   beiden Zahlen Geld ist, das das Haus verlaesst.

   Steht NACH .zell-zweite, damit die Farbe deren Grau gewinnt (gleiche
   Spezifitaet, spaeter im Blatt). */
.zell-ausgabe {
    color: var(--color-danger-text);
}

/* ---------------------------------------------------------------------------
   Zahlungsdaten-Karte: vier Spalten, damit Betrag und Frist nebeneinander
   stehen (Anzahlungshöhe / Anzahlung fällig, Offen / Restzahlung fällig).
   Zeilen ohne Gegenstück laufen über die restlichen drei Spalten.
   --------------------------------------------------------------------------- */

/* ═══════════════════════════════════════════════════════════════════════════
   ZAHLUNGSDATEN — VIER SPALTEN MIT FESTEN PLAETZEN
   ═══════════════════════════════════════════════════════════════════════════
   Beschriftung | Betrag (rechtsbuendig) | zweite Beschriftung | zweiter Wert.

   Die Plaetze stehen AUSDRUECKLICH und nicht ueber die Reihenfolge: eine Zeile
   ohne zweite Angabe (Gesamtpreis, Bezahlt) liesse sonst zwei Zellen frei, und
   die naechste Beschriftung ruecke in dieselbe Zeile nach — gemessen stand
   "Gebuehr" dann rechts neben dem Gesamtpreis. Mit `grid-column: 1` am dt
   beginnt jede Hauptangabe eine neue Zeile.

   Die Betragsspalte ist so breit wie ihr breitester Betrag (auto) und nicht
   1fr: nur so stehen die Zahlen rechtsbuendig untereinander, ohne quer durch die
   Karte zu wandern. */
.zahlungsdaten-liste {
    grid-template-columns: auto auto auto 1fr;
    /* space-3 und nicht space-4: die Karte steht neben zwei weiteren in einer
       Reihe, und mit dem groesseren Abstand brachen "Anzahlung Hoehe" und
       "Restzahlung faellig" in zwei Zeilen um. */
    column-gap: var(--space-3);
}

.zahlungsdaten-liste > dt {
    grid-column: 1;
}

.zahlungsdaten-liste > dd {
    grid-column: 2;
}

.zahlungsdaten-liste > dt.zd-zweit {
    grid-column: 3;
}

.zahlungsdaten-liste > dd.zd-zweit {
    grid-column: 4;
}

/* Ein Hinweis, der in der SPALTE DER ZWEITEN ANGABE beginnt (dritte
   Rasterspalte) und bis zum Rand laeuft: "im Gesamtpreis enthalten" steht damit
   auf einer Linie mit "Anzahlung faellig" darunter, unabhaengig davon, wie lang
   der Betrag links davon ist. */
/* Betraege rechtsbuendig, mit Ziffern gleicher Breite: dann liegen Komma und
   Kommastellen untereinander und zwei Zahlen sind auf einen Blick
   vergleichbar. */
.zahlungsdaten-liste .zd-betrag {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.zahlungsdaten-liste > .zd-hinweis {
    grid-column: 3 / span 2;
    font-size: 0.85em;
    color: var(--color-text-muted);
}

/* Untertitel innerhalb einer Karte — gliedert einen Abschnitt, ohne wie eine
   eigene Karte auszusehen (Systemeinstellungen: Zugangsdaten des eigenen
   Mailservers innerhalb des Mailversand-Blocks). */
.karten-untertitel {
    margin: 1.25rem 0 0.75rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

/* Fußzeile des Mailversand-Blocks: Hinweis links, Testmail-Knopf rechts. */
.mailversand-fuss {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

.mailversand-fuss .form-hint {
    margin: 0;
}

/* Buchungskopf: Nummer und Status NEBENeinander.

   Eigene Klasse statt einer Änderung an .detail-header-main — die steht auf
   flex-direction: column und wird von Hotel-, Kunden- und Agenturmasken
   mitbenutzt, wo Titel und Unterzeile untereinander gehören. */
.detail-header-main.buchung-kopf {
    flex-direction: row;
    align-items: center;
    gap: 0.85rem;
    flex-wrap: wrap;
}

/* ── Filialen: Logos und Texte ───────────────────────────────────────────────
   Die BLOB-Felder einer Filiale (Briefkopf, Logos, Voucher, QR-Code) stehen in
   der Bearbeitungszeile der Systemeinstellungen. Als eigenes Raster, weil ein
   Bild-Upload mit Vorschau nicht in die einzeilige Feldreihe des
   .inline-edit-form passt. */
.filiale-blobs {
    grid-column: 1 / -1;
    border-top: 1px solid var(--color-border);
    margin-top: 1rem;
    padding-top: 1rem;
}

.filiale-blobs h3 {
    margin: 0 0 0.75rem;
    font-size: 0.95rem;
}

/* EINE Zeile je Bild, nicht mehrere Kacheln nebeneinander: die Vorschau steht
   in Originalgroesse und braucht die volle Breite neben der Bedienung. */
.filiale-blob-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

.filiale-blob {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 1rem;
    padding: 0.75rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}

/* Titel, Entfernen-Haken und Dateifeld: feste schmale Spalte links, damit die
   Vorschau daneben immer an derselben Stelle beginnt. */
.filiale-blob-steuerung {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    flex: 0 0 210px;
}

.filiale-blob-titel {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

/* Die Vorschau zeigt das Bild in ORIGINALGROESSE — so, wie es in der Datenbank
   liegt und im Beleg landet. Verkleinert (frueher hoechstens 70 px hoch) war
   nicht zu beurteilen, ob ein Briefkopf scharf genug ist und ob der Text darin
   lesbar bleibt.
   Ist das Bild breiter als der Platz daneben, rollt DIESER Kasten waagerecht;
   die Seite selbst bleibt davon unberuehrt. */
.filiale-blob-vorschau {
    flex: 1 1 320px;
    min-width: 0;
    overflow-x: auto;
}

.filiale-blob-bild {
    display: block;
    background: #ffffff;
    border-radius: 4px;
    padding: 0.25rem;
}

.filiale-blob-leer,
.filiale-blob-weg {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.filiale-blob-weg {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.filiale-blob input[type="file"] {
    font-size: 0.78rem;
}

.filiale-blob-text {
    display: block;
    margin-top: 1rem;
}

.filiale-blob-text textarea {
    width: 100%;
    font-family: var(--schrift-mono);
    font-size: 0.82rem;
}

/* Suchleiste ohne Kartenrahmen — fuer Masken, in denen die Felder schon in
   einer Karte stehen (GoBD-Export). Erbt alles andere von .search-form, damit
   Datums- und Textfelder ueberall gleich aussehen. */
.search-form-blank {
    background: none;
    border: 0;
    box-shadow: none;
    padding: 0;
    margin-bottom: 1rem;
}

/* ── GoBD-Export ─────────────────────────────────────────────────────────────
   Links die Auswahl (Zeitraum + Datenbereiche), rechts Archivordner und die
   letzten Exporte. Die Auswahlspalte ist die breitere: dort steht eine Tabelle
   mit elf Zeilen, rechts nur eine Liste. */
/* Die Auswahlkarte nimmt die ganze Breite: der Zeitraum steht darin als Leiste
   ueber die volle Breite, die Datenbereiche darunter in zwei Spalten. */
.gobd-auswahl {
    width: 100%;
}

/* Zeitraumleiste ueber die ganze Breite; die Jahresvorlagen stehen rechts. */
.gobd-zeitraum {
    width: 100%;
}

.gobd-zeitraum .gobd-vorlagen {
    margin-left: auto;
}

/* Die elf Datenbereiche in zwei Tabellen nebeneinander; untereinander waere die
   Liste hoeher als die halbe Seite. Bei schmalem Fenster brechen sie um. */
.gobd-bereich-spalten {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 0 1.5rem;
    align-items: start;
}

.gobd-vorlagen {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* Die Ankreuzspalte braucht keine Breite fuer eine Beschriftung, die
   Zahlenspalte nur ihre Ziffern. */
.gobd-bereiche td.col-actions,
.gobd-bereiche th.col-actions {
    width: 2.5rem;
}

.gobd-bereiche td.text-right,
.gobd-bereiche th.text-right {
    width: 7rem;
}

/* Die Beschriftung gehoert zum Ankreuzfeld: ein Klick auf den Namen des
   Bereichs soll ihn an- und abwaehlen. */
.gobd-bereiche label {
    cursor: pointer;
}

.gobd-ok {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--color-success-text);
}

/* Zweite Zeile in einer Kennzahlkachel — die Summe unter der Anzahl (Offene
   Posten: markierte Zeilen). Kleiner und ruhiger als der Hauptwert, damit die
   Kachel eine Aussage behaelt und nicht zwei gleich laute. */
.stat-sub {
    font-size: 0.95rem;
    color: var(--color-text-muted);
}

/* Der Knopf "Alle Kapitel" in der Titelzeile: er soll nicht so laut sein wie
   eine Handlung in einer Maske, deshalb umrandet statt gefuellt. Zwei Klassen
   im Waehler, damit er die Fuellung von .button-primary sicher ueberschreibt —
   bei gleicher Staerke haenge es an der Reihenfolge in der Datei. */
.button-primary.hb-knopf {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-left: auto;
    padding: 0.45rem 0.9rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    text-decoration: none;
    font-size: 0.88rem;
}

.button-primary.hb-knopf:hover {
    background: var(--color-bg);
    border-color: var(--color-primary);
}

/* ---------- Online-Handbuch ----------
   Text links, Kapitelliste und Inhaltsverzeichnis rechts. Die Textspalte ist
   auf 68 Zeichen begrenzt (max-width in ch): laengere Zeilen liest man beim
   Zeilenwechsel schlechter, und ein Handbuch wird gelesen, nicht ueberflogen.
   ------------------------------------------------------------------------- */
.hb-raster {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17rem;
    gap: 1.25rem;
    align-items: start;
}

/* Der Textblock nimmt die GANZE Spalte.
   Er war auf 68 Zeichen begrenzt — die klassische Leseweite. Auf breiten
   Schirmen stand die Karte damit aber links und rechts davon blieb leere
   Fläche, was aussah wie ein Fehler im Layout. Die Zeilen sind jetzt länger;
   dafür ist der Block ein Block. Die Spalte selbst ist ohnehin begrenzt (das
   Band ist 1180px breit), es werden also keine 200 Zeichen. */
.hb-text {
    width: 100%;
}

/* Abstaende der Prosa. Die Regeln greifen nur INNERHALB von .hb-text, damit
   sie nicht in die Masken der Anwendung ausstrahlen. */
.hb-text h2 {
    margin: 2rem 0 0.75rem;
    font-size: 1.2rem;
}

.hb-text h2:first-child {
    margin-top: 0;
}

.hb-text h3 {
    margin: 1.5rem 0 0.5rem;
    font-size: 1rem;
}

.hb-text p,
.hb-text li {
    line-height: 1.65;
}

/* Die Punkte AUSDRUECKLICH wieder einschalten: die Anwendung stellt Listen
   global ohne Zeichen dar (Menues, Kacheln, Trefferlisten sind Listen im
   HTML-Sinn). Im Handbuch ist eine Aufzaehlung aber genau das und soll wie eine
   aussehen. */
.hb-text ul,
.hb-text ol {
    margin: 0.75rem 0;
    padding-left: 1.4rem;
    list-style-position: outside;
}

.hb-text ul {
    list-style-type: disc;
}

.hb-text ol {
    list-style-type: decimal;
}

.hb-text li::marker {
    color: var(--color-primary);
}

.hb-text li {
    margin: 0.35rem 0;
}

.hb-text code {
    padding: 0.1rem 0.35rem;
    border-radius: 0.25rem;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    font-size: 0.9em;
}

/* Hinweisblock (`>` im Text): abgesetzt, aber keine Warnung — deshalb die
   Markenfarbe an der Kante und kein Rot. */
.hb-text blockquote {
    margin: 1rem 0;
    padding: 0.8rem 1rem;
    border-left: 3px solid var(--color-primary);
    background: var(--color-primary-soft);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: 0.95rem;
}

/* Tabellen im Handbuch rollen in ihrem eigenen Kasten, damit eine breite
   Tabelle nicht die ganze Seite quer schiebt. */
.hb-tabelle {
    overflow-x: auto;
    margin: 1rem 0;
}

.hb-tabelle table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.hb-tabelle th,
.hb-tabelle td {
    padding: 0.5rem 0.7rem;
    text-align: left;
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}

.hb-tabelle th {
    background: var(--color-bg);
    font-weight: 600;
}

/* Blaettern am Fuss der Seite: zurueck links, weiter rechts. */
.hb-blaettern {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 2.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
    font-size: 0.9rem;
}

.hb-blaettern a {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    text-decoration: none;
}

/* ---------- Navigation rechts neben dem Text ----------
   Keine Karten mehr: Ueberschrift in Grossbuchstaben, Liste an einer
   senkrechten Schiene, das aktuelle Kapitel mit farbigem Balken. Die Leiste
   laeuft beim Rollen mit, damit sie in einem langen Kapitel erreichbar bleibt. */
.hb-nav {
    position: sticky;
    top: 1rem;
    display: grid;
    gap: 1.75rem;
    /* Die Schrift eine Nummer kleiner als im Text: die Leiste begleitet, sie
       konkurriert nicht. */
    font-size: 0.86rem;
}

.hb-nav-gruppe h2 {
    margin: 0 0 0.7rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

/* Die Schiene: EINE Linie fuer die ganze Liste, nicht je Eintrag ein Rahmen.
   Der Balken des aktiven Eintrags liegt darauf. */
.hb-nav-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    border-left: 2px solid var(--color-border);
}

.hb-nav-liste li {
    position: relative;
}

.hb-nav-liste a {
    display: block;
    padding: 0.35rem 0 0.35rem 0.85rem;
    color: var(--color-text-muted);
    text-decoration: none;
    line-height: 1.45;
    transition: color var(--duration) var(--ease);
}

.hb-nav-liste a:hover {
    color: var(--color-text);
}

/* Der Balken auf der Schiene — ein ::before am <li>, damit er die ganze Hoehe
   des Eintrags hat, auch wenn der Titel zwei Zeilen braucht. */
.hb-nav-liste li::before {
    content: "";
    position: absolute;
    left: -2px;
    top: 0;
    bottom: 0;
    width: 2px;
    background: transparent;
    transition: background var(--duration) var(--ease);
}

/* `:not(.hb-nav-aktiv)` statt `!important`: die Hover-Regel waere sonst
   staerker (0,2,2 gegen 0,1,1) und ueberdeckte den farbigen Balken des
   aktuellen Kapitels, sobald die Maus darueber steht. Wer den Ausschluss in den
   Waehler schreibt, braucht kein !important — und die naechste Regel bleibt
   berechenbar. */
.hb-nav-liste li:not(.hb-nav-aktiv):hover::before {
    background: var(--color-text-muted);
}

/* ZWEI Klassen im Waehler, und das ist der Grund: `.hb-nav-liste li::before`
   weiter oben setzt `background: transparent` und ist mit (0,1,2) STAERKER als
   `.hb-nav-aktiv::before` mit (0,1,1) — der Balken des aktuellen Kapitels blieb
   damit unsichtbar, nachgemessen rgba(0,0,0,0). Mit der Listenklasse davor sind
   es (0,2,1) und die Regel gewinnt. */
.hb-nav-liste .hb-nav-aktiv::before {
    background: var(--color-primary);
}

.hb-nav-aktiv > a {
    color: var(--color-primary);
    font-weight: 600;
}

/* Kapitelliste der Uebersicht */
.hb-kapitel {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0.75rem;
}

.hb-kapitel a {
    display: flex;
    align-items: center;
    /* Der Titel nimmt den Platz, der Pfeil bleibt rechts stehen. */
    justify-content: space-between;
    gap: 0.7rem;
    padding: 1rem 1.1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    text-decoration: none;
    font-weight: 500;
    transition: border-color var(--duration) var(--ease), transform var(--duration) var(--ease),
        box-shadow var(--duration) var(--ease);
}

.hb-kapitel a:hover {
    border-color: var(--color-primary);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}

.hb-kapitel-pfeil {
    flex: 0 0 auto;
    color: var(--color-text-muted);
    transition: transform var(--duration) var(--ease), color var(--duration) var(--ease);
}

/* Der Pfeil rueckt beim Ueberfahren ein Stueck in seine Richtung — dieselbe
   Bewegung wie am Knopf der dunklen Tafel auf der Anmeldeseite. */
.hb-kapitel a:hover .hb-kapitel-pfeil {
    color: var(--color-primary);
    transform: translateX(3px);
}

/* ---------- Suchleiste des Handbuchs ----------
   Sie sah zuerst aus wie nichts, und der Grund ist eine Kleinigkeit mit grosser
   Wirkung: die Feldregeln der Anwendung stehen an
   `.search-form input[type="text"]` — mein Feld ist ein `type="search"` und
   bekam davon NICHTS ab. Es stand als Browservorgabe da: 24px hoch, schwarzer
   Rand, kein Radius, und im Dunkelmodus weiss auf dunkler Seite.

   Deshalb hier eigene Regeln, aber mit denselben Werten wie die Suchleisten der
   Masken (Polster, Radius, Fokusring aus --color-primary-soft): das Handbuch
   soll nicht wie ein zweites Programm aussehen. */
.hb-suche {
    display: flex;
    gap: 0.6rem;
    margin-top: 1rem;
}

/* Der Kasten um Zeichen und Feld. position: relative, weil das Zeichen darin
   absolut sitzt; `flex: 1` mit `min-width: 0`, damit das Feld schrumpfen DARF —
   ohne min-width:0 bleibt ein Eingabefeld auf seiner Inhaltsbreite stehen und
   schiebt den Knopf aus der Zeile. */
.hb-suche-feld {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
}

.hb-suche-feld .icon {
    position: absolute;
    left: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--color-text-muted);
    pointer-events: none;
}

/* Das Polster fuer die Lupe steht NICHT hier, sondern hinter dem gemeinsamen
   Block ("Felder mit einem Zeichen darin"). */
.hb-suche input {
    width: 100%;
    min-width: 0;
    font-family: inherit;
    font-size: 0.95rem;
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}/* ═══════════════════════════════════════════════════════════════════════════
   EIN FOKUS FUER ALLE EINGABEFELDER
   ═══════════════════════════════════════════════════════════════════════════
   Dieser Block stand ELFMAL in der Datei — Wort fuer Wort derselbe, einmal je
   Maske mit eigenen Feldern (Anmeldung, Suchleiste, Auswahl, Sammelzahlung,
   Formularraster, Mailmaske, Kontenfilter, Zeilenraster, Dialogsuche,
   CRS-Zeile, Handbuchsuche).

   Elf Kopien heisst: wer den Fokusrahmen aendert, aendert ihn an zehn Stellen
   und vergisst die elfte. Genau so entsteht eine Maske, in der der Fokus
   anders aussieht als ueberall sonst — und niemand weiss, ob das Absicht war.

   Sie steht auf OBERSTER EBENE (nicht in einer Medienabfrage) und an der
   spaetesten Stelle, an der eine der Kopien stand.
   ═══════════════════════════════════════════════════════════════════════════ */
.auth-card input:focus,
.search-form input[type="text"]:focus,
.search-form input[type="date"]:focus,
.search-form select:focus,
.totp-form input[type="text"]:focus,
.auswahl-suche input:focus,
.sammel-liste input[type="text"]:focus,
.form-grid input:not([type="checkbox"]):not([type="radio"]):focus,
.form-grid select:focus,
.form-grid textarea:focus,
.inline-edit-form input:not([type="checkbox"]):not([type="radio"]):focus,
.inline-edit-form select:focus,
.mail-compose-form input:focus,
.mail-compose-form textarea:focus,
.konten-filterfeld input:focus,
.row-grid input:focus,
.row-grid select:focus,
.modal-search input:focus,
.crs-zeile input:focus,
.crs-zeile select:focus,
.hb-suche input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: var(--fokus-ring);
}

/* ═══════════════════════════════════════════════════════════════════════════
   EIN AUSSEHEN FUER ALLE EINGABEFELDER
   ═══════════════════════════════════════════════════════════════════════════
   Dieselbe Auswahl wie der Fokus darueber, nur ohne :focus — und aus demselben
   Grund an einer Stelle: Rahmen, Radius und Polster eines Feldes standen in elf
   Masken elfmal, und sie waren dabei laengst nicht mehr gleich (0,45 / 0,5 /
   0,6 rem Polster, zwei Radien, zwei Rahmenfarben). Elf Kopien laufen
   auseinander; man sieht es erst, wenn zwei Masken nebeneinander offen sind.

   DIE WERTE SIND DIE DES FLIGHT-IMPORTERS (.field-input dort): weisse Flaeche,
   ein Pixel kraeftiger Rahmen, 8 px Polster oben/unten und 11 px seitlich, der
   flache Schatten aller Bedienelemente. Der Rahmen traegt --color-border-strong
   und nicht den Trennlinien-Ton: ein Feld ist kein Strich, sondern etwas zum
   Hineinschreiben, und mit demselben Wert war auf einer Maske mit dreissig
   Feldern nicht zu sehen, wo eines aufhoert und die naechste Linie anfaengt.

   Die HOEHE steht nicht hier, sondern als --hoehe-feld an den Masken: ein Feld
   und der Knopf daneben muessen gleich hoch sein, und das entscheidet die
   Marke, nicht dieser Block.
   ═══════════════════════════════════════════════════════════════════════════ */
.auth-card input,
.search-form input[type="text"],
.search-form input[type="date"],
.search-form select,
.totp-form input[type="text"],
.auswahl-suche input,
.sammel-liste input[type="text"],
.form-grid input:not([type="checkbox"]):not([type="radio"]),
.form-grid select,
.form-grid textarea,
.inline-edit-form input:not([type="checkbox"]):not([type="radio"]),
.inline-edit-form select,
.mail-compose-form input,
.mail-compose-form textarea,
.konten-filterfeld input,
.row-grid input,
.row-grid select,
.modal-search input,
.crs-zeile input,
.crs-zeile select,
.hb-suche input {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    /* Seitlich die 11 px des Importers. OBEN UND UNTEN WENIGER als seine 8:
       seine Felder haben keine gesetzte Hoehe und wachsen mit dem Polster,
       unsere sind 34 px hoch (siehe --hoehe-feld). Bei 8 px blieben davon 16 px
       fuer eine Zeile von knapp 22 — genug, um Unterlaengen abzuschneiden. */
    padding: 0.35rem 0.7rem;
    box-shadow: var(--shadow-sm);
}

/* Mehrzeilige Felder haben KEINE gesetzte Hoehe, sie wachsen mit dem Inhalt —
   dort passt das Polster des Importers unveraendert. */
.form-grid textarea,
.mail-compose-form textarea {
    padding: 0.5rem 0.7rem;
}

/* Beim Ueberfahren derselbe Sprung wie am Knopf: der Rahmen wird dunkler, sonst
   aendert sich nichts. Eine Farbe waere hier zu viel — auf einer Maske mit
   dreissig Feldern faehrt der Zeiger staendig ueber eines. */
.auth-card input:hover,
.search-form input[type="text"]:hover,
.search-form input[type="date"]:hover,
.search-form select:hover,
.totp-form input[type="text"]:hover,
.auswahl-suche input:hover,
.sammel-liste input[type="text"]:hover,
.form-grid input:not([type="checkbox"]):not([type="radio"]):hover,
.form-grid select:hover,
.form-grid textarea:hover,
.inline-edit-form input:not([type="checkbox"]):not([type="radio"]):hover,
.inline-edit-form select:hover,
.mail-compose-form input:hover,
.mail-compose-form textarea:hover,
.konten-filterfeld input:hover,
.row-grid input:hover,
.row-grid select:hover,
.modal-search input:hover,
.crs-zeile input:hover,
.crs-zeile select:hover,
.hb-suche input:hover {
    border-color: var(--color-text-muted);
}

.auth-card input::placeholder,
.search-form input[type="text"]::placeholder,
.search-form input[type="date"]::placeholder,
.totp-form input[type="text"]::placeholder,
.auswahl-suche input::placeholder,
.sammel-liste input[type="text"]::placeholder,
.form-grid input:not([type="checkbox"]):not([type="radio"])::placeholder,
.form-grid textarea::placeholder,
.inline-edit-form input:not([type="checkbox"]):not([type="radio"])::placeholder,
.mail-compose-form input::placeholder,
.mail-compose-form textarea::placeholder,
.konten-filterfeld input::placeholder,
.row-grid input::placeholder,
.modal-search input::placeholder,
.crs-zeile input::placeholder,
.hb-suche input::placeholder {
    color: var(--color-text-subtle);
}

/* FELDER MIT EINEM ZEICHEN DARIN brauchen links Platz dafuer, sonst steht die
   Lupe auf dem ersten Buchstaben. Das Polster steht HIER und nicht an den
   Masken: der gemeinsame Block darueber setzt es, und er steht spaeter in der
   Datei als sie. */
.konten-filterfeld input {
    padding-left: 2.25rem;
}

.hb-suche input {
    padding-left: 2.5rem;
}

/* NUR ZUM LESEN: graue Flaeche statt weisser. Das ist die einzige Auskunft, die
   ein Feld darueber geben kann, bevor man hineinklickt. */
input[readonly],
textarea[readonly] {
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    cursor: not-allowed;
}

/* DER PFEIL DER AUSWAHLFELDER ist selbst gezeichnet — zwei Farbverlaeufe, die
   sich zu einem Dreieck ergaenzen (so macht es der Flight-Importer). Der Pfeil
   des Betriebssystems sieht auf jedem Rechner anders aus und traegt seine
   eigene Groesse; in einer Zeile aus Textfeld, Datumsfeld und Auswahlfeld war
   er das einzige Stueck, das nicht zur Maske gehoerte.

   currentColor: damit folgt er der Schriftfarbe und stimmt in Hell und Dunkel
   von selbst. */
.search-form select,
.form-grid select,
.inline-edit-form select,
.row-grid select,
.crs-zeile select {
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
    padding-right: 2rem;
    background-image:
        linear-gradient(45deg, transparent 50%, currentColor 50%),
        linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 0.85rem center, right 0.55rem center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}

.hb-suche input:focus + .icon,
.hb-suche-feld:focus-within .icon {
    color: var(--color-primary);
}

/* Das X, mit dem Chrome ein Suchfeld leert, sitzt sonst hart am rechten Rand. */
.hb-suche input::-webkit-search-cancel-button {
    margin-right: 0.15rem;
}

.hb-suche button {
    flex: 0 0 auto;
    padding: 0.6rem 1.4rem;
    font-size: 0.95rem;
    white-space: nowrap;
}

/* ---------- Trefferliste ---------- */
.hb-treffer {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 0;
    display: grid;
    gap: 0.6rem;
}

.hb-treffer li {
    display: grid;
    gap: 0.3rem;
    padding: 1rem 1.1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    transition: border-color var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.hb-treffer li:hover {
    border-color: var(--color-primary);
    transform: translateY(-1px);
}

/* Der Kapitelname ist der Verweis und soll wie eine Ueberschrift lesen, nicht
   wie ein Link mitten im Text. */
.hb-treffer a {
    font-size: 1rem;
    font-weight: 600;
    text-decoration: none;
}

.hb-treffer span {
    font-size: 0.88rem;
    line-height: 1.55;
    color: var(--color-text-muted);
}

/* Der gefundene Begriff in der Textstelle. Nicht das Gelb des Browsers: es
   passt in keines der beiden Themen und ist im Dunkelmodus grell. */
.hb-treffer mark {
    background: var(--color-primary-soft);
    color: var(--color-primary);
    border-radius: 0.2rem;
    padding: 0 0.15rem;
    font-weight: 600;
}

/* Hinweis "noch nicht uebersetzt" */
.hb-hinweis {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0.6rem 0.9rem;
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--color-warning) 12%, transparent);
    color: var(--color-warning-text);
    font-size: 0.88rem;
}

@media (max-width: 900px) {
    /* Einspaltig, und die Kapitelliste WANDERT NACH UNTEN: auf einem Telefon
       will man zuerst den Text sehen, nicht das Verzeichnis. */
    .hb-raster {
        grid-template-columns: 1fr;
    }

    /* Untereinander laeuft die Navigation nicht mit: sie steht dann UNTER dem
       Text, und ein mitlaufender Kasten am Seitenende ist sinnlos. (Die Regel
       hiess bis zur Umgestaltung .hb-seitenleiste und griff seit dem
       Umbenennen ins Leere — nachgemessen: position blieb sticky.) */
    .hb-nav {
        position: static;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIE OEFFENTLICHE REISESEITE (/reise/{token})
   ═══════════════════════════════════════════════════════════════════════════
   Eine Seite fuer den KUNDEN, nicht fuer den Sachbearbeiter: keine
   Seitenleiste, keine Kopfzeile, eine Spalte, groessere Schrift, mehr Luft.

   Sie benutzt DIESELBEN MARKEN wie das Backoffice (Farben, Abstaende, Radien,
   Fokus) — ein zweites Farbsystem waere eine zweite Wahrheit ueber den Auftritt
   des Hauses. Was hier steht, sind nur die Formen, die es im Backoffice nicht
   gibt: der Reisebuerokopf, die Leistungskarten, die Betragsliste.

   HELL, ohne Dunkelmodus: die Kundenseite folgt dem Auftritt des Reisebueros
   und nicht der Bildschirmvorliebe des Betrachters. Deshalb steht am <html>
   data-theme="light" — die Farbtabelle des Dunkelmodus greift damit nicht,
   ohne dass hier eine einzige Farbe doppelt definiert werden muss.
   ═══════════════════════════════════════════════════════════════════════════ */

.reise-body {
    /* ───────────────────────────────────────────────────────────────────────
       EINE SPALTE FUER KOPF, INHALT UND FUSS
       ───────────────────────────────────────────────────────────────────────
       Vorher hatte der Kopf 46rem, die Anmeldekarte 30rem und der Fuss wieder
       46rem. Damit stand nichts ueber irgendetwas: das Logo hing links neben
       der Karte, die Kontaktzeile rechts daneben, der Fuss noch einmal woanders
       — drei Kanten auf einer Seite, die zwei Angaben zeigt.

       Jetzt nennt EINE Marke die Spalte, und alle drei folgen ihr. Das Logo
       steht ueber der linken Kante des Inhalts, die Kontaktzeile ueber der
       rechten. */
    --reise-spalte: 46rem;
    background: var(--color-bg);
    color: var(--color-text);
    /* Die Seite fuellt den Schirm. Sonst endete der Fuss auf halber Hoehe, und
       darunter stand ein grauer Streifen, der aussieht, als fehle noch etwas. */
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Anmeldung und Hinweisseite tragen EINE schmale Karte — dort ist die ganze
   Seite schmaler, Kopf und Fuss eingeschlossen. */
.reise-body-schmal {
    --reise-spalte: 34rem;
}

/* ---------------------------------------------------------------------------
   KOPF: Logo und Reisebuero
   ---------------------------------------------------------------------------
   Das Logo ist eine feste Hoehe und keine feste Breite: Briefkoepfe sind quer
   (oft 520x90), und eine Breitenvorgabe haette sie verzerrt oder winzig
   gemacht. Fehlt das Logo, stehen Name und Anschrift allein — ohne leeren
   Kasten davor.
   --------------------------------------------------------------------------- */
.reise-kopf {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.reise-kopf-inhalt,
.reise-inhalt,
.reise-fuss-inhalt {
    max-width: var(--reise-spalte);
    margin: 0 auto;
    /* width statt nur max-width: als Flexkind der Seite wuerde der Kasten sonst
       auf seinen Inhalt schrumpfen und die Zentrierung ginge verloren. */
    width: 100%;
    padding: var(--space-6) var(--space-4);
}

/* Logo links, Haus rechts — der Aufbau eines Briefkopfs. Auf dem Telefon
   stehen sie untereinander und beide linksbuendig (siehe ganz unten). */
.reise-kopf-inhalt {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.reise-kopf-text {
    text-align: right;
}

.reise-kopf-text .reise-kontaktzeile {
    justify-content: flex-end;
}

/* ---------------------------------------------------------------------------
   AUF DER SCHMALEN SEITE STEHT DER BRIEFKOPF UNTEREINANDER
   ---------------------------------------------------------------------------
   In 34rem passen ein Logo und ein Hausname wie "Altay Reisen GmbH - Zuerich"
   nicht nebeneinander. Der Kasten brach dann von selbst um — und weil die
   Angaben rechtsbuendig stehen, landeten sie versetzt UNTER dem Logo: es sah
   aus, als seien zwei Bloecke verrutscht.

   Untereinander und links ist es kein Notbehelf, sondern die ruhigere Form:
   Logo, darunter das Haus, beides an derselben Kante wie die Karte. */
.reise-body-schmal .reise-kopf-inhalt {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
}

.reise-body-schmal .reise-kopf-text {
    text-align: left;
}

.reise-body-schmal .reise-kopf-text .reise-kontaktzeile {
    justify-content: flex-start;
}

.reise-logo {
    height: 44px;
    width: auto;
    /* Hoechstens zwei Fuenftel der Zeile. Ein breiter Briefkopf (die gibt es
       mit 520x90) sprengte sonst den Kopf: Logo und Hausangaben passten nicht
       mehr nebeneinander, die Zeile brach um, und die rechtsbuendigen Angaben
       standen ploetzlich unter dem Logo statt daneben.

       object-fit haelt dabei das Seitenverhaeltnis — ohne es wuerde das Bild in
       den schmaleren Kasten gequetscht. */
    max-width: 40%;
    object-fit: contain;
    object-position: left center;
}

.reise-haus {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
}

.reise-haus-zusatz,
.reise-haus-zeile {
    margin: 0.15rem 0 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* Telefon und E-Mail sind auf dem Telefon die wichtigsten Handlungen der Seite
   — sie sind Verweise (tel:/mailto:) und duerfen wie solche aussehen. */
.reise-kontaktzeile {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.reise-kontaktzeile a,
.reise-fuss a {
    color: var(--color-primary);
    font-weight: 500;
}

/* ---------------------------------------------------------------------------
   INHALT
   --------------------------------------------------------------------------- */
.reise-inhalt {
    /* Der Inhalt nimmt den uebrigen Platz — damit steht der Fuss am unteren
       Rand und nicht auf halber Hoehe. */
    flex: 1 0 auto;
    padding-top: var(--space-4);
    padding-bottom: var(--space-6);
}

.reise-karte {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    /* Ringsum dasselbe Polster. Vorher war es oben 24 und seitlich 16 px — die
       Ueberschrift stand damit naeher an der linken Kante als am oberen Rand,
       und die Karte wirkte angeschnitten. */
    padding: var(--space-6);
    margin-bottom: var(--space-4);
}

.reise-abschnitt {
    margin-bottom: var(--space-6);
}

.reise-abschnitt > h2 {
    margin: 0 0 var(--space-3);
    font-size: 0.82rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
}

.reise-inhalt h1 {
    margin: 0 0 var(--space-2);
    font-size: 1.5rem;
}

.reise-hinweis {
    margin: 0 0 var(--space-4);
    color: var(--color-text-muted);
    line-height: 1.5;
}

.reise-hinweis-warnung {
    color: var(--color-warning-text);
    margin-top: var(--space-3);
    margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
   PAARE (Beschriftung / Wert) — die Grundform der ganzen Seite
   ---------------------------------------------------------------------------
   Zwei Spalten auf dem Schirm, eine auf dem Telefon: die Beschriftung steht
   dort UEBER dem Wert und nicht daneben in 90 Pixeln. Kein <table>, weil das
   hier keine Tabelle ist — es sind Angaben zu einem Gegenstand.
   --------------------------------------------------------------------------- */
.reise-daten,
.reise-paare,
.reise-betraege,
.reise-fristen {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--space-2) var(--space-4);
    margin: 0;
}

.reise-daten dt,
.reise-paare dt,
.reise-betraege dt,
.reise-fristen dt {
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

/* ZWEI Spalten statt des allgemeinen Rasters — fuer Bloecke, deren Angaben
   paarweise zusammengehoeren (Transfer: Datum und Uhrzeit eines Weges). Steht
   NACH der Regel oben, damit sie deren auto-fit ueberschreibt. */
.reise-paare-zwei {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 560px) {
    .reise-paare-zwei {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Ein Paar ueber die ganze Rasterbreite — fuer Freitext (Bezeichnung, Extras).
   1 / -1 und nicht span 2: die Spaltenzahl des Rasters steht nicht fest
   (auto-fit), und ein fester Sprung wuerde auf dem Telefon eine Spalte
   erzwingen, die es dort nicht gibt. */
.reise-paare .reise-paar-breit {
    grid-column: 1 / -1;
}

.reise-daten dd,
.reise-paare dd,
.reise-betraege dd,
.reise-fristen dd {
    margin: 0.1rem 0 0;
    font-size: 1rem;
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   LEISTUNGEN
   --------------------------------------------------------------------------- */
.reise-leistung {
    padding: var(--space-4);
}

.reise-leistung-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--color-border);
}

.reise-leistung-kopf h3 {
    margin: 0;
    font-size: 1rem;
}

.reise-leistung-zeit {
    margin: 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.reise-leistung-ziel {
    margin: 0 0 var(--space-3);
    font-weight: 600;
}

/* Mehrere Zeilen einer Art (zwei Fluege in einer Leistung) durch eine feine
   Linie getrennt — sonst laufen Hin- und Rueckflug ineinander. */
.reise-leistung .reise-paare + .reise-paare {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px dashed var(--color-border);
}

/* ---------------------------------------------------------------------------
   FLUEGE UND FAHRTEN ALS TABELLE
   ---------------------------------------------------------------------------
   Mehrere Segmente mit immer denselben Angaben: die Beschriftung steht einmal
   oben, darunter ein Segment je Zeile. Als Paare stand jedes der neun Woerter
   je Segment noch einmal da — bei vier Flugsegmenten sechsunddreissig
   Beschriftungen fuer zwoelf Zahlen, die man vergleichen will.

   Der Behaelter rollt, nicht die Seite: neun Spalten passen auf kein Telefon,
   und waagerecht rollen darf immer nur der Kasten, in dem das breite Ding
   steht. */
.reise-tabelle-rolle {
    overflow-x: auto;
    /* Fokusrahmen und Kanten der Zellen nicht anschneiden. */
    padding-bottom: 2px;
}

/* Dieselbe Trennung wie zwischen zwei Paargruppen: in EINER Karte koennen
   Tabelle und Paare aufeinander folgen (Pauschalreise — Fluege als Tabelle,
   darunter Hotel und Transfer als Paare), und ohne Linie beginnt das Hotel
   unmittelbar unter der letzten Flugzeile. */
.reise-leistung .reise-tabelle-rolle + .reise-paare,
.reise-leistung .reise-paare + .reise-tabelle-rolle,
.reise-leistung .reise-tabelle-rolle + .reise-tabelle-rolle,
/* Seit die Fluege Bordkarten sind, folgt auf sie dasselbe: bei einer
   Pauschalreise steht das Hotel unmittelbar unter dem Rueckflug, und ohne
   Linie beginnt "Anreise" direkt unter "SunExpress". */
.reise-leistung .reise-flugrichtung + .reise-paare,
.reise-leistung .reise-paare + .reise-flugrichtung,
.reise-leistung .reise-flugrichtung + .reise-tabelle-rolle,
.reise-leistung .reise-tabelle-rolle + .reise-flugrichtung {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px dashed var(--color-border);
}

.reise-tabelle {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.95rem;
}

.reise-tabelle th,
.reise-tabelle td {
    /* nowrap: ein umgebrochenes "03.10.2026" oder "12:55" ist schlechter zu
       lesen als eine rollende Tabelle. */
    white-space: nowrap;
    text-align: left;
    padding: var(--space-2) var(--space-3) var(--space-2) 0;
}

.reise-tabelle th {
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--color-text-muted);
    border-bottom: 1px solid var(--color-border);
}

.reise-tabelle td {
    font-weight: 600;
    border-bottom: 1px dashed var(--color-border);
    /* Ziffern gleicher Breite: Uhrzeiten und Flugnummern stehen damit
       untereinander auf einer Linie. */
    font-variant-numeric: tabular-nums;
}

.reise-tabelle tbody tr:last-child td {
    border-bottom: 0;
}

/* ---------------------------------------------------------------------------
   DER LANGNAME UNTER DEM KUERZEL (Flughafen, Airline)
   ---------------------------------------------------------------------------
   Klein, leicht und in der ruhigen Farbe: das Kuerzel bleibt die Hauptangabe
   — es steht auf der Bordkarte und am Gate —, der Name beantwortet nur, was es
   bedeutet.

   `white-space: normal` gegen das `nowrap` der Zelle: "Frankfurt am Main" in
   einer Zeile machte die Spalte dreimal so breit wie ihre Zahl. Die Breite ist
   gedeckelt, damit die Tabelle davon nicht auseinanderlaeuft.

   Keine Tabellenziffern: die erben sonst von der Zelle und sperren einen Namen
   unnoetig auseinander. */
.reise-code-name {
    display: block;
    max-width: 11rem;
    margin-top: 0.1rem;
    white-space: normal;
    font-size: 0.75rem;
    font-weight: 400;
    line-height: 1.3;
    color: var(--color-text-muted);
    font-variant-numeric: normal;
}

/* ═══════════════════════════════════════════════════════════════════════════
   HINFLUG UND RUECKFLUG
   ═══════════════════════════════════════════════════════════════════════════
   Der Kunde liest hier vor allem zwei Dinge: wann geht es los, und wann bin
   ich zurueck. In EINER Tabelle stand beides untereinander, ohne dass etwas
   sagt, welche Zeile welche Richtung ist — bei vier Segmenten mit
   Zwischenlandung musste man die Flughaefen vergleichen, um das zu sehen.

   Jetzt je Richtung eine eigene kleine Tabelle mit Ueberschrift und Datum.
   Welche Zeile wohin gehoert, entscheidet die laengste Pause zwischen zwei
   Abfluegen (siehe reise-onepager.php).
   --------------------------------------------------------------------------- */
.reise-flugrichtung + .reise-flugrichtung {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px dashed var(--color-border);
}

.reise-flugrichtung-kopf {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-3);
    margin: 0 0 var(--space-2);
}

.reise-flugrichtung-titel {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.reise-flugrichtung-datum {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* Die Flugtabelle steht WEITER auseinander als die uebrigen: ihre Zellen sind
   zweizeilig (Kuerzel oben, Ort darunter), und mit dem engen Spaltenabstand
   der einzeiligen Tabellen liefen "Duesseldorf" und "Antalya" optisch
   ineinander. */
.reise-tabelle-weit th,
.reise-tabelle-weit td {
    padding-right: var(--space-4);
    vertical-align: top;
}

.reise-tabelle-weit th:last-child,
.reise-tabelle-weit td:last-child {
    padding-right: 0;
}

/* ---------------------------------------------------------------------------
   REISENDE
   --------------------------------------------------------------------------- */
.reise-gaeste {
    list-style: none;
    margin: 0;
    padding: 0;
}

.reise-gaeste li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--color-border);
}

.reise-gaeste li:first-child {
    border-top: 0;
}

.reise-gast-name {
    font-weight: 600;
}

.reise-gast-zusatz {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   ZAHLUNG
   ---------------------------------------------------------------------------
   Der offene Betrag ist die Aussage, auf die es ankommt: eigene Flaeche,
   groessere Zahl — und das WORT "Offen" daneben, nicht nur die Farbe (dieselbe
   Regel wie bei den semantischen Flaechen des Backoffice).
   --------------------------------------------------------------------------- */
.reise-offen {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin: var(--space-4) 0 0;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    background: var(--color-warning-soft);
    color: var(--color-warning-text);
}

.reise-offen-label {
    font-weight: 600;
}

.reise-offen-wert {
    font-size: 1.25rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.reise-bezahlt {
    margin: var(--space-4) 0 0;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    background: var(--color-success-soft);
    color: var(--color-success-text);
    font-weight: 600;
}

.reise-fristen {
    margin-top: var(--space-3);
}

/* ---------------------------------------------------------------------------
   ANMELDUNG
   --------------------------------------------------------------------------- */
.reise-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.reise-feld {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.reise-feld > span {
    font-size: 0.85rem;
    font-weight: 600;
}

/* Die Felder sind hoeher als im Backoffice: auf dem Telefon wird hier mit dem
   Daumen getippt, und 44 px ist das Mindestmass fuer eine Beruehrflaeche. */
.reise-feld input {
    height: var(--hoehe-feld);
    font-size: 1rem;
}

.reise-knopf {
    height: var(--hoehe-feld);
    border: 0;
    border-radius: var(--radius);
    background: var(--color-primary);
    color: var(--auf-farbflaeche);
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
}

.reise-knopf:hover {
    background: var(--color-primary-hover);
}

.reise-fehler {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    background: var(--color-danger-soft);
    color: var(--color-danger-text);
    font-weight: 500;
}

.reise-weg-kontakt {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

.reise-weg-kontakt p,
.reise-fuss p {
    margin: 0.15rem 0;
}

/* ---------------------------------------------------------------------------
   FUSS
   --------------------------------------------------------------------------- */
.reise-fuss {
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.reise-fuss-inhalt {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.reise-fuss-name {
    font-weight: 700;
    color: var(--color-text);
}

/* ---------------------------------------------------------------------------
   TELEFON
   ---------------------------------------------------------------------------
   Unter 640 px: eine Spalte, weniger Polster, aber dieselbe Schriftgroesse —
   eine Reiseuebersicht wird auf dem Telefon gelesen, nicht auf dem Schreibtisch.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
    .reise-kopf-inhalt,
    .reise-inhalt,
    .reise-fuss-inhalt {
        padding: var(--space-4) var(--space-3);
    }

    .reise-daten,
    .reise-paare,
    .reise-betraege,
    .reise-fristen {
        grid-template-columns: minmax(0, 1fr);
    }

    .reise-karte {
        padding: var(--space-4) var(--space-3);
    }

    .reise-fuss-inhalt {
        flex-direction: column;
    }

    /* Der Briefkopf steht untereinander — und dann linksbuendig. Rechtsbuendig
       unter einem linken Logo saehe aus wie zwei Bloecke, die nichts
       miteinander zu tun haben. */
    .reise-kopf-text {
        text-align: left;
    }

    .reise-kopf-text .reise-kontaktzeile {
        justify-content: flex-start;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   DER DIALOG "BUCHUNGSLINK" im Buchungsdetail
   ═══════════════════════════════════════════════════════════════════════════ */

.reiselink-box {
    max-width: 40rem;
}

.reiselink-status {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--space-2) var(--space-4);
    margin: 0 0 var(--space-4);
}

.reiselink-status dt {
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

.reiselink-status dd {
    margin: 0.1rem 0 0;
    font-weight: 600;
}

.reiselink-adresse {
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
}

.reiselink-feld {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: var(--space-3);
}

.reiselink-feld > span {
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

/* Die Adresse ist lang und soll ganz markierbar sein — deshalb volle Breite
   und eine Schrift mit gleichen Zeichenbreiten: so sieht man Verwechslungen
   zwischen 0 und O. */
.reiselink-feld input {
    width: 100%;
    font-family: var(--schrift-mono);
    font-size: 0.85rem;
    /* AUSSEHEN UND HOEHE WIE JEDES ANDERE FELD DER ANWENDUNG.
       -----------------------------------------------------------------------
       Rahmen, Rundung, Innenabstand, Flaeche und Schriftfarbe der Felder haengen
       im Stylesheet an `.form-grid` bzw. `.inline-edit-form` — dieser Dialog
       baut seine Zeilen selbst und traegt keine der beiden Klassen. Damit
       zeichnete der Browser seine eigenen Felder: 25px hoch neben einem 44px
       hohen Knopf, und im Dunkelmodus WEISS mit schwarzer Schrift, weil die
       Vorgabe des Browsers die Farbvariablen nicht kennt.

       Die Werte stehen deshalb hier noch einmal — dieselben wie in der Regel
       fuer `.form-grid input`. Wer sie dort aendert, aendert sie hier mit. */
    height: var(--hoehe-feld);
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
}

.reiselink-aktionen {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* ───────────────────────────────────────────────────────────────────────────
   LINK WEITERGEBEN — zwei Zeilen, Feld und Knopf nebeneinander
   ───────────────────────────────────────────────────────────────────────────
   Derselbe Kasten wie die Adresse darueber (gleicher Rahmen, gleiches Radius,
   gleiche Flaeche), damit der Dialog nicht aus zwei Gestaltungen besteht.
   Vorher stand hier ein <fieldset>: dessen Rahmen zeichnet der Browser, und die
   Beschriftung sass in der Rahmenlinie — im Dialog war das der einzige Kasten
   dieser Art. */
.reiselink-senden {
    margin-top: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
}

.reiselink-senden-titel {
    margin: 0 0 0.2rem;
    font-weight: 600;
    font-size: 0.9rem;
}

.reiselink-senden-hinweis {
    margin: 0 0 var(--space-3);
}

/* Feld und Knopf in EINER Zeile: der Knopf gehoert zu dem Feld links von ihm.
   Untereinander sah es aus wie zwei getrennte Aktionen, und die Zuordnung
   ergab sich erst aus der Beschriftung.

   Das Raster liegt um BEIDE Formulare, nicht in jedem einzelnen: nur so ist die
   Knopfspalte fuer beide Zeilen gleich breit. Vorher war jeder Knopf so breit
   wie sein eigener Text ("Per E-Mail senden" 169 px, "Ueber WhatsApp senden"
   205 px) — zwei gleichrangige Aktionen in zwei Breiten.

   Die <form>-Elemente sind darin nur Durchreiche (display: contents): ihre
   Kinder — Feld und Knopf — werden selbst Rasterzellen. Abgeschickt wird
   dadurch nichts anders; das versteckte Token-Feld traegt display:none und
   belegt keine Zelle. */
.reiselink-senden-formulare {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: var(--space-3) var(--space-2);
}

.reiselink-senden-zeile {
    display: contents;
}

.reiselink-senden-zeile .reiselink-feld {
    margin-bottom: 0;
}

/* Die Schrift mit gleichen Zeichenbreiten gilt fuer die ADRESSE, nicht fuer
   eine Mailadresse oder eine Rufnummer — die schreibt man hier hinein, und ein
   Eingabefeld dieser Maske sieht sonst anders aus als jedes andere. */
.reiselink-senden .reiselink-feld input {
    font-family: inherit;
    font-size: 0.95rem;
}

/* Die Hoehe stand hier einmal ausdruecklich auf Feldhoehe, weil der Knopf neben
   einem Eingabefeld steht. Das gilt inzwischen fuer JEDEN Knopf (siehe
   --hoehe-feld), also bleibt hier nur, was diesen einen betrifft. */
.reiselink-senden-zeile .export-button {
    white-space: nowrap;
}

@media (max-width: 560px) {
    .reiselink-senden-formulare {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--space-2);
    }

    .reiselink-senden-zeile .export-button {
        justify-content: center;
    }
}

.reiselink-aktionen-fuss {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
    justify-content: space-between;
}

/* Die Marke am Knopf der Kopfzeile: kleiner als ein Statusabzeichen in einer
   Liste, damit der Knopf nicht wandert. */
.reiselink-marke {
    margin-left: 0.35rem;
    font-size: 0.68rem;
    padding: 0.05rem 0.4rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   WENIGER BEWEGUNG, WENN DER RECHNER DARUM BITTET
   ═══════════════════════════════════════════════════════════════════════════
   `prefers-reduced-motion` ist keine Geschmackseinstellung. Wer sie setzt, tut
   das meist wegen Schwindel oder Migraene — Bewegung im Randbereich des Blicks
   loest das aus, und diese Anwendung hat davon einiges: Uebergaenge an Knoepfen,
   Feldern, Menuepunkten und Aufklappfeldern, dazu die Zeitachse der Diagramme
   und ein drehender Ring am absendenden Formular.

   Abgeschaltet wird nicht die Auskunft, sondern ihr Weg: aus dem Uebergang wird
   ein Sprung. Man sieht weiterhin, dass ein Knopf reagiert — nur nicht mehr,
   wie er dorthin kommt.

   DER SPINNER BLEIBT, LANGSAMER. Er ist die einzige Bewegung hier, die selbst
   die Auskunft IST ("es laeuft noch"). Stuende er still, waere er ein Ring, der
   nichts sagt, und der Anwender klickte ein zweites Mal ab. Zwei Sekunden statt
   0,7 sind ruhig genug — die Empfehlung lautet, Wesentliches zu verlangsamen
   und nicht zu entfernen.

   `scroll-behavior: auto` gehoert dazu: ein sanft gerollter Sprung ist
   dieselbe Bewegung, nur ueber die ganze Seite.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        transition-delay: 0ms !important;
        scroll-behavior: auto !important;
    }

    .spinner {
        animation-duration: 2s !important;
        animation-iteration-count: infinite !important;
    }
}
