/* bulung.css · v1 · 2026-10-01 · sha256 1af769b9f5a4e585a92d602559a083ea624b02d243640bb3b44489c02d70f54e */
/* Erzeugt von baue.mjs. NICHT von Hand aendern — die naechste Erzeugung
   ueberschreibt jede Handarbeit, und der Waechter meldet sie vorher. */

/* ── tokens/colors.css ───────────────────────────────────────────────── */
/* Bulung Logistics — Farben
   ==========================================================================
   Quelle der Markenfarben ist das CI-Booklet von dotsandlines, Seite 6.
   Dort stehen sie woertlich: Bulung Green #a2c629 (RAL 120 70 70,
   Pantone 2299 C), Ocean Blue #040c2c (RAL 5011, Pantone 534 C).
   Waehrend der Aufraeumarbeit am 2026-08-29 waren DREI verschiedene Gruens
   im Umlauf (#a2c629 in den Token, #a1c52b im Vektorlogo, #94cc4e in den
   PNG-Assets). Es gilt genau eines: #a2c629.

   ZWEI REGISTER. Hell steht auf :root, Dunkel unter [data-register="dunkel"].
   Beide tragen DIESELBEN Namen mit anderen Werten — das ist die Bedingung
   dafuer, dass Penpot sie als zwei Token-Themes fuehren kann.
   Achtung: bulung-at-dashboard und bulung-daily-report drehen das um (dunkel
   ist dort der Grundzustand, hell die Ausnahme). Die WERTE sind dieselben.

   ALLE KONTRASTE SIND GERECHNET, NICHT GESCHAETZT — `node tokens/kontrast.mjs`
   rechnet sie nach. Wer hier einen Wert aendert, laesst das Skript laufen.
   ========================================================================== */

:root {
  /* ---- Marke (registerneutral, aus dem CI-Booklet) ---- */
  --green: #a2c629;          /* Bulung Green — RAL 120 70 70 · Pantone 2299 C */
  --navy: #040c2c;           /* Ocean Blue — RAL 5011 · Pantone 534 C */
  --grey-dark: #8a8b8b;      /* CI "Dark Grey" · RAL 9005 */
  --grey-light: #f0f0f1;     /* CI "Light Grey" */
  --white: #ffffff;

  /* Das CI nennt --grey-dark "Font Color". Auf Weiss traegt es 3,42 : 1 und
     faellt damit durch 1.4.3. Es ist hier eine DEKORFARBE (Linien, Symbole,
     ausgegraute Flaechen). Fuer Text steht --text-muted bereit. */

  /* ---- Marke abgeleitet ---- */
  --navy-light: #0a1540;                    /* navy aufgehellt, Hover auf Navy */
  --navy-hover: #1b2758;                    /* Hover des Hauptknopfs — sichtbar heller als Navy, Weiss darauf 14,2 : 1 */
  --green-hover: #93b622;                   /* im Hellregister geht Hover nach UNTEN */
  --green-deep: #6f9018;                    /* dunkle Kante fuer Balken und Ringe */
  --green-light: rgba(162, 198, 41, 0.14);  /* leiser Gruenschleier */
  --green-medium: rgba(162, 198, 41, 0.26); /* mittlerer Gruenschleier */

  /* ---- Gruen als TINTE ----
     #a2c629 auf Weiss sind 1,97 : 1. Als Text, Symbol oder Fokusring ist die
     Markenfarbe damit unbrauchbar. Diese zwei Werte sind der Ersatz; sie
     stammen aus bulung-at-dashboard/src/app.css und sind dort nachgerechnet. */
  --green-ink: #3f6a0f;        /* Gruen als Text/Symbol — 6,40 : 1 auf Weiss */
  --green-ink-hover: #35590c;  /* dessen Hover */
  --focus-ring: #3d6205;       /* Fokusring — 7,12 : 1 auf Weiss */

  /* ---- Flaechenleiter (7 Stufen) ----
     Die Reihenfolge ist die Auskunft: eingelassen -> Grund -> Papier ->
     Bedienflaeche -> Hover -> Ueberlagerung.

     SEIT DEM 23.09.2026 NEUTRAL STATT BLAUSTICHIG. Die alte Leiter
     (#e8ecf4, #e4ebfa …) legte einen hellblauen Schleier ueber jede Flaeche;
     neben Ocean Blue als Schrift wirkte das Ganze wie eingefaerbt statt wie
     Papier. Die neue Leiter ist ein kuehles Grau mit einem Hauch Blau (der
     Blauanteil liegt je Stufe 2-3 Punkte ueber Rot) — genug, um mit Navy
     verwandt zu sein, zu wenig, um als Farbe gelesen zu werden. */
  --fl-rail: #ffffff;   /* Navigation — Papier, von der Arbeitsflaeche durch die Kante getrennt */
  --fl-0: #f6f7f9;      /* Arbeitsgrund unter den Karten */
  --fl-well: #f9fafb;   /* eingelassen: Tabellenkopf, Bahnen, Kartenfuss */
  --fl-1: #ffffff;      /* Karte, Panel — das Papier */
  --fl-2: #f4f5f8;      /* Bedienflaeche: Chip, Werkzeugleiste */
  --fl-3: #eef0f4;      /* Hover, Auswahl, aktive Zeile */
  --fl-over: #ffffff;   /* echte Ueberlagerung: Drawer, Popover, Modal */

  /* ---- Flaechen, die Bauteile benutzen (Aliasse auf die Leiter) ---- */
  --bg: #f4f5f7;          /* Seitengrund der Website- und Folienwelt */
  --surface: var(--fl-1);
  --surface-alt: #fafbfc; /* Zebrastreifen, Einlassungen */

  /* ---- Text ---- */
  --text: #040c2c;            /* = navy */
  --text-secondary: #5a6578;  /* 5,89 : 1 auf Weiss */
  --text-muted: #6b7083;      /* 4,92 : 1 auf Weiss, 4,51 : 1 auf --bg */
  --text-on-dark: #ffffff;
  --text-on-dark-soft: rgba(255, 255, 255, 0.85);
  --ink-on-green: var(--navy); /* Schrift auf einer gruenen Flaeche */

  /* ---- Kanten ----
     --border ist die Haarlinie zwischen Zeilen und Karten; sie darf leise
     sein. --border-strong ist der Rand eines BEDIENELEMENTS (Eingabefeld,
     Auswahlfeld, Kontrollkaestchen) und traegt die 3 : 1 aus 1.4.11. */
  --border: #e4e6eb;          /* 1,25 : 1 — bewusst dekorativ */
  --border-light: #eef0f3;
  --border-strong: #898d9c;   /* 3,31 : 1 auf Weiss, 3,03 : 1 auf --bg */
  --border-hover: #707487;    /* 4,63 : 1 — beim Ueberfahren wird die Kante STAERKER */

  /* ---- Zustaende ---- */
  --state-hover: var(--fl-3);
  --state-selected: var(--green-light);
  --state-disabled-bg: #f1f3f7;
  --state-disabled-ink: #8b90a0;   /* nur fuer ausgegrauten Text */
  --state-focus: var(--focus-ring);

  /* ---- Semantische Zustandsfarben (Badge, Toast, Hinweisband) ---- */
  --status-info-bg: #dbeafe;     --status-info-fg: #1e40af;    --status-info-dot: #2563eb;
  --status-warn-bg: #fef9c3;     --status-warn-fg: #854d0e;    --status-warn-dot: #ca8a04;
  --status-success-bg: #eef4e1;   /* seit 2026-09-23 deckend: der Lindschleier las sich als Neonstift */
  --status-success-fg: #3d5a00;  --status-success-dot: #a2c629;
  --status-error-bg: #fee2e2;    --status-error-fg: #991b1b;   --status-error-dot: #ef4444;
  --status-neutral-bg: #f1f5f9;  --status-neutral-fg: #475569; --status-neutral-dot: #94a3b8;

  /* ---- Auftragsstatus (fachlich, Order Portal) ----
     NICHT dasselbe wie die semantischen Zustaende oben. Diese elf beschreiben,
     wie weit ein Auftrag ist, und sie sind eine LEITER, keine Sammlung:
       Arbeit noetig -> blau (hereingekommen) · cyan (im ERP offen) · gold (verschoben)
       erledigt      -> Bulung-Gruen (zugesagt) · Teal (unterwegs) · grau (fertig)
       auffaellig    -> rot, und nur das
     Wer eine Farbe aendert, muss die Reihenfolge mitdenken. Quelle:
     order-portal/static/styles.css. Sie gelten nur im HELLEN Register — das
     Order Portal ist hell, eine dunkle Fassung waere erfunden. */
  --auftrag-empfangen-bg: #dbeafe;    --auftrag-empfangen-fg: #1e40af;    --auftrag-empfangen-dot: #3b82f6;
  --auftrag-offen-bg: #cffafe;        --auftrag-offen-fg: #155e75;        --auftrag-offen-dot: #0891b2;
  --auftrag-aktualisiert-bg: #fcd34d; --auftrag-aktualisiert-fg: #78350f; --auftrag-aktualisiert-dot: #b45309;
  --auftrag-organisiert-bg: rgba(162, 198, 41, 0.15);
  --auftrag-organisiert-fg: #3d5a00;  --auftrag-organisiert-dot: #a2c629;
  --auftrag-disponiert-bg: #d1fae5;   --auftrag-disponiert-fg: #065f46;   --auftrag-disponiert-dot: #10b981;
  --auftrag-entladen-bg: #f1f5f9;     --auftrag-entladen-fg: #475569;     --auftrag-entladen-dot: #94a3b8;
  --auftrag-reklamation-bg: #fee2e2;  --auftrag-reklamation-fg: #991b1b;  --auftrag-reklamation-dot: #ef4444;
  --auftrag-erledigt-bg: #e2e8f0;     --auftrag-erledigt-fg: #334155;     --auftrag-erledigt-dot: #64748b;
  --auftrag-neu-bg: #dcfce7;          --auftrag-neu-fg: #166534;          --auftrag-neu-dot: #22c55e;
  --auftrag-default-bg: #f1f5f9;      --auftrag-default-fg: #475569;      --auftrag-default-dot: #94a3b8;
  /* ALTBESTAND: `positioniert` wird seit 2026-08-27 nie mehr geschrieben,
     steht aber in der Historie und an Auftraegen, die das Gateway gerade
     nicht beantworten kann. Nicht fuer Neues verwenden. */
  --auftrag-positioniert-bg: rgba(162, 198, 41, 0.15);
  --auftrag-positioniert-fg: #3d5a00; --auftrag-positioniert-dot: #a2c629;

  /* ---- Gefahr ---- */
  --danger: #c62828;         /* 5,62 : 1 auf Weiss — #ef4444 traegt nur 3,76 */
  --danger-hover: #a91d1d;
  --danger-surface: #ef4444; /* nur als FLAECHE, nie als Text auf Weiss */

  /* ---- Signaturlinie: 3 px, gruen -> navy ----
     Penpot kennt keinen Token-Typ `gradient`. Dieser Wert kommt beim Import
     NICHT mit und steht in tokens/penpot/pruefe.mjs als bewusste Auslassung. */
  --gradient-accent: linear-gradient(90deg, var(--green) 0%, var(--navy) 100%);

  /* ---- Glas, leise (HR-Portal, seit 28.09.2026) ----
     Zweite Fassung. Die erste (Farbgrund 0,32, vier Flecken, bunte Verlaeufe
     fuer Kacheln und Initialen) las sich als KI-Vorlage und ist am selben Tag
     entfallen; ganz ohne Glas war das Portal „zu langweilig". Diese Fassung
     halbiert den Farbgrund und kennt nur zwei Verlaeufe (Rail, Anmeldung).
     Bunte Verlaeufe fuer Kacheln, Symbole oder Initialen gibt es NICHT.

     LESBARKEIT: der Farbgrund ist so schwach, dass `--text-muted` auch
     DIREKT auf dem Kern des kraeftigsten Flecks 4,5 : 1 traegt (gruen:
     Mischfarbe ~ #eff5dd). Auf Glas (78 % Weiss) sowieso. */
  --glass-fl: rgba(255, 255, 255, 0.78);         /* Karte, Tabelle, Kachel */
  --glass-fl-stark: rgba(255, 255, 255, 0.86);   /* Kopfzeile, Tafel, Menue: liegt ueber rollendem Text */
  --glass-fl-zart: rgba(255, 255, 255, 0.5);     /* eingelassene Flaeche auf Glas */
  --glass-licht: rgba(255, 255, 255, 0.9);       /* helle Innenkante: die „Glaskante" */
  --glass-rand: rgba(4, 12, 44, 0.08);           /* aeussere Haarlinie um Glas */
  --glass-dunkel-rand: rgba(255, 255, 255, 0.1); /* Kante der Navy-Rail */

  --aura-gruen: rgba(162, 198, 41, 0.16);
  --aura-blau: rgba(37, 99, 235, 0.09);
  --aura-tuerkis: rgba(8, 145, 178, 0.09);

  /* Rail: Navy mit leichter Tiefe nach unten. Weiss darauf: 17,17 / 19,19 / 17,78. */
  --verlauf-rail: linear-gradient(180deg, #0b1745 0%, #040c2c 55%, #041a26 100%);
  /* Schild der Anmeldung. Weiss: 19,19 / 15,31 / 10,01. */
  --verlauf-held: linear-gradient(120deg, #040c2c 0%, #0b1f5e 55%, #0e4a4a 100%);
}

/* ==========================================================================
   DUNKELREGISTER
   Zwei von drei laufenden Apps sind dunkel. Bis zum 2026-08-29 hatte das
   Design-System dafuer keinen einzigen Wert. Diese Leiter stammt aus
   bulung-at-dashboard/src/app.css und laeuft dort seit dem 10.08.2026.
   Nachgerechnet auf --fl-1: Text 14,50 · Text sekundaer 7,90 ·
   Text leise 5,54 · Gruen als Text 9,19.
   ========================================================================== */
[data-register="dunkel"] {
  --navy-light: #16224a;
  --navy-hover: #22305e;
  --green-hover: #b4d838;    /* im Dunkelregister geht Hover nach OBEN */
  --green-deep: #8bab1f;
  --green-light: rgba(162, 198, 41, 0.13);
  --green-medium: rgba(162, 198, 41, 0.22);

  /* Auf dunklem Grund traegt die Markenfarbe selbst 9,19 : 1 — die
     Ersatztinte des Hellregisters wird hier NICHT gebraucht. */
  --green-ink: var(--green);
  --green-ink-hover: var(--green-hover);
  --focus-ring: var(--green);

  --fl-rail: #070c20;
  --fl-0: #060b1c;
  --fl-well: #080f28;
  --fl-1: #0c1430;
  --fl-2: #121b3d;
  --fl-3: #18234c;
  --fl-over: #1b2757;

  --bg: var(--fl-0);
  --surface: var(--fl-1);
  --surface-alt: var(--fl-well);

  --text: #dfe6f7;
  --text-secondary: rgba(223, 230, 247, 0.72);
  --text-muted: rgba(223, 230, 247, 0.58);
  --text-on-dark: #dfe6f7;
  --text-on-dark-soft: rgba(223, 230, 247, 0.6);
  --ink-on-green: var(--navy);

  --border: rgba(150, 175, 240, 0.22);
  --border-light: rgba(150, 175, 240, 0.12);
  --border-strong: rgba(150, 175, 240, 0.52); /* 3,16 : 1 auf --fl-1 */
  --border-hover: rgba(150, 175, 240, 0.70);  /* 4,72 : 1 auf --fl-1 */

  --state-hover: var(--fl-3);
  --state-selected: var(--green-light);
  --state-disabled-bg: rgba(150, 175, 240, 0.08);
  --state-disabled-ink: rgba(223, 230, 247, 0.4);

  --status-info-bg: rgba(59, 130, 246, 0.18);    --status-info-fg: #93c5fd;    --status-info-dot: #3b82f6;
  --status-warn-bg: rgba(202, 138, 4, 0.20);     --status-warn-fg: #fcd34d;    --status-warn-dot: #ca8a04;
  --status-success-bg: rgba(162, 198, 41, 0.18); --status-success-fg: #cfe17f; --status-success-dot: #a2c629;
  --status-error-bg: rgba(239, 68, 68, 0.20);    --status-error-fg: #fca5a5;   --status-error-dot: #ef4444;
  --status-neutral-bg: rgba(150, 175, 240, 0.12);--status-neutral-fg: #a8b3cc; --status-neutral-dot: #94a3b8;

  --danger: #fca5a5;
  --danger-hover: #f87171;
  --danger-surface: #ef4444;
}

/* ── tokens/typography.css ───────────────────────────────────────────── */
/* Bulung Logistics — Typografie
   ==========================================================================
   Aus dem CI-Booklet, Seite 7:
     HEADLINE / SUBHEADLINE  Basier Circle Bold, Zeilenhoehe = Schriftgrad x 1,2
     CAPTION                 Jost Semi, Sperrung 200 (= 0.2em), Grossbuchstaben
     COPY TEXT               Jost Book, Zeilenhoehe = Schriftgrad x 1,6
     CALL TO ACTION          Jost Book, Grossbuchstaben und unterstrichen

   ZAHLEN BRAUCHEN EINE EIGENE SCHRIFT. In Tabellen, Kennzahlen und Betraegen
   muessen Ziffern untereinander stehen. Dafuer gibt es --font-mono
   (IBM Plex Mono) und --num-tabular; das Design-System hatte dafuer bis zum
   2026-08-29 kein Token, waehrend die Produktion es seit Monaten benutzt.

   Basier Circle ist eine KOMMERZIELLE Schrift (Atipo Foundry). Sie liegt hier
   als OTF, weil dotsandlines sie mit dem CI geliefert hat. Sie darf NICHT
   oeffentlich ausgeliefert werden, ohne dass die Lizenz das deckt — siehe
   readme.md, Abschnitt Lizenzen. Jost und IBM Plex Mono stehen unter der
   SIL Open Font License und sind frei.
   ========================================================================== */

:root {
  /* ---- Familien ---- */
  --font-display: "Basier Circle", "Jost", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: "Jost", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  /* DIE SCHRIFT DER ARBEITSFLAECHEN — seit 2026-10-01 Inter (Ansage
     Auftraggeber: „professionelles B2B-Enterprise-Gefuehl").
     Jost ist eine Markenschrift: rund, geometrisch, mit kleiner x-Hoehe. Auf
     einer Seite, die man EINMAL liest, traegt sie die Marke; bei 14 px in
     einer Tabelle, die man den ganzen Tag liest, wirkte sie duenn und
     unruhig. Inter ist fuer genau diese Groesse gezeichnet. Die Marke bleibt
     in Logo, Signet, Farbe und auf Website und Folien (--font-body/-display).
     Die Basis schaltet Inter mit `cv11` (einstoeckiges a) — das holt etwas
     von der Geometrie der Marke in die Arbeitsschrift. */
  --font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /* ZIFFERN IN DER OBERFLAECHE — seit 2026-10-01 Inter (vorher Jost, davor
     Plex Mono). Inter traegt eigene Tabellenziffern (`tnum`). `--font-mono`
     bleibt fuer das, was wirklich Code ist: Pfade, Pruefsummen, Kennungen. */
  --font-num: var(--font-ui);

  /* ---- Schnitte ---- */
  --fw-light: 300;   /* @kind font */
  --fw-book: 400;    /* @kind font */
  --fw-medium: 500;  /* @kind font */
  --fw-semi: 600;    /* @kind font */
  --fw-bold: 700;    /* @kind font */

  /* ---- Groessenskala ----
     Zwei Skalen, weil zwei Welten: die Marketing-Welt (Website, Folien) liest
     man einmal, die Arbeitsflaechen (Portale, Dashboards) den ganzen Tag.
     Wer die Lesefassung auf eine Tabelle legt, bekommt halb so viele Zeilen
     ins Bild. */
  --fs-caption: 12px;   /* Etiketten, Bildunterschriften — Grossbuchstaben */
  --fs-meta: 13px;      /* Meta, Kleingedrucktes */
  --fs-body: 16px;      /* Grundtext */
  --fs-lg: 18px;
  --fs-h3: 20px;
  --fs-h2: 25px;
  --fs-h1: 33px;
  --fs-display: 48px;   /* Aufmacher */
  --fs-display-lg: 64px;

  /* Arbeitsflaechen — dichter. Gemessen an den laufenden Portalen. */
  --fs-app-micro: 12px;  /* Spaltenkopf. 2026-10-01: 11 -> 12, Inter in normaler Schreibung statt Jost in Versalien */
  --fs-app-caption: 12px;
  --fs-app-body: 14px;   /* Tabellenzelle, Formularfeld */
  --fs-app-lg: 15px;
  --fs-app-h3: 16px;     /* 2026-10-01: 17 -> 16 mit Inter (groessere x-Hoehe) */
  --fs-app-h2: 18px;     /* 2026-10-01: 20 -> 18 */
  --fs-app-h1: 24px;   /* 2026-09-25: 26 -> 30; 2026-09-27: 30 -> 28; 2026-10-01: 28 -> 24 mit Inter — Enterprise-Seitentitel sind ruhig, die Rangfolge kommt aus Gewicht und Sperrung */
  --fs-app-kpi: 28px;    /* die Zahl einer Kennzahlkachel; 2026-09-27: 30 -> 24; 2026-09-28: 24 -> 28, seit die Zahl auf eigener Kachel steht und neben 12-px-Etikett eine Stufe Abstand braucht (HR-Portal) */

  /* ---- Zeilenhoehen ---- */
  --lh-display: 1.2;    /* @kind font — CI: Schriftgrad x 1,2 */
  --lh-heading: 1.25;   /* @kind font */
  --lh-body: 1.6;       /* @kind font — CI: Schriftgrad x 1,6 */
  --lh-dense: 1.45;     /* @kind font — Tabellen und Formulare. 2026-10-01: 1.35 -> 1.45, Inter braucht bei 14 px rund 20 px Zeile */

  /* ---- Sperrung ---- */
  --ls-caption: 0.2em;     /* @kind font — CI: spacing 200 */
  --ls-subhead: 0.12em;    /* @kind font — CI: spacing 120 */
  --ls-label: 0.04em;      /* @kind font */
  --ls-tight: -0.02em;     /* @kind font — Ueberschriften der Arbeitsflaechen ab 16 px. 2026-10-01: -0.015 -> -0.02 fuer Inter */

  /* ---- Ziffern ----
     Penpot kennt keinen Token-Typ fuer font-variant-numeric. Der Wert steht
     hier als CSS-Baustein und ist in tokens/penpot/pruefe.mjs als bewusste
     Auslassung verzeichnet. */
  --num-tabular: tabular-nums;   /* @kind other */
}

/* ── tokens/spacing.css ──────────────────────────────────────────────── */
/* Bulung Logistics — Abstaende, Groessen, Layout
   ==========================================================================
   Registerneutral: diese Werte sind in Hell und Dunkel dieselben.

   Die Skala hiess bis 2026-08-29 4/8/16/24/32/48/64. Das ist die Skala einer
   LESEFASSUNG. Die Arbeitsflaechen der Produktion (Order Portal, AT-Dashboard)
   brauchen dichtere Stufen und benutzten deshalb 2/6/12/20 an den Token
   vorbei. Diese vier Halbstufen sind jetzt Teil der Skala.

   ENTFALLEN: --bp-tablet und --bp-mobile. Eine Media Query kann eine Custom
   Property nicht lesen — `@media (max-width: var(--bp-tablet))` ist
   ungueltiges CSS und wird vom Browser stillschweigend verworfen. Die zwei
   Token waren also wirkungslos und haben Sicherheit vorgetaeuscht. Die
   Haltepunkte stehen als Zahlen in den Media Queries und sind unten als
   Kommentar verzeichnet.
   ========================================================================== */

:root {
  /* ---- Abstandsskala ---- */
  --space-2xs: 2px;   /* Haarabstand: Symbol zu Text, Punkt zu Etikett */
  --space-xs: 4px;    /* Abstaende innerhalb einer Zeile */
  --space-2s: 6px;    /* dichte Werkzeugleisten */
  --space-sm: 8px;    /* enge Gruppen */
  --space-2m: 12px;   /* Polster einer Tabellenzelle, Chip */
  --space-md: 16px;   /* Standardpolster */
  --space-2l: 20px;   /* Polster einer Arbeitskarte */
  --space-lg: 24px;   /* Kartenpolster, Abschnittsabstand */
  --space-xl: 32px;   /* Behaelterpolster, Abstand zwischen Abschnitten */
  --space-2xl: 48px;  /* grosse Abschnittstrennung */
  --space-3xl: 64px;

  /* ---- Polster ---- */
  --pad-card: 24px;
  --pad-card-dense: 16px;      /* Karte auf einer Arbeitsflaeche */
  --pad-cell: 12px 16px;       /* Tabellenzelle — 2026-09-27 10 → 14 (gedraengt mit Jost); 2026-10-01 → 12 mit Inter und Zeile 1,45: rund 45 px je Zeile */
  --pad-container: 32px;
  --pad-container-mobile: 16px;

  /* ---- Symbolgroessen ----
     Die acht Markenicons sind ILLUSTRATIV (zweifarbig, feine Linien). Unter
     20 px verlieren sie ihre gruenen Details. --icon-sm ist fuer
     Oberflaechensymbole gedacht, nicht fuer die Markenicons. */
  --icon-sm: 16px;
  --icon-md: 20px;
  --icon-lg: 24px;
  --icon-brand: 48px;   /* Mindestgroesse fuer die acht Markenicons */

  /* ---- Layout ---- */
  --maxw-text: 72ch;    /* Lesebreite eines Fliesstexts */
  --maxw-page: 1180px;  /* Marketingseiten (Website, Folien) */
  --maxw-app: 1840px;   /* Arbeitsflaechen mit Tabellen */
  --sidebar-w: 232px;   /* linke Rail der Anwendungen */
  --nav-height: 60px;

  /* ---- Haltepunkte ----
     NUR als Notiz. Sie MUESSEN in der Media Query als Zahl stehen:
       @media (max-width: 768px) { ... }
     Haltepunkte des Hauses: 480 · 560 · 768 · 1024 · 1280 · 1440 · 1600 */
}

/* ── tokens/effects.css ──────────────────────────────────────────────── */
/* Bulung Logistics — Radien, Schatten, Kanten, Bewegung, Stapelfolge
   ==========================================================================
   Radien, Kanten, Bewegung und Stapelfolge sind registerneutral.
   SCHATTEN NICHT: auf dunklem Grund traegt ein Schatten nichts, weil unter
   einer dunklen Karte kein Licht fehlt. Die Produktion setzt sie dort auf
   `0 0 transparent` und arbeitet mit der Flaechenleiter statt mit Hoehe.
   Genau das steht unten im Dunkelregister.
   ========================================================================== */

:root {
  /* ---- Radien ---- */
  --radius-xs: 6px;       /* Abzeichen — seit 2026-10-01 ein Etikett statt einer Pille */
  --radius-sm: 8px;       /* Eingabefelder, Knoepfe */
  --radius: 12px;         /* Karten — auf Karten nicht ueberschreiten */
  --radius-lg: 16px;      /* Ueberlagerungen, Modale */
  --radius-pill: 9999px;

  /* ---- Schatten (nur zwei Stufen — keine Schattenorgien) ---- */
  --shadow-xs: 0 1px 2px rgba(4, 12, 44, 0.05);  /* Knopf, Feld, Karte — gerade genug, um zu liegen */
  --shadow-sm: 0 1px 3px rgba(4, 12, 44, 0.05);
  --shadow-md: 0 4px 16px rgba(4, 12, 44, 0.07);
  --shadow-over: 0 24px 60px -20px rgba(4, 12, 44, 0.3); /* Drawer, Popover */
  /* Hauptknopf (seit 2026-10-01): helle Innenkante oben, dichter Schatten
     unten. Gibt der Navy-Flaeche Koerper, ohne Glanz und ohne Leuchten. */
  --shadow-knopf-haupt: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 1px 2px rgba(4, 12, 44, 0.24);
  /* Weicher Hof um ein fokussiertes Feld, zusaetzlich zur Kante in
     --focus-ring. Allein traegt er keinen Kontrast — er ist Schmuck. */
  --focus-hof: 0 0 0 3px rgba(61, 98, 5, 0.16);

  /* ---- Kanten ---- */
  --border-width: 1px;          /* @kind other */
  --border-accent-width: 2px;   /* @kind other */
  --border-row-accent: 3px;     /* @kind other — Zeilenbalken links */

  /* ---- Fokus ----
     Sichtbarer Ring, 2 px, mit 2 px Abstand zum Element. Die Farbe kommt aus
     --focus-ring (colors.css) und traegt im Hellregister 7,12 : 1. */
  --focus-width: 2px;           /* @kind other */
  --focus-offset: 2px;          /* @kind other */

  /* ---- Verdunkelung hinter Modalen ---- */
  --backdrop: rgba(4, 12, 44, 0.4);
  --backdrop-blur: 4px;         /* @kind other */

  /* ---- Glas (seit 28.09.2026, leise Fassung) ----
     Die Weichzeichnung fuer schwebende Flaechen (Kopfzeile, Menue, Tafel).
     Der Glasschatten ist flacher als in der ersten Fassung: 8 statt 12 px
     Versatz, 0,14 statt 0,22 Deckkraft. Die Karte liegt auf, sie schwebt
     nicht. Erste Zeile = helle Innenkante oben. */
  --glass-blur: 18px;           /* @kind other */
  --glass-saettigung: 160%;     /* @kind other */
  --shadow-glass: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 8px 24px -16px rgba(4, 12, 44, 0.14), 0 1px 3px rgba(4, 12, 44, 0.04);
  /* Leuchtschatten (Glow) gab es hier am 28.09.2026 kurz: am selben Tag
     wieder entfernt. Ein leuchtender Knopf ist das Erkennungszeichen einer
     KI-Vorlage, nicht der Marke. */

  /* ---- Bewegung (sparsam und funktional) ----
     Penpot kennt keine Token-Typen `duration` und `cubicBezier`. Diese vier
     Werte kommen beim Import NICHT mit; sie stehen als bewusste Auslassung in
     tokens/penpot/pruefe.mjs. */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);  /* @kind other */
  --dur-fast: 200ms;     /* @kind other */
  --dur-mid: 300ms;      /* @kind other */
  --dur-enter: 400ms;    /* @kind other */

  /* ---- Chrom ---- */
  --accent-line-height: 3px;    /* @kind other — Signaturlinie in der Oberflaeche */
  --accent-line-slide: 6px;     /* @kind other — dieselbe Linie auf einer Folie.
                                   Eine Folie ist 1920 px breit und wird projiziert;
                                   3 px sind dort ein Haar. Der Wert stand bis zum
                                   2026-08-29 roh in slides/title-slide.html und
                                   widersprach der readme.md, die 3 px behauptete. */

  /* ---- Stapelfolge ---- */
  --z-nav: 100;       /* @kind other */
  --z-dropdown: 200;  /* @kind other */
  --z-backdrop: 900;  /* @kind other */
  --z-modal: 1000;    /* @kind other */
  --z-toast: 1100;    /* @kind other */
}

/* Flach im Dunkelregister — Tiefe kommt dort aus der Flaechenleiter. */
[data-register="dunkel"] {
  --shadow-sm: 0 0 transparent;
  --shadow-md: 0 0 transparent;
  --shadow-knopf-haupt: 0 0 transparent;
  --shadow-over: 0 24px 60px -20px rgba(0, 0, 0, 0.75);
  --backdrop: rgba(0, 0, 0, 0.6);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0ms;   /* @kind other */
    --dur-mid: 0ms;    /* @kind other */
    --dur-enter: 0ms;  /* @kind other */
  }
}

/* ── schrift/auslieferung.css ────────────────────────────────────────── */
/* Bulung — Schriften der Auslieferung
   ==========================================================================
   Woertlich uebernommen aus bulung-at-dashboard/src/app.css, wo diese acht
   Bloecke seit dem 10.08.2026 laufen.

   NICHT dieselbe Datei wie tokens/fonts.css: die traegt 16 OTF-Bloecke samt
   Basier Circle (kommerziell) und ist fuer die Schaufensterseiten und Penpot.
   Hier stehen die acht WOFF2, die eine Anwendung laedt — rund ein Zehntel so
   gross.

   Jost ist VARIABEL: `font-weight: 400 700` als Bereich auf EINEM Block statt
   vier identischer. Kein Gewicht wird synthetisch fett gerechnet.
   IBM Plex Mono ist statisch, dort je Gewicht eine eigene Datei.

   INTER seit 2026-10-01: die Schrift der ARBEITSFLAECHEN (--font-ui). Auch
   variabel, `font-weight: 100 900`. Quelle: npm @fontsource-variable/inter
   5.3.0 (Inter 4, rsms), Dateien `inter-latin(-ext)-wght-normal.woff2`
   unveraendert umbenannt. SIL Open Font License 1.1 wie Jost.
   ========================================================================== */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900; /* Variable Font */
  font-display: swap;
  src: url('/fonts/inter-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: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-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: 'Jost';
  font-style: normal;
  font-weight: 400 700; /* Variable Font — eine Datei, alle Gewichte echt */
  font-display: swap;
  src: url('/fonts/jost-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: 'Jost';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/jost-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/plexmono-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: 400;
  font-display: swap;
  src: url('/fonts/plexmono-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: 500;
  font-display: swap;
  src: url('/fonts/plexmono-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 Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/plexmono-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: 600;
  font-display: swap;
  src: url('/fonts/plexmono-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: 600;
  font-display: swap;
  src: url('/fonts/plexmono-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;
}

/* ── basis/reset.css ─────────────────────────────────────────────────── */
/* Bulung — Reset
   ==========================================================================
   Bewusst klein. Ein grosser Reset kaempft mit dem, was eine App schon hat.
   Hier steht nur, was ueberall gleich sein soll.
   ALLES unter [data-bulung] — ohne den Schalter aendert sich nichts.
   ========================================================================== */

[data-bulung] *, [data-bulung] *::before, [data-bulung] *::after { box-sizing: border-box; }
[data-bulung] body { margin: 0; }
[data-bulung] img, [data-bulung] svg { max-width: 100%; }
[data-bulung] button, [data-bulung] input,
[data-bulung] select, [data-bulung] textarea { font: inherit; color: inherit; }

/* ── basis/typografie.css ────────────────────────────────────────────── */
/* Bulung — Grundtypografie
   ==========================================================================
   Die ARBEITSFLAECHEN-Skala, nicht die Lesefassung: Portale und Dashboards
   werden den ganzen Tag gelesen. Wer die Marketing-Skala auf eine Tabelle
   legt, bekommt halb so viele Zeilen ins Bild.
   ========================================================================== */

[data-bulung] body {
  /* Seit 2026-10-01 die Arbeitsschrift, nicht die Markenschrift — siehe
     --font-ui in tokens/typography.css. `cv11` = einstoeckiges a. */
  font-family: var(--font-ui);
  font-feature-settings: "cv11";
  font-size: var(--fs-app-body);
  line-height: var(--lh-dense);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* Ziffern stehen untereinander. Heute ist das dreifach geloest: IBM Plex Mono
   in den Svelte-Apps, eine NIE GELADENE JetBrains-Kette im LKW-Portal, gar
   nichts im Order Portal. */
[data-bulung] .bul-zahl {
  font-family: var(--font-num);
  font-variant-numeric: var(--num-tabular);
}

/* ── basis/fokus.css ─────────────────────────────────────────────────── */
/* Bulung — Fokus
   ==========================================================================
   Hier waren sich alle vier Apps SCHON einig: 2 px Strich, 2 px Abstand.
   Verschieden war nur der Farbname (--green / --fokus / --akzent). Der Ring
   kostet also nichts ausser einem gemeinsamen Namen.
   --focus-ring traegt hell 7,12 : 1; dunkel ist es die Markenfarbe (9,93 : 1).
   ========================================================================== */

[data-bulung] :focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
}
[data-bulung] :focus:not(:focus-visible) { outline: none; }

/* ── bauteile/tabelle.css ────────────────────────────────────────────── */
/* Bulung — Tabelle
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Hauptquelle ist `order-portal/static/styles.css` — die durchgearbeitetste
   Tabelle des Hauses, gegen 70 echte Auftraege aus der Produktions-DB
   geeicht. Ihre Regeln liegen dort aber verstreut zwischen Zeile 846 und
   2469 und sind mit Fachlichem vermischt. Aus jedem Fund wurde einzeln
   entschieden: allgemein (kommt mit) oder fachlich (bleibt in der App).
   IM ZWEIFEL BLEIBT ES DRAUSSEN. Was fehlt, kann die App weiter selbst
   setzen; was zu viel mitkommt, zwingt allen ihre Eigenheit auf.

   ZWEITE QUELLE fuer genau eine Sache: `bulung-at-dashboard/src/app.css`
   (`.tafel`, Zeile 1044 ff.). Das Order Portal hat KEINE Zahlenspalte — die
   Ziel-API verlangt aber `.bul-zahl`. Rechtsbuendig, Monoschrift und
   `nowrap` stammen deshalb von dort, wo sie gegen echte Betragsspalten
   eingestellt wurden.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (order-portal/static/styles.css), Zeilennummer in Klammern:

     table (855)          Breite 100 %, `border-collapse: collapse`, Grundgrad
     thead (860)          klebender Spaltenkopf
     th (861)             Versalien, Sperrung (0.04em), `nowrap`, linksbuendig,
                          deckender Grund. NICHT der Schriftgrad, NICHT die
                          Haarlinie — beides steht unten unter
                          "Neuentscheidungen".
     td (1049)            Zellpolster, Haarlinie, `vertical-align: middle`,
                          `user-select: text`
     td (1053-1055)       `overflow: hidden` + `text-overflow: ellipsis` —
                          hier NUR im nowrap-Zustand, weil ein Auslassungs-
                          zeichen ohne `nowrap` ohnehin nie erscheint
     tbody tr (1062)      weiche Blende beim Wechsel des Zeilengrunds
     tbody tr.data-row    Hover auf der Zeile. Der Klassenteil `.data-row`
       :hover (1068)      bleibt draussen — er trennt im Order Portal die
                          Datenzeile von der aufgeklappten Detailzeile.
     th, td (1886/1912)   engere Polster auf kleinen Schirmen -> als
                          `--dicht` zu einem AUSDRUECKLICHEN Zustand gemacht,
                          nicht an eine Breite gehaengt (s.u.)
     td (1876)            "unter 1279 px darf wieder umgebrochen werden" ->
                          umgekehrt: umbrechen ist hier der Grundzustand,
                          `--nowrap` ist die Ausnahme (s.u.)
     .col-fk .fk-kz       `font-variant-numeric: tabular-nums` als Regel fuer
       (2248)             Ziffern -> geht in `.bul-zahl`
     .col-timestamp       `white-space: nowrap` + tabellarische Ziffern auf
       (2469)             einer Zahlenspalte -> geht in `.bul-zahl`

   Dazu aus `.tafel` des AT-Dashboards:
     .tafel .zahl (1100)  rechtsbuendig, Monoschrift, `nowrap`
     tbody tr:last-child  die letzte Zeile traegt keine Haarlinie mehr
       (1096)
     .tafel td (1084)     `overflow-wrap: anywhere`. Dort woertlich "der
                          groesste Einzelhebel des Audits" — ein langer
                          Firmenname schob die Auftragsliste auf ueber
                          2000 px. Kommt MIT, weil umbrechen hier der
                          Grundzustand ist und ein einziges langes Wort ohne
                          Leerzeichen sonst genau dasselbe tut. Gemessen,
                          siehe messstand/BEFUND.md.

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------
   Was hier steht, hat in der Quelle kein Vorbild oder ein gegenteiliges.
   Es als Ernte auszugeben waere die teurere Luege: die Aufgaben 6 bis 8
   richten sich nach dieser Tabelle.

     Haarlinie unter        Die Quelle setzt dort ausdruecklich
     dem Kopf               `border-bottom: none` (styles.css:873). Sie kann
                            das, weil ihr Kopf NAVY ist — die Farbkante
                            trennt schon. Hier steht der Kopf auf `--fl-well`
                            und liegt damit dicht an der ersten Zeile; ohne
                            Linie verschwimmt die Grenze. Die Linie ist also
                            die FOLGE der Kopffarbe, nicht ihre Ernte.
     Kopf 11 px             Die Quelle hat 12 px (`0.75rem`, styles.css:867).
                            Die 11 kommen aus `--fs-app-micro` und aus der
                            Ziel-API dieser Aufgabe. Der Satz "jedes Zehntel
                            kostet Spaltenbreite" ist aus der Quelle geerbt,
                            die ZAHL nicht.
     Kopf Gewicht 600       Die Quelle hat 500 (styles.css:866) — auf Navy mit
                            weisser Schrift. Auf der hellen `--fl-well` traegt
                            500 zu wenig; 600 ist der Wert, den das
                            AT-Dashboard fuer denselben hellen Kopf benutzt.
     Kopffarbe              Weder das Weiss der Quelle (Navy-Kopf) noch das
     --text-secondary       naheliegende `--text-muted`: letzteres traegt auf
                            `--fl-well` nur 4,15 : 1 und faellt durch 1.4.3.
                            Gerechnet, siehe unten.
     Auswahlbalken          Die Quelle loest den Zeilenbalken als absolut
     (box-shadow: inset)    gesetztes `::after` an `tr[data-updated]`
                            (styles.css:1282) und braucht dafuer
                            `position: relative` an der Zeile. Hier ein
                            eingesetzter Schatten in der ersten Zelle — die
                            Begruendung steht an der Regel selbst.
     Zustandsnamen          `--dicht` und `--nowrap` als ausdrueckliche
                            Zustaende gibt es in keiner der beiden Quellen;
                            dort haengen dieselben Werte an Media Queries.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .table-card (846)        eine KARTE, kein Tabellenteil. Kommt in
                              Aufgabe 8.
     .table-wrapper (852)     der Rollkasten. Er gehoert dem Layout der App:
                              wer die Tabelle in eine Karte legt, entscheidet
                              selbst, ob und wo gerollt wird. Siehe die Notiz
                              zum klebenden Kopf weiter unten.
     th:hover (878)           die Koepfe des Order Portals SIND Knoepfe
                              (Sortierung). Eine Tabelle ohne Sortierung
                              haette damit einen Kopf, der auf Beruehrung
                              reagiert, ohne dass etwas passiert.
     th cursor/user-select    dito — Folge derselben Sortierung.
       (871/872)
     th .sort-icon (879)      Sortiersymbol, Bauteil der App.
     th.sorted (886)          dito.
     th Grund navy (862)      EINE Hausfarbe, keine Systemregel: das Order
                              Portal setzt den Kopf auf Navy mit weisser
                              Schrift, das AT-Dashboard auf die helle
                              Flaeche. Das System nimmt `--fl-well` — der
                              Token nennt den Tabellenkopf woertlich als
                              seinen Zweck.
     .detail-row (1161)       aufklappbare Detailzeile — ein Verhalten, kein
                              Aussehen.
     .detail-row > td (1061)  dito.
     .detail-row td (1162)    dito, samt der beiden `!important`.
     tbody tr.data-row        Zebra ueber `4n+1`: die 4 kommt daher, dass auf
       :nth-child(4n+1)       jede Datenzeile eine Detailzeile folgt. Ein
       (1065)                 fremder Rhythmus in einer fremden Tabelle.
                              ZEBRA KOMMT AUCH SONST NICHT MIT — die
                              Hausvorgabe fuer Arbeitsflaechen ist die ruhige
                              Flaeche mit Haarlinien, nicht der Streifen.
     tr[data-updated] …       die ganze Statusleiter (1270-1312): elf
                              Auftragszustaende des Order Portals. Fachlich
                              bis in die Farbwerte.
     tr.data-row.row-updated  Blinken nach einer Aktualisierung (1510).
     .col-fk und Kinder       Fraechter/Kennzeichen, zweizeilige Zelle
       (2220-2258)            (2220-2258).
     #orderTable td           die zwei Breitendeckel (2282/2283). Sie sind an
       .col-frachtraum        genau zwei Datenbestaende geeicht.
       .col-stadt
     .kopier und Kinder       Kopierknopf (2309-2360).
     .col-timestamp .ts-*     Datum/Uhrzeit einer bestimmten Spalte
       (2476/2481)            (2476/2481).
     Spaltenstaffel           `nth-child(3|6|7|8|9)` in fuenf Media Queries
       (1861-2068)            (1861-2068). Sie zaehlt die Spalten des Order
                              Portals ab. In einer fremden Tabelle blendet
                              sie die falsche Spalte aus, und kein Testtor
                              sieht es.
     .skel-* (1413-1444)      Ladeattrappe.

   ---- ZWEI UMKEHRUNGEN GEGENUEBER DER QUELLE -------------------------------
   1. `nowrap` ist im Order Portal der Grundzustand und wird unter 1280 px
      zurueckgenommen. Hier ist es umgekehrt: `--nowrap` muss angefordert
      werden. Grund: `nowrap` traegt nur, solange die Summe der natuerlichen
      Spaltenbreiten in den Behaelter passt — das Order Portal garantiert das
      mit seiner Spaltenstaffel, die hier fachlich bleibt. Ohne die Staffel
      waere `nowrap` als Vorgabe eine waagerechte Rollleiste ab der ersten
      langen Zelle, und eine Spalte hinter der Kante sieht man nicht.
   2. Das engere Polster haengt an `--dicht`, nicht an einer Bildschirm-
      breite. Eine Media Query im System entschiede fuer alle vier Apps mit,
      wie dicht ihre Tabellen sind; die Dichte ist aber eine Entscheidung des
      Bildschirms, auf dem gearbeitet wird, nicht seiner Breite.
   ========================================================================== */

/* Der KLEBENDE SPALTENKOPF braucht einen Vorfahren, der ihn nicht klippt.
   `overflow: hidden` oder `overflow: auto` an einer Karte darueber macht
   genau diesen Kasten zum Bezugsrahmen — dann klebt der Kopf am Kasten statt
   am Fenster, und bei `hidden` verschwindet er. Wer die Tabelle in eine Karte
   legt, nimmt dort `overflow: clip`. (Gemessen in bulung-at-dashboard am
   17.08.2026.) */
[data-bulung] .bul-tabelle {
  /* Ein Polster fuer Kopf UND Zelle. Verschiedene WAAGERECHTE Polster wuerden
     die Textkanten von Kopf und Spalte gegeneinander versetzen. */
  --bul-tabelle-polster: var(--pad-cell);
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-app-body);
  font-variant-numeric: var(--num-tabular);
}

/* ── Spaltenkopf ─────────────────────────────────────────────────────────
   11 px kommen aus `--fs-app-micro` und aus der Ziel-API dieser Aufgabe —
   die Quelle steht auf 12 px (styles.css:867). GEERBT IST DER GRUND, NICHT
   DIE ZAHL: der Kopf ist der BODEN seiner Spalte, jedes Zehntel Schriftgrad
   hier kostet Spaltenbreite in der ganzen Tabelle. Im Order Portal sparten
   `Bereitstellung` statt `Bereitstellungsdatum` und `Auslieferung` statt
   `Auslieferdatum` zusammen 63 px.

   Schriftgewicht und Haarlinie sind Neuentscheidungen (Kopfteil oben): die
   Quelle hat 500 und `border-bottom: none`, aber sie hat auch einen NAVY
   Kopf. Auf `--fl-well` trennt keine Farbkante mehr.

   DIE FARBE IST GERECHNET, NICHT GEGRIFFEN. Der naheliegende Griff
   `--text-muted` traegt auf `--fl-well` nur 4,15 : 1 und faellt damit durch
   1.4.3 — 11 px sind kein grosser Text. `--text-secondary` traegt 4,97 : 1
   hell und 8,15 : 1 dunkel. */
[data-bulung] .bul-tabelle th {
  padding: var(--bul-tabelle-polster);
  text-align: left;
  /* Satzschreibung seit 2026-09-23: Versalien mit Sperrung ueber jeder
     Spalte waren die lauteste Zeile der Tabelle — lauter als die Daten. */
  font-size: var(--fs-app-caption);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
  /* Der Kopf bleibt einzeilig. Ein umbrechender Kopf aendert die Hoehe des
     klebenden Bandes und verschiebt damit den Versatz zur ersten Zeile. */
  white-space: nowrap;
  border-bottom: var(--border-width) solid var(--border);
  position: sticky;
  top: 0;
  /* Der Grund MUSS deckend sein, sonst scheinen die Zeilen beim Rollen
     durch. `--fl-well` nennt den Tabellenkopf woertlich als seinen Zweck.
     HAKEN `--tabelle-kopf-flaeche` (seit 2026-09-28, HR-Portal): auf Glas
     hebt sich `--fl-well` (#f9fafb) nicht mehr ab, das Portal setzt dort
     `--fl-2`. Wer nichts setzt, bekommt den Kopf von vorher. Der Haken muss
     DECKEND bleiben (siehe oben) und `--text-secondary` mit 4,5 : 1 tragen
     (`--fl-2`: 5,40 : 1, nachgerechnet). */
  background: var(--tabelle-kopf-flaeche, var(--fl-well));
  /* Ohne diese Stufe gewinnt jede Zeile, die die App selbst positioniert
     (das Order Portal setzt `position: relative` auf jede Statuszeile), und
     rollt ueber den Kopf. Fuer diese kleine Stufe INNERHALB eines Bauteils
     gibt es heute keinen Token — als Befund verzeichnet. */
  z-index: 2;
}

/* ── Zelle ─────────────────────────────────────────────────────────────── */
[data-bulung] .bul-tabelle td {
  padding: var(--bul-tabelle-polster);
  border-bottom: var(--border-width) solid var(--border-light);
  vertical-align: middle;
  /* Wer Text in einer Tabelle markiert, will kopieren. Apps, die den
     Zeilenklick belegen (Aufklappen, Auswahl), duerfen ihm das nicht
     wegnehmen. */
  -webkit-user-select: text;
  user-select: text;
  /* EIN EINZIGES LANGES WORT DARF DIE TABELLE NICHT AUFSCHIEBEN. Umbrechen
     ist hier der Grundzustand — das hilft aber nur, wo ein Leerzeichen steht.
     Eine Sammelnummer, eine Adresse ohne Leerzeichen oder ein zusammen-
     geschriebener Firmenname wirkt sonst genau wie `nowrap`: die Spalte nimmt
     die Breite ihres breitesten Wortes, und die Tabelle laeuft aus dem
     Behaelter. Im AT-Dashboard war das "der groesste Einzelhebel des Audits"
     (app.css:1079) — ein langer Firmenname schob die Auftragsliste auf ueber
     2000 px.

     `anywhere` und nicht `break-word`: nur `anywhere` zaehlt beim Ermitteln
     der Mindestbreite mit, und genau die entscheidet, wie breit eine
     Tabellenspalte werden muss.

     ZAHLEN SIND DAVON AUSGENOMMEN, ohne dass es hier stehen muss:
     `.bul-zahl` traegt `white-space: nowrap`, und das schlaegt jeden
     Wortumbruch. Eine Auftragsnummer wird also nie mitten durchgebrochen.
     Im Zustand `--nowrap` ist die Regel folgenlos — dort bricht ohnehin
     nichts um. */
  overflow-wrap: anywhere;
}

/* Die letzte Zeile grenzt nach unten an nichts mehr ab. */
[data-bulung] .bul-tabelle tbody tr:last-child > * {
  border-bottom: none;
}

/* ── Zeilenzustaende ─────────────────────────────────────────────────────
   REIHENFOLGE IST PFLICHT: `.bul-zeile--gewaehlt` steht NACH dem Hover und
   gewinnt nur deshalb. Wer die gewaehlte Zeile nach oben schiebt, verliert
   sie unter der Maus — ohne dass irgendetwas rot wird. Dieselbe Falle wie
   bei der Statusleiter des Order Portals (styles.css:1263). */
[data-bulung] .bul-tabelle tbody tr {
  transition: background var(--dur-fast) var(--ease-standard);
}
/* Hover eine Stufe leiser als die Auswahl (seit 2026-10-01): `--fl-2` statt
   `--state-hover`. Eine Liste, die unter der Maus aufblinkt, wirkt unruhig. */
[data-bulung] .bul-tabelle tbody tr:hover {
  background: var(--fl-2);
}
[data-bulung] .bul-tabelle tbody tr.bul-zeile--gewaehlt {
  background: var(--state-selected);
}
/* ZWEITES SIGNAL neben der Farbe. Vier Zeilenzustaende auf hellem Grund
   liegen im Kontrast nur 1,0 bis 1,4 auseinander — bei Rot-Gruen-Schwaeche
   sind das vier gleiche Graustufen (gemessen 17.08.2026, Fleet Map). Der
   Balken liegt als eingesetzter Schatten IN der ersten Zelle: ein `box-shadow`
   direkt am `tr` ist bei `border-collapse: collapse` nicht verlaesslich, und
   ein absolut gesetztes `::after` verlangte `position: relative` an der
   Zeile — das nimmt der App eine Stelle weg, die sie oft selbst braucht. */
[data-bulung] .bul-tabelle tbody tr.bul-zeile--gewaehlt > *:first-child {
  box-shadow: inset var(--border-row-accent) 0 0 0 var(--green-deep);
}

/* ── Zahlenspalte ────────────────────────────────────────────────────────
   Monoschrift und tabellarische Ziffern stehen schon in basis/typografie.css
   an `.bul-zahl`. Hier kommt nur dazu, was die Spalte betrifft.
   `tabular-nums` allein reicht fuer gleiche BREITEN, nicht fuer gleiche
   FORMEN: in Jost liegen 1, 7 und 4 geometrisch nah beieinander, und genau
   in einer Zahlenspalte wird verglichen statt gelesen. */
[data-bulung] .bul-tabelle .bul-zahl {
  text-align: right;
  white-space: nowrap;
}

/* ── Zustand: dicht ──────────────────────────────────────────────────────
   Engere Zeilen fuer Bildschirme, an denen den ganzen Tag gearbeitet wird.
   Gesetzt wird nur die eine Variable — Kopf und Zelle ziehen mit, und ihre
   waagerechten Kanten bleiben deckungsgleich. */
[data-bulung] .bul-tabelle--dicht {
  --bul-tabelle-polster: var(--space-sm) var(--space-2m);
}

/* ── Zustand: nowrap ─────────────────────────────────────────────────────
   Keine Zelle bricht um. Ohne `nowrap` entscheidet die Auto-Verteilung der
   Tabelle, welche Spalte zu eng wird, und die getroffene Zeile wird doppelt
   so hoch (im Order Portal 75 statt 53 px, elf von 57 Zeilen).

   MIT `nowrap` IST DIE SPALTENBREITE DIE BREITE IHRES BREITESTEN WERTES —
   ein einziger Ausreisser genuegt, um die Tabelle ueber den Behaelter zu
   schieben. Wer das hier einschaltet, misst gegen den AKTUELLEN Datenbestand
   nach und deckelt seine Freitextspalten selbst. */
[data-bulung] .bul-tabelle--nowrap th,
[data-bulung] .bul-tabelle--nowrap td {
  white-space: nowrap;
  /* Nur hier, nicht am Grund-`td`: ein Auslassungszeichen erscheint ohne
     `nowrap` ohnehin nie, und `overflow: hidden` macht aus der Zelle einen
     Klippbereich — auch waagerecht. */
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── bauteile/knopf.css ──────────────────────────────────────────────── */
/* Bulung — Knopf
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Hauptquelle ist `fahrzeug-portal/static/styles.css` (`.btn`, Zeile 2094 ff.),
   zweite Quelle `order-portal/static/styles.css` (`.dismiss-modal button`,
   Zeile 1732 ff.) — dort steht die einzige gebaute Knopfgruppe des Hauses:
   ein bestaetigender und ein abbrechender Knopf nebeneinander.

   DIE UMBENENNUNG IST DER KERN. Der Bestand heisst nach ZWECK, nicht nach
   FORM, und ist deshalb nicht wiederverwendbar:

     .btn            -> .bul-knopf
     .btn-confirm    -> .bul-knopf--haupt
     .btn-cancel     -> .bul-knopf--leise
     .btn-step, .btn-today, .btn-row   BLEIBEN DRAUSSEN

   `.btn-step` (Datumsschritt), `.btn-today` (Sprung auf heute) und `.btn-row`
   (die Knopfreihe im Modal) sind Bildschirme, keine Formen. Ein System, das
   sie mitnimmt, liefert drei Apps einen Knopf, den nur die vierte je braucht.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (fahrzeug-portal/static/styles.css), Zeile in Klammern:

     .btn (2095-2099)     `inline-flex`, mittig in beiden Achsen, Abstand
                          zwischen Symbol und Wort (8 px), `font-family:
                          inherit`
     .btn (2102)          `line-height: 1` — ein Knopf ist eine Zeile, seine
                          Hoehe kommt aus Polster und Mindesthoehe
     .btn (2105)          `border-radius` aus dem Radius-Token
     .btn (2106)          `cursor: pointer`
     .btn (2109-2111)     weiche Blende auf Grund, Versatz und Schatten
     .btn:hover (2113)    Grund wechselt, kleiner Schatten kommt dazu
     .btn:active (2117)   1 px nach unten. `transform` verschiebt nichts im
                          Layout, kostet also keine Nachbarzeile.
     .btn--block (2118)   Vollbreite -> hier `.bul-knopf--breit`
     .btn[hidden] (3286)  `display: none` — noetig, weil `inline-flex` das
                          Attribut sonst ueberstimmt

   Aus `order-portal/static/styles.css`:
     .dismiss-modal       gemeinsame Form fuer BEIDE Knoepfe einer Gruppe
       button (1732)      (Polster, Radius, Gewicht, Blende) — genau die
                          Trennung, die dieses Bauteil macht: die Form steht
                          einmal, die Rolle steht als Zusatz daran.
     .btn-confirm (1744)  gruene Flaeche, Navy als Schrift -> `--haupt`
     .btn-cancel (1737)   leiser Knopf mit Kante statt Flaeche -> `--leise`

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Mindesthoehe 36 px     Die Quelle setzt `padding: 11px 20px` und laesst
                            die Hoehe aus Schriftgrad und Polster entstehen
                            (styles.css:2103) — gerechnet rund 36,7 px. Hier
                            steht die Hoehe als Zahl da, weil Knopf und Feld
                            NEBENEINANDER stehen und ihre Kanten sonst um
                            ein bis zwei Pixel auseinanderlaufen.
                            `bauteile/feld.css` traegt dieselbe Zahl.
     Grundknopf hat eine    Die Quelle kennt nur zwei Rollen: gruen gefuellt
     eigene Erscheinung     und leise. Ein neutraler Knopf ohne Rolle kommt
                            dort nicht vor. Er steht hier, weil in einer
                            Werkzeugleiste die meisten Knoepfe weder Haupt-
                            noch Abbruchhandlung sind.
     Kante --border-strong  Die Quelle hat `border: 0` am gruenen Knopf
                            (styles.css:2104) und `1px solid #e2e8f0` am
                            Abbruchknopf (order-portal:1739) — das sind
                            1,24 : 1 und faellt durch WCAG 1.4.11. Jede
                            Knopfkante hier traegt `--border-strong`
                            (3,05 : 1 auf --fl-2 hell, 3,08 dunkel).
                            Der gefuellte Knopf setzt sie auf `transparent`:
                            seine FLAECHE ist die Kante.
     --gefahr ist ein       Die Quelle fuellt ihn (`background: #dc2626`,
     UMRISS, keine Flaeche  weisse Schrift, order-portal:1760). Das laesst
                            sich hier NICHT registerneutral bauen: `--danger`
                            kippt zwischen den Registern (hell #c62828,
                            dunkel #fca5a5), und der einzige registerneutrale
                            Wert `--danger-surface` traegt weisse Schrift nur
                            3,76 : 1. Rot als TINTE traegt in beiden:
                            5,19 : 1 hell, 8,85 : 1 dunkel. Wer eine gefuellte
                            rote Flaeche will, braucht einen neuen Token —
                            als Befund verzeichnet, nicht hier erfunden.
     --klein                Gibt es in keiner Quelle. 28 px hoch, 12 px
                            Schrift — fuer Knoepfe IN einer Tabellenzeile,
                            deren Zeilenhoehe 36 px nicht traegt.
     ausgegraut             Die Quelle hat dafuer nur einen Sonderfall
                            (`.vp-btn-primary.is-disabled-soft`, ein Knopf,
                            der ABSICHTLICH klickbar bleibt). Hier die
                            gewoehnliche Fassung aus den vorhandenen Token.
     Schriftgrad 14 px      Die Quelle steht auf `0.92rem` = 14,72 px
                            (styles.css:2100). Die 14 kommen aus
                            `--fs-app-body` und aus der Ziel-API — dieselbe
                            Umrechnung wie beim Tabellenkopf.
     Schriftgewicht         Die Quelle hat 500 am `.btn` (styles.css:2101)
     500 / haupt 600        und 600 an BEIDEN Modalknoepfen
                            (order-portal:1734). Hier traegt der gewoehnliche
                            Knopf 500 und nur die HANDLUNG 600 — sonst ist in
                            einer Werkzeugleiste jeder Knopf halbfett und
                            keiner faellt mehr auf.
     Kante und Schrift      Die Quelle blendet nur Grund, Versatz und
     blenden mit            Schatten (styles.css:2109-2111). Hier blenden
                            auch `border-color` und `color` — ohne das
                            springt die Kante beim Ueberfahren hart, waehrend
                            die Flaeche darunter weich wechselt.
     `white-space: nowrap`  In keiner Quelle. Ein umbrechender Knopf zieht in
                            einer Werkzeugleiste die ganze Reihe hoeher.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .btn-step (209)          Datumsschritt der Werkzeugleiste, samt
                              `.btn-step--drop` und `--drop-blocked` (1512).
     .btn-today (322)         Sprung auf heute, samt `.is-current` (340).
     .btn-row (1729)          die Knopfreihe des Modals -> steht als
                              `.bul-modal-fuss` in bauteile/modal.css, weil
                              sie dort hingehoert und nicht zum Knopf.
     .btn--login (2120)       ein Aussenabstand fuer genau eine Seite.
     .modal-icon (1713)       Symbolkreis im Bestaetigungsdialog.
   ========================================================================== */

/* DIE FORM. Alles, was jeder Knopf braucht, egal welche Rolle er spielt.
   Der Fokusring steht NICHT hier — er kommt einmal aus `basis/fokus.css`.
   Ein Knopf, der ihn wiederholt, gewinnt die Kaskade gegen die Basis und
   nimmt einer App die einzige Stelle, an der sie ihn aendern kann. */
[data-bulung] .bul-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2s);
  /* Der Knopf erbt die Schrift der Seite. Ohne diese Zeile setzt der Browser
     seine eigene Systemschrift — der einzige Text der Oberflaeche, der nicht
     die Arbeitsschrift waere. */
  font-family: inherit;
  font-size: var(--fs-app-body);
  font-weight: var(--fw-medium);
  /* Ein Knopf ist EINE Zeile. Seine Hoehe kommt aus `min-height` und dem
     waagerechten Polster, nicht aus der Zeilenhoehe — sonst verschiebt jede
     Aenderung an `--lh-dense` alle Knopfhoehen des Hauses. */
  line-height: 1;
  /* 36 px, damit Knopf und Feld auf derselben Kante stehen. 2026-09-27 auf
     40 px gehoben, weil Jost bei 36 zu klein wirkte; seit 2026-10-01 mit
     Inter (groessere x-Hoehe) wieder 36 — das Mass von Enterprise-Apps.
     Das Polster 14 statt 24 px: ein breiter Knopf wirkt wie ein Banner. */
  min-height: 36px;
  padding: 0 calc(var(--space-2m) + var(--space-2xs));
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-sm);
  /* Haken fuer Glas, siehe karte.css: auf Glas ist ein deckend weisser
     Knopf ein Loch. */
  background: var(--knopf-flaeche, var(--fl-1));
  color: var(--text);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  /* Ein Knopf ist nie unterstrichen — auch nicht, wenn er ein <a> ist.
     Das kam im Pilotdurchgang (HR-Portal, 31.08.2026) heraus: vier Stellen
     tragen die Knopfform an einem Link, weil sie zu einer anderen Seite
     fuehren statt etwas abzusenden. Ohne diese Zeile setzt der Browser
     seinen Standardstrich unter die Beschriftung — an einem <button>
     faellt das nie auf, weil der von Haus aus keinen hat. */
  text-decoration: none;
  /* Der Knopf bleibt einzeilig. Ein umbrechender Knopf ist hoeher als seine
     Nachbarn, und in einer Werkzeugleiste zieht das die ganze Reihe mit. */
  white-space: nowrap;
  transition:
    background var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-fast) var(--ease-standard),
    transform var(--dur-fast) var(--ease-standard);
}

[data-bulung] .bul-knopf:hover {
  background: var(--fl-2);
  border-color: var(--border-hover);
}

/* Gedrueckt: die Flaeche wird eine Stufe dunkler, der Schatten geht weg —
   der Knopf liegt flach. Bis 2026-10-01 rutschte er 1 px nach unten; das
   wirkte wie ein Spielzeug, nicht wie ein Werkzeug. */
[data-bulung] .bul-knopf:active {
  background: var(--fl-3);
  box-shadow: none;
}

/* Symbole im Knopf: 16 px, fest, vor oder hinter der Beschriftung. Ohne
   diese Zeile erbt ein SVG die Groesse seiner viewBox. */
[data-bulung] .bul-knopf svg {
  width: var(--icon-sm);
  height: var(--icon-sm);
  flex: none;
}

/* Ausgegraut. Der Zeiger wechselt MIT — ohne das sieht ein toter Knopf aus
   wie ein lebender, bis man ihn drueckt. Kein Hover und kein Versatz mehr:
   beides behauptete, es passiere etwas.

   DIE KANTE BLEIBT AUF `--border-strong`, und zwar ausdruecklich: der
   gefuellte Hauptknopf setzt sie auf `transparent`, weil seine FLAECHE die
   Kante ist — ausgegraut verliert er diese Flaeche, und ohne diese Zeile
   stuende `--state-disabled-bg` (#f1f3f7) randlos auf `--fl-2` (#f3f6fb).
   Das sind 1,03 : 1: der Knopf waere nicht ausgegraut, sondern weg.
   Ausgegraut sagen hier Flaeche, Tinte und Zeiger, nicht die Kante. */
[data-bulung] .bul-knopf:disabled,
[data-bulung] .bul-knopf[aria-disabled="true"] {
  background: var(--state-disabled-bg);
  border-color: var(--border-strong);
  color: var(--state-disabled-ink);
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* `hidden` gewinnt gegen `inline-flex` nicht von allein. Ohne diese Zeile
   steht ein Knopf mit dem Attribut weiterhin da (styles.css:3286). */
[data-bulung] .bul-knopf[hidden] {
  display: none;
}

/* ── Rolle: Hauptknopf ───────────────────────────────────────────────────
   Die Markenfarbe als Flaeche, Navy als Schrift — 9,73 : 1, und beim
   Ueberfahren 8,18 (hell) bzw. 11,72 (dunkel). Die Kante wird durchsichtig
   statt entfernt: ein `border: 0` liesse den Knopf um 2 px schrumpfen und
   damit neben seinen Nachbarn springen. */
/* DER HAUPTKNOPF IST NAVY, seit 2026-09-23. Vorher Bulung Green mit Navy
   als Schrift: auf einer Seite mit drei gruenen Knoepfen, gruenen Abzeichen
   und gruenen Links war das Gruen kein Akzent mehr, sondern Tapete. Navy
   traegt die Marke ernster, und das Gruen bleibt fuer das, was es sagen
   soll — „hier bist du" (Rail) und „erledigt" (Abzeichen). 19,19 : 1. */
/* Seit 2026-10-01 mit eigenem Schatten (`--shadow-knopf-haupt`): eine
   helle Innenkante oben und ein dichter Schlagschatten unten. Das gibt der
   Flaeche Koerper, ohne zu leuchten. Der Hover geht auf `--navy-hover` —
   `--navy-light` lag so nah an Navy, dass man ihn nicht sah. */
[data-bulung] .bul-knopf--haupt {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--text-on-dark);
  font-weight: var(--fw-medium);
  box-shadow: var(--shadow-knopf-haupt);
}
[data-bulung] .bul-knopf--haupt:hover {
  background: var(--navy-hover);
  border-color: var(--navy-hover);
}
[data-bulung] .bul-knopf--haupt:active {
  background: var(--navy);
  box-shadow: none;
}

/* ── Rolle: leise ────────────────────────────────────────────────────────
   Der Abbruch neben der Zusage. Keine Flaeche, damit im Knopfpaar genau EINE
   Flaeche steht — zwei gefuellte Knoepfe nebeneinander sind zwei Angebote
   gleichen Ranges, und die Rueckfrage hat nur eine Antwort, die man meint. */
[data-bulung] .bul-knopf--leise {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--text-secondary);
}
[data-bulung] .bul-knopf--leise:hover {
  background: var(--fl-2);
  border-color: transparent;
  color: var(--text);
}

/* ── Rolle: Gefahr ───────────────────────────────────────────────────────
   Umriss statt Flaeche — die Begruendung steht oben unter den
   Neuentscheidungen: es gibt keinen registerneutralen Token fuer eine rote
   FLAECHE mit lesbarer Schrift. Rot als Tinte traegt 5,19 : 1 hell und
   8,85 : 1 dunkel, der Hover 6,73 und 6,07. */
[data-bulung] .bul-knopf--gefahr {
  background: var(--fl-1);
  border-color: var(--danger);
  color: var(--danger);
  font-weight: var(--fw-semi);
}
[data-bulung] .bul-knopf--gefahr:hover {
  background: var(--status-error-bg);
  border-color: var(--danger-hover);
  color: var(--danger-hover);
}

/* ── Groesse: klein ──────────────────────────────────────────────────────
   Fuer Knoepfe IN einer Tabellenzeile. Eine Zeile ist rund 44 px hoch — der
   gewoehnliche Knopf (40 px) wuerde sie aufschieben. */
[data-bulung] .bul-knopf--klein {
  min-height: 30px;
  padding: 0 var(--space-2m);
  font-size: var(--fs-meta);
}

/* ── Breite ──────────────────────────────────────────────────────────────
   Am Telefon ist ein vollbreiter Knopf als LETZTES Element einer Karte ein
   gutes Tastziel. Als Zustand und nicht an eine Bildschirmbreite gehaengt:
   das System entschiede sonst fuer alle vier Apps mit, ab wann ihre Knoepfe
   die Breite wechseln. */
[data-bulung] .bul-knopf--breit {
  width: 100%;
}

/* ── Variante: Symbol ────────────────────────────────────────────────────
   Quadratisch, ohne Rahmen, nur ein Symbol. Fuer „⋯" in Tabellenzeilen und
   die Glocke. Leise, bis man darueberfaehrt: eine Zeile mit zehn gerahmten
   Knoepfen ist ein Schaltpult, keine Liste. Braucht IMMER `aria-label`.
   Seit 2026-09-27 (HR-Portal, Spec Grundgeruest UX). */
[data-bulung] .bul-knopf--symbol {
  min-height: 32px;
  width: 32px;
  padding: 0;
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  color: var(--text-secondary);
}
[data-bulung] .bul-knopf--symbol:hover,
[data-bulung] .bul-knopf--symbol[aria-expanded="true"],
[data-bulung] details[open] > .bul-knopf--symbol {
  background: var(--fl-2);
  border-color: transparent;
  color: var(--text);
}
[data-bulung] .bul-knopf--symbol svg {
  width: var(--icon-md);
  height: var(--icon-md);
}

/* ── bauteile/feld.css ───────────────────────────────────────────────── */
/* Bulung — Feld
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Beide Portale beschreiben ihre Eingabefelder mehrfach und fast gleich:
     fahrzeug-portal/static/styles.css  `.vp-field` (1813 ff.), Etikett (1799),
                                        Kontrollkaestchen (1930 ff.),
                                        Fehlerzustand (2024 ff.)
     order-portal/static/styles.css     `.admin-login-box input` (2507),
                                        `.admin-panel-controls` (2575),
                                        `.auth-login-box input` (2616)
   Das fahrzeug-portal sagt an seiner Regel woertlich „1:1 wie
   .admin-login-box input bzw. .admin-panel-controls" (styles.css:1812) — es
   ist DIESELBE Regel, dreimal getippt. Genau dafuer gibt es dieses Bauteil.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (fahrzeug-portal/static/styles.css), Zeile in Klammern:

     .vp-field input      Polster, Radius, `font-family: inherit`,
       (1818-1826)        Schriftgrad, Textfarbe, Flaeche, weiche Blende auf
                          Kante und Schatten
     .vp-field            eine Regel fuer `input[type=text|date|password|
       (1813-1817)        email]` UND `select` — Eingabefeld und Auswahlfeld
                          sind dieselbe Form
     ::placeholder        Platzhalter leiser als der Wert
       (1834)
     label (1799-1805)    Versalien, Sperrung, halbfett, leiser als der Wert
                          -> `.bul-etikett`
     .vp-flag             Kontrollkaestchen: `appearance: none`, 16 px,
       input (1930-1940)  eigener Radius, eigene Flaeche, weiche Blende
     :checked (1949)      gefuellt in der Markenfarbe
     :checked::after      der Haken als gedrehtes L aus zwei Kanten
       (1953-1963)
     .vp-field--invalid   roter Rand im Fehlerfall -> `.bul-feld--fehler`
       (2024-2027)

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Kante --border-strong  ALLE Quellen setzen `1px solid var(--border)`
                            (styles.css:1820, order-portal:2510/2578). Das
                            sind 1,24 : 1 und faellt durch WCAG 1.4.11: die
                            Kante ist DA, sie ist nur zu leise, und genau
                            deshalb faellt der Fehler niemandem auf. Hier
                            `--border-strong` — 3,05 : 1 auf `--fl-2` hell,
                            3,08 dunkel. Beim Ueberfahren `--border-hover`
                            (4,27 / 4,50). Waechter G14 haelt das fest.
     KEIN `outline: none`   Jede Quelle setzt beim Fokus `outline: none` und
                            baut sich einen eigenen Ring aus `box-shadow`
                            (styles.css:1828-1832, order-portal:2516/2584).
                            Das Design-System hat EINEN Fokusring in
                            `basis/fokus.css`; ein `outline: none` hier
                            loeschte ihn fuer alle vier Apps, und der Ersatz
                            waere je Bauteil neu zu pflegen.
     Grund --fl-2           Die Quellen setzen `var(--white)`
                            (styles.css:1823) — im Dunkelregister waere das
                            eine weisse Flaeche mitten in einer dunklen
                            Oberflaeche. `--fl-2` nennt das Eingabefeld
                            woertlich als seinen Zweck und kippt mit dem
                            Register.
     Mindesthoehe 36 px     Die Quelle laesst die Hoehe aus `padding: 10px
                            12px` entstehen (styles.css:1819). Hier steht sie
                            als Zahl, damit Feld und Knopf nebeneinander auf
                            derselben Kante sitzen — `bauteile/knopf.css`
                            traegt dieselbe.
     KEINE Breite           Die Quelle setzt `width: 100%` (styles.css:1818),
                            weil ihre Felder in einer Formularspalte stehen.
                            Wie breit ein Feld ist, entscheidet das Layout
                            der App, nicht das Feld.
     Haken aus rohen px     `left: 4px; top: 1px; width: 4px; height: 8px`
                            (styles.css:1956-1959) sind eine ZEICHNUNG in
                            einem 16-px-Kasten, kein Abstand. Dafuer gibt es
                            heute keinen Token und soll es keinen geben —
                            als Befund verzeichnet.
     Kaestchen-Kante 1 px   Die Quelle hat 1,5 px (styles.css:1934) auf
                            `--border`. Der Kontrast kommt hier aus der
                            FARBE (`--border-strong`), nicht aus der Staerke;
                            damit passt die Kante wieder auf
                            `--border-width` und laeuft nicht als einziger
                            Wert des Hauses auf halben Pixeln.
     Etikett 11 px          Die Quelle steht auf `0.72rem` = 11,52 px
                            (styles.css:1800). 11 kommt aus
                            `--fs-app-micro`, dieselbe Stufe wie der
                            Tabellenkopf — beide sind Beschriftungen.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .vp-field (1794)         die Spalte aus Etikett, Feld und Hinweis. Ein
                              Formularlayout, kein Feld.
     .vp-req (1806)           der Pflichtstern.
     .vp-field-hint (2017)    der Hinweistext unter dem Feld — und mit ihm
                              die Regel, dass er erst im Fehlerfall
                              erscheint. Das ist Verhalten.
     .vp-field--autocomplete  Vorschlagsliste unter dem Feld (1839 ff.).
     .fk-suche input (434)    das Suchfeld der Filterkarte des Order Portals
                              samt `::-webkit-search-cancel-button` (450).
     .fk-sz input (608)       ein VERSTECKTES Kontrollkaestchen mit
                              nachgebautem Kasten daneben (635-640). Ein
                              zweiter Weg zur selben Sache; hier gilt der
                              erste (`appearance: none` am Element selbst).
     .date-filter-popover     Datumsfeld in einem Aufklapper (933).
     .mail-dialog-input       Felder eines bestimmten Dialogs (3184).
     Warnfarbe im Fehlerfall  Die Quelle nimmt `--warn` (styles.css:2026) —
                              ein Token, das es im System nicht gibt. Hier
                              `--danger`.
   ========================================================================== */

/* DIE FORM. Eingabefeld, Auswahlfeld und Textfeld sind dasselbe Ding.
   Die Quelle sagt das selbst, indem sie alle vier `input`-Arten und `select`
   in EINEN Selektor schreibt (styles.css:1813-1817). */
[data-bulung] .bul-feld {
  /* Ohne `inherit` setzt der Browser seine eigene Systemschrift — bei
     `select` und `textarea` sogar eine andere als bei `input`. */
  font-family: inherit;
  font-size: var(--fs-app-body);
  line-height: var(--lh-dense);
  /* 36 px, gemeinsam mit dem Knopf (2026-09-27 bis 2026-10-01: 40 px). Das
     senkrechte Polster muss UNTER der Mindesthoehe bleiben: bei 36 px stand
     das Feld mit 8 px schon auf 36,89 px (gemessen 2026-08-30), und Knopf und
     Feld standen versetzt. Mit Inter und Zeile 1,45 sind es 20,3 px Text —
     deshalb 6 px senkrecht (34,3 px). Waagerecht bleiben die 12 px der
     Quelle (styles.css:1819). */
  min-height: 36px;
  padding: var(--space-2s) var(--space-2m);
  /* DIE KANTE EINES BEDIENELEMENTS TRAEGT 3 : 1 (WCAG 1.4.11). Die
     dekorative Haarlinie `--border` traegt 1,24 — sie ist sichtbar genug,
     um „da ist ein Feld" zu behaupten, und zu leise, um es zu zeigen.
     Waechter G14 verbietet sie hier. */
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--fl-1);
  color: var(--text);
  box-shadow: var(--shadow-xs);
  transition:
    border-color var(--dur-fast) var(--ease-standard),
    background var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-fast) var(--ease-standard);
}

/* Beim Ueberfahren wird die Kante STAERKER, nicht bunter: 4,27 : 1 hell,
   4,50 dunkel. Eine Farbaenderung waere ein zweites Signal, das mit dem
   Fehlerzustand darunter um dieselbe Bedeutung stritte. */
/* DAS AUSWAHLFELD TRAEGT DEN PFEIL DES SYSTEMS, seit 2026-09-23. Der
   Pfeil des Browsers ist je Betriebssystem ein anderer, sitzt ohne Abstand
   an der Kante und machte jedes Filterformular zum Fremdkoerper neben den
   eigenen Knoepfen. Der eigene Pfeil ist ein Winkel in `--text-muted`
   (#6b7083 — im Bild ausgeschrieben, weil ein Hintergrundbild keine
   Variable lesen kann). */
[data-bulung] select.bul-feld {
  appearance: none;
  -webkit-appearance: none;
  padding-right: calc(var(--space-2m) + var(--icon-sm) + var(--space-xs));
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7083' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-2m) center;
  background-size: var(--icon-sm);
  cursor: pointer;
}
[data-bulung] .bul-feld:hover {
  border-color: var(--border-hover);
}

/* Fokus im Feld (seit 2026-10-01): die Kante selbst wird zum Ring
   (--focus-ring, 7,12 : 1) und bekommt einen weichen Hof. Der abgesetzte
   2-px-Ring aus `basis/fokus.css` stand um ein Feld wie ein Browserrahmen;
   Knoepfe und Links behalten ihn. */
[data-bulung] .bul-feld:focus-visible {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: var(--focus-hof);
}

/* KEIN `:focus { outline: none }`. Der Ring steht einmal in basis/fokus.css.
   Alle drei Quellen loeschen ihn hier und bauen ihn aus einem `box-shadow`
   nach — dann gibt es vier Ringe im Haus und keinen Ort, sie zu aendern. */

[data-bulung] .bul-feld::placeholder {
  color: var(--text-muted);
  /* Firefox nimmt dem Platzhalter sonst Deckkraft und macht aus 4,54 : 1
     eine unlesbare Andeutung. */
  opacity: 1;
}

/* Ausgegraut. Die Kante BLEIBT auf `--border-strong`: `--state-disabled-bg`
   (#f1f3f7) traegt auf `--fl-2` (#f3f6fb) 1,03 : 1 — ohne Kante waere das
   Feld nicht ausgegraut, sondern unsichtbar. Ausgegraut sagen Flaeche, Tinte
   und Zeiger. */
[data-bulung] .bul-feld:disabled {
  background: var(--state-disabled-bg);
  color: var(--state-disabled-ink);
  cursor: not-allowed;
}

/* ── Zustand: Fehler ─────────────────────────────────────────────────────
   NUR die Kante. Der Grund bleibt, wie er ist: eine rot getoente Flaeche
   waere ein zweites Signal fuer dieselbe Sache und faerbte ausgerechnet den
   Text ein, den der Nutzer gerade korrigieren soll. Farbe allein traegt
   nicht — der Hinweistext daneben ist das zweite Signal, und der gehoert
   der App. */
[data-bulung] .bul-feld--fehler,
[data-bulung] .bul-feld--fehler:hover {
  border-color: var(--danger);
}

/* ── Etikett ─────────────────────────────────────────────────────────────
   Dieselbe Stufe wie der Tabellenkopf: beide beschriften, statt zu sagen.
   `--text-secondary` und nicht `--text-muted` — auf `--fl-well` traegt
   `--text-muted` nur 4,15 : 1, und ein Etikett steht oft in einer
   eingelassenen Bank. */
/* DAS ETIKETT IN SATZSCHREIBUNG, seit 2026-09-23. Versalien mit Sperrung
   sind die Stimme einer Bildunterschrift; ueber einem Eingabefeld schrien
   sie jedes Formular an. 13 px mittel in Textfarbe liest sich als Frage,
   und das Feld darunter als Antwort. */
[data-bulung] .bul-etikett {
  display: block;
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  color: var(--text);
}

/* ── Kontrollkaestchen ───────────────────────────────────────────────────
   `appearance: none` und selbst gezeichnet: das native Kaestchen nimmt
   weder Farbe noch Radius an, und `accent-color` faerbt nur die Fuellung —
   die zu leise Kante des ungehakten Zustands bliebe. */
[data-bulung] .bul-kaestchen {
  appearance: none;
  -webkit-appearance: none;
  /* Fest quadratisch. `--icon-sm` ist die Symbolgroesse des Hauses; ein
     Kaestchen ist ein Symbol, kein Abstand. */
  width: var(--icon-sm);
  height: var(--icon-sm);
  /* `flex: none`: in einer Zeile mit langem Text schrumpft es sonst zum
     Strich, und ein halbes Kaestchen sieht aus wie ein Zeichenfehler. */
  flex: none;
  margin: 0;
  position: relative;
  border: var(--border-width) solid var(--border-strong);
  /* Kleiner als `--radius-sm`: 8 px an einem 16-px-Kasten waere fast ein
     Kreis, und ein Kreis heisst „genau eine Wahl". Fuer diese kleine Rundung
     gibt es heute keinen Token — als Befund verzeichnet. */
  border-radius: 3px;
  background: var(--fl-2);
  cursor: pointer;
  transition:
    background var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard);
}
[data-bulung] .bul-kaestchen:hover {
  border-color: var(--border-hover);
}
[data-bulung] .bul-kaestchen:checked {
  background: var(--green);
  border-color: var(--green);
}
/* Der Haken ist ein gedrehtes L aus zwei Kanten — kein Zeichen und kein
   Bild: eine Schrift muesste geladen sein, ein Bild koennte seine Farbe
   nicht aus dem Token nehmen. Die vier Masse sind eine ZEICHNUNG in einem
   16-px-Kasten und haben deshalb keinen Token (Befund). */
[data-bulung] .bul-kaestchen:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--ink-on-green);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
[data-bulung] .bul-kaestchen:disabled {
  background: var(--state-disabled-bg);
  cursor: not-allowed;
}
[data-bulung] .bul-kaestchen:disabled:checked::after {
  border-color: var(--state-disabled-ink);
}

/* ── bauteile/abzeichen.css ──────────────────────────────────────────── */
/* Bulung — Abzeichen
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Quelle ist `order-portal/static/styles.css` (`.status-badge`, Zeile 1089
   ff.) — das einzige gebaute Abzeichen des Hauses, und zugleich das mit der
   groessten Fachlast: die elf Auftragszustaende darunter (1121-1146) sind
   seit dem 27.08.2026 die Statusleiter des Order Portals.

   ZWEI FAMILIEN, DIE NICHT VERMISCHT WERDEN. Das steht schon in
   `tokens/colors.css` und gilt hier woertlich:

     --status-*    fuenf GENERISCHE Zustaende (info, warn, success, error,
                   neutral). Sie beschreiben eine Meldung.
     --auftrag-*   elf AUFTRAGSZUSTAENDE des Order Portals. Sie beschreiben,
                   wie weit ein Auftrag ist, und sie sind eine LEITER: die
                   Reihenfolge traegt die Bedeutung, nicht die einzelne Farbe.

   Wer `--auftrag-organisiert` fuer „Erfolg" haelt, hat die Leiter zerlegt.
   Deshalb heissen die Zusaetze hier ausgeschrieben `--auftrag-…` und teilen
   sich keinen Namensraum mit den fuenf generischen.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (order-portal/static/styles.css), Zeile in Klammern:

     .status-badge        `inline-flex`, mittig, Abstand zwischen Punkt und
       (1089-1098)        Wort (6 px), Pillenradius, halbfett, `nowrap`
     .status-badge .dot   der Punkt: rund, 7 px, `flex-shrink: 0`
       (1099-1104)
     Polster 4px 12px     (1093) — waagerecht dreimal so viel wie senkrecht;
                          eine Pille ist breiter als hoch.
     `white-space:nowrap` (1097) — ein umbrechendes Abzeichen ist keine
                          Pille mehr, und in einer Tabellenzelle zieht es die
                          ganze Zeile hoeher.
     Die elf Farbpaare    (1121-1146) samt Punktfarbe. Sie stehen als Token
                          in `tokens/colors.css` und werden hier nur gelesen.

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Schriftgrad 12 px      Die Quelle steht auf `0.85rem` = 13,6 px
                            (styles.css:1095). 12 kommt aus
                            `--fs-app-caption`; das Abzeichen sitzt in einer
                            Tabellenzeile und darf sie nicht hoeher machen
                            als ihren eigenen Text (14 px).
     Punkt 7 px roh         `--space-2xs` waere 2 px, `--space-xs` 4 —
                            beides sind ABSTAENDE. Fuer den Durchmesser
                            eines Signalpunktes gibt es heute keinen Token,
                            und einen Abstandstoken dafuer zu nehmen waere
                            ein Kategorienfehler. Wert aus der Quelle
                            uebernommen (styles.css:1100), als Befund
                            verzeichnet.
     Radius --radius-pill   Die Quelle hat `border-radius: 20px`
                            (styles.css:1094) — bei 24 px Hoehe ist das
                            faktisch eine Pille, aber eine, die bei jeder
                            Hoehenaenderung eckig wird. `--radius-pill`
                            (9999px) sagt, was gemeint ist.
     `.bul-abzeichen`       Die Quelle hat KEINE Grundfarbe am `.status-badge`
     ohne Zusatz            selbst — ohne eine der elf Klassen ist es
                            durchsichtig mit geerbtem Text. Hier traegt die
                            Grundform `--status-neutral-*`: ein Abzeichen
                            ohne Zusatz soll wie ein Abzeichen aussehen, nicht
                            wie vergessenes Markup.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     Die Zuordnung          Welcher Auftragszustand welches Abzeichen
     Zustand -> Klasse      bekommt, entscheidet `auftragsstatus.py` /
                            `filters.js` im Order Portal. Das System liefert
                            die elf Formen, nicht die Regel.
     .status-pill (2736)    ein anderes Bauteil mit gleichem Wortstamm:
                            aktiv/inaktiv eines Kontos (2746). Kein Zustand
                            einer Sache, sondern ein Schalterzustand.
     .pill-flag (789)       ein Flaggenbild in einer Filterpille — ein Bild
                            mit Rundung, kein Abzeichen.
     tr[data-updated]       die ZEILENtoenung derselben Leiter (1270-1312).
       (1270)               Sie faerbt Tabellenzeilen und gehoert zur
                            Tabelle des Order Portals, nicht zum Abzeichen.
                            Achtung: wer eine Abzeichenfarbe aendert, muss
                            die Zeilentoenung mitziehen — die Quelle sagt es
                            an ihrer Regel selbst (styles.css:1119).
   ========================================================================== */

/* DIE FORM. Ohne Zusatz ein neutrales Abzeichen. */
[data-bulung] .bul-abzeichen {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2s);
  /* Seit 2026-10-01 ein ETIKETT statt einer Pille: 6 px Radius, schmaleres
     Polster, eine feine Innenkante in der eigenen Schriftfarbe. Die Pille
     mit 16 px Polster sah aus wie ein Knopf; ein Etikett liest sich als
     Zustand. Die Kante ist `currentColor` bei 18 % — sie folgt jeder Art,
     ohne eine eigene Farbe zu brauchen (G5). */
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-xs);
  box-shadow: inset 0 0 0 var(--border-width) color-mix(in srgb, currentColor 18%, transparent);
  font-size: var(--fs-app-caption);
  /* medium -> semi seit 2026-09-25: in einer Liste mit zwanzig Zeilen muss
     der Status beim Ueberfliegen auffallen. Gilt auch mit Inter. */
  font-weight: var(--fw-semi);
  line-height: 1.5;
  /* Eine umbrechende Pille ist keine Pille mehr — und in einer Tabellenzelle
     zieht sie die ganze Zeile hoeher. */
  white-space: nowrap;
  background: var(--status-neutral-bg);
  color: var(--status-neutral-fg);
}

/* Der Punkt ist das ZWEITE Signal neben der Flaechenfarbe. Fuenf getoente
   Flaechen liegen im Kontrast dicht beieinander; der Punkt traegt die
   kraeftige Farbe, die als Flaeche hinter Text nicht ginge.
   7 px stehen roh da — fuer den Durchmesser eines Signalpunktes gibt es
   heute keinen Token (Befund). `flex: none`, sonst schrumpft er neben einem
   langen Wort zum Strich. */
[data-bulung] .bul-abzeichen-punkt {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  flex: none;
  background: var(--status-neutral-dot);
}

/* ── Familie 1: die fuenf generischen Zustaende ──────────────────────────
   Sie beschreiben eine MELDUNG (Hinweis, Warnung, Erfolg, Fehler, nichts).
   Jedes Paar traegt mindestens 4,5 : 1 — Waechter G15 rechnet es nach. */
[data-bulung] .bul-abzeichen--info {
  background: var(--status-info-bg);
  color: var(--status-info-fg);
}
[data-bulung] .bul-abzeichen--info .bul-abzeichen-punkt { background: var(--status-info-dot); }

[data-bulung] .bul-abzeichen--warnung {
  background: var(--status-warn-bg);
  color: var(--status-warn-fg);
}
[data-bulung] .bul-abzeichen--warnung .bul-abzeichen-punkt { background: var(--status-warn-dot); }

[data-bulung] .bul-abzeichen--erfolg {
  background: var(--status-success-bg);
  color: var(--status-success-fg);
}
[data-bulung] .bul-abzeichen--erfolg .bul-abzeichen-punkt { background: var(--status-success-dot); }

[data-bulung] .bul-abzeichen--fehler {
  background: var(--status-error-bg);
  color: var(--status-error-fg);
}
[data-bulung] .bul-abzeichen--fehler .bul-abzeichen-punkt { background: var(--status-error-dot); }

[data-bulung] .bul-abzeichen--neutral {
  background: var(--status-neutral-bg);
  color: var(--status-neutral-fg);
}
[data-bulung] .bul-abzeichen--neutral .bul-abzeichen-punkt { background: var(--status-neutral-dot); }

/* ── Familie 2: die elf Auftragszustaende ────────────────────────────────
   NUR IM HELLEN REGISTER. Die `--auftrag-*`-Token stehen ausschliesslich auf
   `:root`; das Dunkelregister ueberschreibt keinen einzigen davon. Das ist
   Absicht und kein Loch:

     Das Order Portal ist hell, und diese Farben sind gegen SEINEN Grund
     eingestellt — cyan zwischen blau und gruen, weil die REIHENFOLGE die
     Auskunft ist (styles.css:1105-1120). Eine dunkle Fassung waere nicht
     uebersetzt, sondern erfunden: sie muesste elf Farbpaare neu waehlen und
     dabei ihre Abstaende zueinander erhalten — und niemand haette sie je
     gegen echte Auftraege gesehen.

   FOLGE, DIE MAN KENNEN MUSS: wer eines dieser Abzeichen im Dunkelregister
   benutzt, bekommt die HELLEN Werte (helle Flaeche, dunkle Schrift) auf
   dunklem Grund. Das ist lesbar — G15 rechnet dieselben Paare nach —, aber es
   ist ein heller Fleck in einer dunklen Oberflaeche. Wer die Leiter dort
   braucht, waehlt elf Paare aus und misst sie, statt diese hier umzufaerben.

   Die Reihenfolge unten IST die Leiter:
     Arbeit noetig -> empfangen (blau) · offen (cyan) · aktualisiert (gold)
     erledigt      -> organisiert (Bulung-Gruen) · disponiert (teal) ·
                      entladen (grau)
     auffaellig    -> reklamation (rot), und nur das
     dazu          -> erledigt (Notausgang von Hand) · neu · default ·
                      positioniert (Altbestand) */
[data-bulung] .bul-abzeichen--auftrag-empfangen {
  background: var(--auftrag-empfangen-bg);
  color: var(--auftrag-empfangen-fg);
}
[data-bulung] .bul-abzeichen--auftrag-empfangen .bul-abzeichen-punkt { background: var(--auftrag-empfangen-dot); }

[data-bulung] .bul-abzeichen--auftrag-offen {
  background: var(--auftrag-offen-bg);
  color: var(--auftrag-offen-fg);
}
[data-bulung] .bul-abzeichen--auftrag-offen .bul-abzeichen-punkt { background: var(--auftrag-offen-dot); }

[data-bulung] .bul-abzeichen--auftrag-aktualisiert {
  background: var(--auftrag-aktualisiert-bg);
  color: var(--auftrag-aktualisiert-fg);
}
[data-bulung] .bul-abzeichen--auftrag-aktualisiert .bul-abzeichen-punkt { background: var(--auftrag-aktualisiert-dot); }

[data-bulung] .bul-abzeichen--auftrag-organisiert {
  background: var(--auftrag-organisiert-bg);
  color: var(--auftrag-organisiert-fg);
}
[data-bulung] .bul-abzeichen--auftrag-organisiert .bul-abzeichen-punkt { background: var(--auftrag-organisiert-dot); }

[data-bulung] .bul-abzeichen--auftrag-disponiert {
  background: var(--auftrag-disponiert-bg);
  color: var(--auftrag-disponiert-fg);
}
[data-bulung] .bul-abzeichen--auftrag-disponiert .bul-abzeichen-punkt { background: var(--auftrag-disponiert-dot); }

[data-bulung] .bul-abzeichen--auftrag-entladen {
  background: var(--auftrag-entladen-bg);
  color: var(--auftrag-entladen-fg);
}
[data-bulung] .bul-abzeichen--auftrag-entladen .bul-abzeichen-punkt { background: var(--auftrag-entladen-dot); }

[data-bulung] .bul-abzeichen--auftrag-reklamation {
  background: var(--auftrag-reklamation-bg);
  color: var(--auftrag-reklamation-fg);
}
[data-bulung] .bul-abzeichen--auftrag-reklamation .bul-abzeichen-punkt { background: var(--auftrag-reklamation-dot); }

[data-bulung] .bul-abzeichen--auftrag-erledigt {
  background: var(--auftrag-erledigt-bg);
  color: var(--auftrag-erledigt-fg);
}
[data-bulung] .bul-abzeichen--auftrag-erledigt .bul-abzeichen-punkt { background: var(--auftrag-erledigt-dot); }

[data-bulung] .bul-abzeichen--auftrag-neu {
  background: var(--auftrag-neu-bg);
  color: var(--auftrag-neu-fg);
}
[data-bulung] .bul-abzeichen--auftrag-neu .bul-abzeichen-punkt { background: var(--auftrag-neu-dot); }

[data-bulung] .bul-abzeichen--auftrag-default {
  background: var(--auftrag-default-bg);
  color: var(--auftrag-default-fg);
}
[data-bulung] .bul-abzeichen--auftrag-default .bul-abzeichen-punkt { background: var(--auftrag-default-dot); }

/* ALTBESTAND. `positioniert` wird seit dem 27.08.2026 nie mehr geschrieben,
   steht aber in der Historie und an Auftraegen, die das Gateway gerade nicht
   beantworten kann. Nicht fuer Neues verwenden. */
[data-bulung] .bul-abzeichen--auftrag-positioniert {
  background: var(--auftrag-positioniert-bg);
  color: var(--auftrag-positioniert-fg);
}
[data-bulung] .bul-abzeichen--auftrag-positioniert .bul-abzeichen-punkt { background: var(--auftrag-positioniert-dot); }

/* ── bauteile/karte.css ──────────────────────────────────────────────── */
/* Bulung — Karte
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Quellen sind `bulung-daily-report/src/lib/ui/Panel.svelte` und
   `src/lib/components/Block.svelte`. Panel.svelte ist am 14.08.2026 genau
   dafuer gebaut worden: sein Kopfkommentar zaehlt VIER Bauformen fuer
   denselben Gedanken „Titel, Nebensatz, Handlung" auf einem Schirm auf und
   legt EINEN Kopfvertrag fest. Diese Datei nimmt genau diesen Vertrag mit.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Aus `Panel.svelte`:

     .tafel-flaeche       Flaeche, Radius, Polster, `min-width: 0` und
                          `display: flex; flex-direction: column` mit Abstand
                          zwischen Kopf und Inhalt
     .kopf                `flex`, `space-between`, `align-items:flex-start`,
                          `flex-wrap: wrap` — der Kopf steht auch OHNE
                          Handlung als Raster da, damit die Titel mehrerer
                          Karten einer Reihe auf derselben Grundlinie sitzen
                          (die Quelle nennt 2 px Versatz als den Fehler,
                          gegen den das gebaut wurde)
     .worte               `min-width: 0` — ohne das schiebt ein langer Titel
                          die Handlung aus der Karte
     .handlung            `flex: none`
     h2                   Titelstufe, halbfett, enge Zeilenhoehe
     .unterzeile          eine Stufe kleiner, leiser, mit Abstand nach oben
     .inhalt              `flex: 1` und `min-width: 0` — sonst sitzt eine
                          Karte, die im Raster mit einer hoeheren Nachbarin
                          gleich hoch gezogen wird, oben und laesst unten ein
                          Loch

   Aus `Block.svelte`:
     .block               „Eine Flaeche, eine Haarlinie, sonst nichts — kein
                          Schatten, kein Verlauf" (woertlich im Quelltext).
                          Genau diese Fassung gilt hier, siehe unten.

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Haarlinie statt        DIE ZWEI QUELLEN WIDERSPRECHEN SICH: `Panel.svelte`
     Schatten               nimmt `box-shadow: var(--ring)`, `Block.svelte`
                            `border: 1px solid var(--kante)`. Hier gilt die
                            Linie, und der Grund ist das Dunkelregister:
                            `tokens/effects.css` setzt dort `--shadow-sm` und
                            `--shadow-md` ausdruecklich auf `0 0 transparent`,
                            weil unter einer dunklen Karte kein Licht fehlt.
                            Eine Karte, die ihre Kante aus einem Schatten
                            bezieht, HAT im Dunkelregister keine.
                            Die Linie ist hier `--border` und nicht
                            `--border-strong`: eine Karte ist kein
                            Bedienelement, sie gruppiert nur.
     Polster                Beide Quellen nehmen `--pad-karte` — ein Token,
     --pad-card-dense       das es im System nicht gibt. `--pad-card` (24 px)
                            ist die Lesefassung, `--pad-card-dense` (16 px)
                            die Arbeitsflaeche. Karten stehen hier auf
                            Arbeitsflaechen.
     Titel --fs-app-h3      Beide Quellen nehmen `--t-gross`, auch das kein
                            Token dieses Systems. 17 px ist die passende
                            Stufe der Arbeitsflaechen-Skala.
     KEIN Raster            `Block.svelte` legt vier Rasterbereiche fest
                            (Kopf, Handlung, Zusammenfassung, Aufklappteil)
                            und dreht sie am Telefon um. Das ist der Aufbau
                            EINER bestimmten Karte, kein Kartenbauteil — und
                            es braeuchte eine Media Query, also eine
                            Entscheidung des Systems ueber vier Apps hinweg.
     Unterzeile             `--text-muted` traegt auf `--fl-1` 4,92 : 1 hell
     --text-muted           und 5,54 dunkel. Beide Quellen nehmen es auch;
                            hier steht es mit der Zahl daneben, weil es auf
                            der eingelassenen Flaeche `--fl-well` NICHT mehr
                            traegt (4,15 : 1) — wer die Karte dort hineinlegt,
                            muss nachmessen.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .nummer                  die Ordnungszahl im Blockkopf. Sie zaehlt die
                              sieben Bloecke des Tagesberichts ab.
     .achse                   der Achsenvorbehalt („Tag und Monat") — ein
                              fachlicher Hinweis, keine Unterzeile.
     .schalter / .pfeil       der Aufklappknopf samt drehendem Pfeil. Ein
                              Knopf; die Form dafuer steht in
                              `bauteile/knopf.css`.
     .huelle / .innen         das Aufklappen ueber `grid-template-rows:
                              0fr -> 1fr`. Verhalten, kein Aussehen — und es
                              haengt an zwei Pflichtzeilen (`overflow: hidden`,
                              `min-height: 0`), die nur im Zusammenhang mit
                              dem Schalter Sinn ergeben.
     .details                 der Trennstrich ueber dem aufgeklappten Teil.
     @media (max-width:639px) die Umordnung am Telefon (s.o.).
   ========================================================================== */

/* DIE FLAECHE. Eine Karte ist eine Flaeche, eine Haarlinie und ein Polster —
   kein Schatten, kein Verlauf. Auf hellem Grund traegt schon der Unterschied
   zwischen Weiss und Arbeitsgrund die Ebene, auf dunklem traegt der Schatten
   ohnehin nichts. */
[data-bulung] .bul-karte {
  display: flex;
  flex-direction: column;
  /* 16 -> 12 px seit 2026-09-27: bei 16 stand der Titel so weit ueber dem
     Inhalt wie die Zeilen voneinander und las sich wie eine davon. */
  gap: var(--space-2m);
  /* Ohne das schiebt ein langes Wort im Inhalt die Karte aus ihrer
     Rasterspalte — der Standardwert `min-width: auto` laesst ein Flex- oder
     Rasterkind nicht unter seine Inhaltsbreite schrumpfen. */
  min-width: 0;
  /* 20 -> 24 px seit 2026-09-25 (HR-Portal, „Abstaende"): ein Rhythmus aus
     24 innen und 32 zwischen den Abschnitten. */
  padding: var(--pad-card);
  /* HAKEN FUER GLAS (28.09.2026, HR-Portal): eine App, die ihren Grund
     einfaerbt, setzt diese Variablen und macht jede Karte zu Glas.
     Wer nichts setzt, bekommt genau die Karte von vorher (Rueckfall).

     `--karte-filter` IST EIN EIGENER HAKEN, nicht `--glas-filter` wie bei
     Menue und Modal. Ein `backdrop-filter` macht die Karte zum Bezugsrahmen
     fuer jedes `position: fixed` darin — ein festes Zeilenmenue in einer
     Karte stuende dann versetzt (gemessen im HR-Portal: 1440 px rechts aus
     dem Fenster). Wer ihn setzt, hat keine festen Menues in Karten. */
  border: var(--border-width) solid var(--karte-rand, var(--border));
  border-radius: var(--radius);
  background: var(--karte-flaeche, var(--surface));
  box-shadow: var(--karte-schatten, var(--shadow-xs));
  -webkit-backdrop-filter: var(--karte-filter, none);
  backdrop-filter: var(--karte-filter, none);
  color: var(--text);
}

/* ── Kopf ────────────────────────────────────────────────────────────────
   Er steht auch OHNE Handlung als Raster da. Sonst sitzt der Titel der einen
   Karte gegen den der Nachbarin versetzt — die Quelle nennt 2 px als den
   gemessenen Fehler, gegen den `Panel.svelte` gebaut wurde. */
[data-bulung] .bul-karte-kopf {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2m);
  flex-wrap: wrap;
}

/* Titel und Unterzeile als Block, damit `space-between` oben sie GEMEINSAM
   von der Handlung trennt. `min-width: 0`: ohne das schiebt ein langer Titel
   die Handlung aus der Karte. */
[data-bulung] .bul-karte-worte {
  min-width: 0;
}

[data-bulung] .bul-karte-titel {
  margin: 0;
  /* 17 -> 15 px am 2026-09-23, zurueck auf 17 am 2026-09-27 („ruhiger
     Satz", HR-Portal): bei 15 zu 14 px Grundtext las sich der Titel wie
     eine halbfette Zeile, und die Seite hatte keine Stufe zwischen
     Seitentitel und Text. Der Seitentitel ist dafuer auf 28 gesunken. */
  font-size: var(--fs-app-h3);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-heading);
  color: var(--text);
}

[data-bulung] .bul-karte-unterzeile {
  margin: var(--space-xs) 0 0;
  font-size: var(--fs-app-caption);
  line-height: var(--lh-dense);
  /* 4,92 : 1 auf --fl-1 hell, 5,54 dunkel. ACHTUNG: auf der eingelassenen
     Flaeche --fl-well sind es nur 4,15 — wer die Karte dorthin legt, misst
     nach oder nimmt --text-secondary. */
  color: var(--text-muted);
}

/* Die Handlung schrumpft nicht. Ein Knopf, der sich unter einen langen Titel
   quetscht, bricht seinen Text um und wird hoeher als der Kopf. */
[data-bulung] .bul-karte-handlung {
  flex: none;
}

/* Der Inhalt nimmt den Rest. Ohne `flex: 1` sitzt eine Karte, die im Raster
   mit einer hoeheren Nachbarin gleich hoch gezogen wird, oben und laesst
   unten ein Loch. */
[data-bulung] .bul-karte-inhalt {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* ── bauteile/rail.css ───────────────────────────────────────────────── */
/* Bulung — Rail
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Quelle ist `bulung-at-dashboard/src/lib/components/Shell.svelte`
   (`.rail`, Zeile 461 ff.). Sie ist die durchgearbeitetste Navigation des
   Hauses und traegt an ihren eigenen Regeln die Begruendungen mit.

   DIE RAIL IST 232 PX (`--sidebar-w`). Beide Svelte-Apps stehen auf 256; 232
   gewinnt, weil bei 1280 px genau diese 24 px die Reserve sind, an der die
   Tabellen zuletzt dreimal gescheitert sind. Waechter G16 haelt fest, dass
   die Zahl im TOKEN steht und nicht in der Regel — sonst gibt es sie wieder
   zweimal.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (Shell.svelte), Zeile in Klammern:

     .rail (462-464)      `flex`, Spalte, Abstand zwischen den Bloecken
     .rail (470)          Polster 24/16 px. Die Quelle nennt an ihrer Regel
                          den Grund: mit 20/16 und einem negativen Rand von
                          −12 px klebte die aktive Flaeche links an der Kante.
     .rail (472)          `background: --fl-rail` — die Rail sitzt HINTER dem
                          Inhalt, nicht darueber
     .rail (473)          Haarlinie rechts
     .rail (475-479)      `position: sticky; top: 0; height: 100dvh;
                          overflow-y: auto; overscroll-behavior: contain`.
                          Das letzte ist das wichtigste: ohne `contain` rollt
                          die Seite weiter, sobald die Rail am Ende ist.
     nav (567-572)        Spalte mit Abstand, `flex: 1` — damit der Fuss
                          unten sitzt
     .gruppe h2           Gruppenueberschrift: klein, gesperrt, leise, KEINE
       (581-600)          Versalien. Die Quelle begruendet das ausfuehrlich
                          (574-580) — sie beschriftet Klickziele und muss
                          hinter ihnen zuruecktreten.
     .gruppe a (623-630)  Zeile als Raster aus fester Symbolspalte und Text.
                          Die feste Spalte ist der Punkt: sonst wandern die
                          Woerter der Ziele um zwei Pixel gegeneinander.
     .gruppe a (631)      `min-height: 36px` — die Trefferflaeche traegt die
                          Hoehe, nicht der Zeilenabstand
     .gruppe a:hover      Flaeche und volle Tinte
       (659-662)
     .gruppe a.aktiv      VIER redundante Signale, keins davon nur Farbe:
       (672-676,          Kante, hellere Flaeche, volle Tinte, halbfett.
        684-693)
     .fuss (700-704)      Haarlinie oben, Spalte, eigener Abstand

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Tinte aus --text,      Die Quelle nimmt durchgehend `--ink-on-dark` und
     nicht --ink-on-dark    `--ink-on-dark-muted` (Shell.svelte:474, 586,
                            635) — ihre Rail ist IMMER dunkel, auch wenn der
                            Inhalt daneben hell laeuft. Hier kippt `--fl-rail`
                            mit dem Register (hell #eef1f7, dunkel #070c20),
                            also muss die Tinte mitkippen. Gerechnet:
                            `--text` 16,96 : 1 hell und 15,52 dunkel,
                            `--text-secondary` 5,20 und 8,27.
     NICHT --text-muted     Der naheliegende Griff fuer die leisen Zeilen
                            traegt auf `--fl-rail` nur 4,35 : 1 und faellt
                            durch 1.4.3. Gerechnet, nicht geschaetzt.
     Balken --green-deep    Die Quelle nimmt `--green` (Shell.svelte:692).
                            Auf ihrer dunklen Rail traegt das 9,83 : 1 — auf
                            der HELLEN `--fl-rail` nur 1,74, der Balken waere
                            praktisch unsichtbar. `--green-deep` traegt
                            3,27 : 1 hell und 7,34 dunkel und ist damit in
                            beiden Registern ein Signal.
     Aktive Flaeche ist     `--fl-3` gegen `--fl-rail` sind 1,06 : 1 hell und
     KEIN Signal            1,28 dunkel. Die Flaeche gruppiert, sie zeigt
                            nichts — genau deshalb sind es vier Signale und
                            nicht eines. Die Zeile steht hier, damit niemand
                            drei davon wieder entfernt.
     KEINE Media Query      Die Quelle wird unter 901 px zum Off-Canvas-
                            Drawer und unter 900 px zur Mobilleiste
                            (Shell.svelte:774 ff. und 878 ff.). Wann eine
                            Rail verschwindet, entscheidet das Layout der
                            App; eine Media Query hier entschiede es fuer
                            alle vier auf einmal.
     `flex: none` an        Ohne das schrumpft eine 232-px-Rail in einem
     `.bul-rail`            Flex-Behaelter neben einem breiten Inhalt — die
                            Breite waere dann eine Bitte, keine Zusage.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .skip (434)              der Sprunglink. Er gehoert zur Seite, nicht zur
                              Rail, und seine Stapelstufe (60) ist gegen die
                              Mobilleiste dieser einen App eingestellt.
     .marke / .marke-logo     Logo und Signet mit ihren festen Hoehen
       (487, 498-518)         (22 px Wortmarke, 26 px Signet). Welche Marke
                              wie gross steht, ist Markenarbeit.
     .klappe (523)            der Einklapp-Umschalter samt `.rail.schmal` —
                              ein ganzer zweiter Zustand mit eigener Breite
                              (`--sidebar-w-schmal`), eigener Symbolspalte
                              und versteckten Beschriftungen (774-877).
     .schliessen              nur im Drawer sichtbar.
     .sprachmarke             die Sprachkennung — eine Auskunft dieser App.
     .konto / .monogramm      Kontozeile im Fuss (718-748). Sie zeigt einen
       / .wer / .abmelden     angemeldeten Benutzer; das System hat keinen.
     .ausbau                  Link auf den Projektstand.
     .mobilbar / .burger      die Mobilleiste (895 ff.).
   ========================================================================== */

/* DIE RAIL. Die Breite steht im Token und NUR dort — Waechter G16 haelt das
   fest. `flex: none`: ohne das schrumpft sie in einem Flex-Behaelter neben
   einem breiten Inhalt, und aus der Zusage wird eine Bitte. */
[data-bulung] .bul-rail {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  width: var(--sidebar-w);
  flex: none;
  padding: var(--space-lg) var(--space-md);
  /* Die Rail sitzt HINTER dem Inhalt, nicht darueber: dunkler als der Grund.
     `--fl-rail` nennt die Navigation woertlich als seinen Zweck und kippt mit
     dem Register (hell #eef1f7, dunkel #070c20). */
  background: var(--fl-rail);
  border-right: var(--border-width) solid var(--border);
  color: var(--text);
  position: sticky;
  /* ZWEI TOKEN MIT RUECKFALL, keine festen Werte.
     `height: 100dvh` und `top: 0` behaupten, die Rail beginne am oberen
     Rand des Fensters. Das gilt nur fuer Apps, deren Rail wirklich ganz
     oben sitzt. Das HR-Portal hat einen Markenbalken darueber — dort war
     die Rail damit 60 px hoeher als der Platz, den sie hat, und JEDE Seite
     rollte um genau diese 60 px, auch wenn ihr Inhalt hineinpasste
     (gemessen 2026-08-31 im Pilotdurchgang: scrollHeight 1327 gegen
     innerHeight 1267).
     Der Rueckfall ist der alte Wert — wer nichts setzt, merkt nichts. */
  top: var(--rail-oben, 0px);
  height: var(--rail-hoehe, 100dvh);
  overflow-y: auto;
  /* Ohne `contain` rollt die SEITE weiter, sobald die Rail an ihrem Ende
     angekommen ist — man scrollt in der Navigation und die Tabelle daneben
     wandert. */
  overscroll-behavior: contain;
}

/* Der Kopf der Rail: eine Zeile fester Hoehe mit Haarlinie darunter. Welche
   Marke darin steht und wie gross, gehoert der App. */
[data-bulung] .bul-rail-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  min-height: 28px;
  padding-bottom: var(--space-md);
  border-bottom: var(--border-width) solid var(--border);
}

/* Die Zielliste nimmt den Rest, damit der Fuss unten sitzt. */
[data-bulung] .bul-rail-ziele {
  display: flex;
  flex-direction: column;
  gap: var(--space-2l);  /* 16 → 24 px am 2026-09-23 (Gruppen sind Absaetze), 20 px seit 2026-09-27: die Rail war laenger als ein Laptopschirm */
  flex: 1;
}

/* Die Ueberschrift ORDNET, sie konkurriert nicht.
   SEIT 2026-09-25 IN VERSALIEN (Auftrag HR-Portal, „professionelleres
   Handling"). Vorher stand hier bewusst das Gegenteil: eine gesperrte
   Versalzeile sei so laut wie eine Ueberschrift. Das stimmt bei Groesse und
   voller Tinte — hier bleibt sie 11 px und leise (`--text-muted`), und die
   Versalien machen sie zur ETIKETTE statt zu einem weiteren Menuepunkt:
   neben den jetzt mittelschweren Zeilen war die kleine gemischte Schrift
   kaum als Gliederung zu lesen. */
[data-bulung] .bul-rail-gruppe {
  margin: 0 0 var(--space-xs);
  padding-left: var(--space-2m);
  font-size: var(--fs-app-micro);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-subhead);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Zeile = feste Symbolspalte + Text. Die Spalte ist FEST breit, damit die
   Beschriftungen aller Ziele auf einer Kante stehen — eine Rail, in der die
   Woerter um zwei Pixel wandern, liest sich sofort unsauber.
   `min-height` traegt die Trefferflaeche, nicht der Zeilenabstand. */
[data-bulung] .bul-rail-ziel {
  display: grid;
  grid-template-columns: var(--icon-md) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-sm);
  position: relative;
  padding: var(--space-2s) var(--space-2m);
  min-height: 36px;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--fs-app-body);
  /* 500 statt 400 seit 2026-09-25: Jost 400 auf der dunklen Rail las sich
     duenn und blass. */
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition:
    background var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard);
}
/* Hover ist LEISER als aktiv (`--fl-2` gegen `--fl-3`). Bis 2026-09-25 trugen
   beide dieselbe Flaeche — unter der Maus sah jeder Eintrag aus wie der, auf
   dem man steht. */
[data-bulung] .bul-rail-ziel:hover {
  background: var(--fl-2);
  color: var(--text);
}

/* ── Der aktive Eintrag: VIER Signale, keins davon nur Farbe ─────────────
   Die Flaeche allein sagt NICHTS: `--fl-3` gegen `--fl-rail` sind 1,06 : 1
   hell und 1,28 dunkel. Sie gruppiert, sie zeigt nicht. Deshalb kommen volle
   Tinte, halbfett und der Balken dazu — und deshalb darf keines der drei
   spaeter „aufgeraeumt" werden. Im Markup gehoert `aria-current` daneben. */
[data-bulung] .bul-rail-ziel--aktiv {
  background: var(--fl-3);
  color: var(--text);
  font-weight: var(--fw-semi);
}
/* Das Symbol des aktiven Eintrags in Gruen — das erste Kind ist die feste
   Symbolspalte. `--green-ink`: auf der hellen Rail die lesbare Tinte, auf
   der dunklen die Markenfarbe selbst (9,19 : 1). */
[data-bulung] .bul-rail-ziel--aktiv > :first-child {
  color: var(--green-ink);
}
/* Der Balken traegt `--green-deep`, nicht die Markenfarbe: `--green` auf der
   HELLEN Rail sind 1,74 : 1 — der Balken waere da und unsichtbar. Mit
   `--green-deep` sind es 3,27 hell und 7,34 dunkel. */
[data-bulung] .bul-rail-ziel--aktiv::before {
  content: "";
  position: absolute;
  left: 0;
  top: var(--space-2xs);
  bottom: var(--space-2xs);
  width: var(--border-row-accent);
  border-radius: 0 var(--border-accent-width) var(--border-accent-width) 0;
  background: var(--green-deep);
}

/* Der Fuss sitzt unten, weil `.bul-rail-ziele` den Rest genommen hat. */
[data-bulung] .bul-rail-fuss {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding-top: var(--space-2m);
  border-top: var(--border-width) solid var(--border);
}

/* ── bauteile/kopfleiste.css ─────────────────────────────────────────── */
/* Bulung — Kopfleiste
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Quelle ist `bulung-at-dashboard/src/lib/components/Seitenkopf.svelte`
   (`header`, Zeile 269 ff.) — das Band ueber dem Inhalt: links wo man ist,
   rechts was man hier tun kann.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (Seitenkopf.svelte), Zeile in Klammern:

     header (270-273)     `flex`, `space-between`, `align-items: flex-start`,
                          Abstand. Der Titel steht OBEN, nicht mittig: er darf
                          mehrzeilig werden, ohne die Handlung mitzuziehen.
     header (274)         mehr Polster oben als unten
     header (275)         Haarlinie nach unten
     header (276)         `background: --fl-well` — das eingelassene Band.
                          Der Token nennt den Seitenkopf woertlich als Zweck.
     header (277)         `flex-wrap: wrap` — die Handlung rutscht unter den
                          Titel, statt ihn zu kappen
     h1 (331-334)         kein Aussenabstand, gross, halbfett
     h1 (335-338)         der Titel ist selbst `flex`: er traegt oft ein
                          Abzeichen neben dem Wort, und das soll auf der
                          Grundlinie sitzen statt darunter
     .beschreibung        eine Zeile unter dem Titel, leiser, mit Lesebreite
       (371-374)

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Polster                Die Quelle nimmt `--pad-seite`, ein Token, das es
     --pad-container        im System nicht gibt. `--pad-container` (32 px)
                            ist der Wert des Hauses fuer ein Behaelterpolster.
     Titel --fs-app-h1      Die Quelle nimmt `--t-zahl`, ebenfalls kein Token
                            dieses Systems. 24 px ist die groesste Stufe der
                            Arbeitsflaechen-Skala.
     Lesebreite             Die Quelle deckelt die Unterzeile auf `62ch`. Hier
     --maxw-text            steht `--maxw-text` (72ch): der Token des Hauses
                            fuer eine Lesebreite. 62 gegen 72 ist eine
                            Feinheit dieser einen Seite, kein Systemwert.
     Unterzeile             Gerechnet: 4,97 : 1 hell und 8,15 dunkel auf
     --text-secondary       `--fl-well`. `--text-muted` traegt dort nur
                            4,15 : 1 und faellt durch 1.4.3 — auf der WEISSEN
                            Karte waere es in Ordnung, auf der eingelassenen
                            Bank nicht. Dieselbe Falle wie beim Tabellenkopf.
     KEINE Sperrung         Die Quelle setzt `letter-spacing: var(--ls-num)`
     am Titel               am `h1`. Das ist die Ziffernsperrung dieser App
                            fuer Kennzahlen; ein Seitentitel ist kein Wert.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .krumen (281-328)        Brotkrumen samt der Mobilfassung
                              (`.krume-mobil`, 336). Eine Navigationsform mit
                              eigener Regel, wann sie zur Zurueck-Zeile wird.
     .quelle (340-368)        die Mandantenpille im Titel (Kuerzel + Firma,
                              Firma faellt unter 639 px weg). Das ist die
                              Zweifirmen-Auskunft des AT-Dashboards.
     .reiter (381-410)        die Reiterzeile darunter. Sie ersetzt in dieser
                              App zwei Handbauten und liest ihren aktiven
                              Eintrag aus dem Pfad — Verhalten, kein Aussehen.
   ========================================================================== */

/* DAS BAND. `align-items: flex-start` und nicht `center`: der Titel darf
   mehrzeilig werden, ohne die Handlung nach unten mitzuziehen.
   `flex-wrap: wrap` laesst die Handlung unter den Titel rutschen, statt ihn
   zu kappen — eine gekappte Handlung ist eine, die niemand mehr findet. */
[data-bulung] .bul-kopfleiste {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-2m);
  flex-wrap: wrap;
  /* KEIN BAND MEHR, seit 2026-09-23. Die eingelassene Flaeche mit Kante
     teilte jede Seite in Kopf und Rest, bevor man etwas gelesen hatte. Der
     Titel steht jetzt auf dem Arbeitsgrund; der Abstand darunter trennt. */
  /* 24 -> 32 px am 2026-09-25, zurueck auf 24 am 2026-09-27 („ruhiger
     Satz"): der Titel gehoert zu seiner Seite und darf nicht so weit von
     ihr stehen wie zwei Abschnitte voneinander. */
  padding: 0 0 var(--space-lg);
  background: transparent;
  color: var(--text);
}

/* Titel und Unterzeile als Block, damit `space-between` sie gemeinsam von der
   Handlung trennt. */
[data-bulung] .bul-kopfleiste-worte {
  min-width: 0;
}

/* Der Titel ist selbst `flex`: er traegt oft ein Abzeichen neben dem Wort,
   und das soll auf der Grundlinie sitzen statt darunter. */
[data-bulung] .bul-kopfleiste-titel {
  margin: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-sm);
  font-size: var(--fs-app-h1);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-heading);
  color: var(--text);
}

/* `--text-secondary` und NICHT `--text-muted`: auf der eingelassenen
   `--fl-well` traegt `--text-muted` nur 4,15 : 1. Auf der weissen Karte waere
   es in Ordnung — hier nicht. Gerechnet: 4,97 hell, 8,15 dunkel. */
[data-bulung] .bul-kopfleiste-unterzeile {
  margin: var(--space-2s) 0 0;
  /* 15 -> 14 px seit 2026-09-27: die Unterzeile erklaert, sie ist keine
     zweite Ueberschrift. */
  font-size: var(--fs-app-body);
  line-height: var(--lh-dense);
  color: var(--text-secondary);
  max-width: var(--maxw-text);
}

/* Die Handlung schrumpft nicht. Sie rutscht lieber ganz unter den Titel —
   das erledigt `flex-wrap` an der Leiste. */
[data-bulung] .bul-kopfleiste-handlung {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* ── bauteile/modal.css ──────────────────────────────────────────────── */
/* Bulung — Modal
   ==========================================================================
   GEERNTET, NICHT KOPIERT.

   Quelle ist `bulung-at-dashboard/src/lib/ui/Bestaetigung.svelte`
   (Zeile 120 ff.) — das erste und einzige Modal der Landschaft, gebaut am
   24.08.2026 fuer die vier Arbeitsstand-Knoepfe von `/fatura`.

   ES IST EIN NATIVES `<dialog>`, geoeffnet mit `showModal()`. Drei Zusagen
   kommen damit VOM BROWSER statt aus Handarbeit:
     1. Escape schliesst.
     2. Der Tabulator verlaesst den Dialog nicht (Fokusfalle).
     3. Der Hintergrund ist nicht bedienbar (inert).
   Funktioniert eine davon nicht, wurde `show()` statt `showModal()` benutzt.
   Diese Datei kann das nicht erzwingen — sie kann es nur nicht kaputtmachen,
   und genau darum steht unten kein `display` am Dialog selbst.

   ---- ALLGEMEIN: kommt mit -------------------------------------------------
   Quelle (Bestaetigung.svelte), Zeile in Klammern:

     .bestaetigung        Der Dialog selbst traegt KEINE Flaeche und KEIN
       (121-126)          Polster: `border: 0; padding: 0; background:
                          transparent`, dazu Breitendeckel und `width: 100%`.
                          Die Quelle begruendet es an ihrer Regel — ein
                          Fenster, dessen Rahmen und dessen Inhalt dasselbe
                          Element sind, kann seinen Hintergrundklick nicht
                          vom Klick auf den Inhalt unterscheiden.
     ::backdrop (132-134) eigene Farbe. Der `::backdrop` ERBT NICHTS — ohne
                          diese Regel nimmt er den Wert des Browsers und ist
                          in beiden Registern derselbe Grauschleier.
     .karton (136-142)    die eigentliche Flaeche: Grund, Radius, Schatten,
                          Polster, Spalte mit Abstand
     .titel (145-149)     kein Aussenabstand, gross, halbfett
     .rumpf (152-154)     Spalte mit engerem Abstand
     .fuss (160-164)      `flex-wrap: wrap`, rechtsbuendig. Die Quelle nennt
                          den Grund: zwei Knopfbeschriftungen passen am
                          Telefon nicht in eine Zeile, und ein abgeschnittener
                          Knopf einer Rueckfrage ist die schlechteste denkbare
                          Stelle dafuer.

   ---- NEUENTSCHEIDUNGEN: steht in der Datei, ist aber NICHT geerbt ---------

     Radius --radius-lg     Die Quelle nimmt `--r-md`, denselben Radius wie
                            ihre Karten. `tokens/effects.css` haelt fuer
                            Ueberlagerungen und Modale eine eigene Stufe
                            bereit (16 px) und nennt sie woertlich so.
     Nur --shadow-over      Die Quelle legt zwei Schatten uebereinander
                            (`--ring`, `--schatten-over`). Der Ring ist dort
                            der Ersatz fuer eine Kante; hier traegt
                            `--shadow-over` allein — und im Dunkelregister
                            ist es ohnehin der EINZIGE Schatten, den
                            `tokens/effects.css` nicht auf `0 0 transparent`
                            setzt.
     KEIN --backdrop-blur   Der Token gibt es (`tokens/effects.css:35`), die
                            Quelle benutzt ihn nicht. Eine Weichzeichnung
                            hinter jedem Modal aller vier Apps waere eine
                            neue Entscheidung, nicht eine geerntete. Der
                            Token bleibt damit ohne Leser — als Befund
                            verzeichnet.
     Abbruchknopf           Die Quelle baut ihren `.abbruch` selbst
     ist kein Bauteil       (166-183). Hier steht dafuer
     des Modals             `.bul-knopf--leise` in `bauteile/knopf.css`; der
                            Fuss ordnet nur an.
     `--danger` Titel       Gibt es in der Quelle nicht. `--gefahr` am Modal
                            faerbt nur den TITEL, nicht die Flaeche: ein rot
                            hinterlegtes Fenster schreit, bevor man gelesen
                            hat, worum es geht.

   ---- FACHLICH: bleibt in der App ------------------------------------------
     .modal-icon              der Symbolkreis ueber dem Titel
       (order-portal:1713)    (order-portal/static/styles.css:1713). Ein
                              zweites Bauteil, das nur diese eine Rueckfrage
                              benutzt.
     @keyframes modalIn       die Einblendbewegung
       (order-portal:1701)    (`scale(0.92) translateY(8px)`). Eine
                              Entscheidung ueber Bewegung, die jede App fuer
                              sich treffen darf — und die einen eigenen
                              `prefers-reduced-motion`-Block braucht.
     Das Verhalten            Was der Dialog fragt, wann er sich oeffnet und
                              was ein Hintergrundklick tut, gehoert der App.
   ========================================================================== */

/* DER DIALOG SELBST: kein Rahmen, kein Polster, keine Flaeche.

   HIER STEHT KEIN `display`, und das ist der Kern. Ein geschlossenes
   `<dialog>` ist `display: none`; wer ihm hier `display: flex` gibt, macht
   ihn dauerhaft sichtbar — und zwar auch dann, wenn er nie geoeffnet wurde.
   Die Anordnung steht deshalb eine Ebene tiefer, an `.bul-modal-karton`.
   Dieselbe Trennung hat die Quelle aus einem zweiten Grund: ein Fenster,
   dessen Rahmen und dessen Inhalt dasselbe Element sind, kann seinen
   Hintergrundklick nicht vom Klick auf den Inhalt unterscheiden. */
[data-bulung] .bul-modal {
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--text);
  max-width: min(420px, calc(100vw - 2 * var(--space-md)));
  width: 100%;
}

/* Der `::backdrop` ERBT NICHTS. Er liegt in der Top-Layer und bekommt weder
   die Farben seines Elternelements noch die des Registers — ohne diese Regel
   nimmt er den Wert des Browsers und ist hell wie dunkel derselbe
   Grauschleier. `--backdrop` gibt es in beiden Registern (rgba navy 0.4 hell,
   schwarz 0.6 dunkel). */
[data-bulung] .bul-modal::backdrop {
  background: var(--backdrop);
}

/* DIE FLAECHE. `--fl-over` ist die Stufe fuer echte Ueberlagerungen, und
   `--shadow-over` der einzige Schatten, den das Dunkelregister nicht
   abschaltet — ein Modal muss auch dort ueber dem Rest schweben. */
[data-bulung] .bul-modal-karton {
  display: flex;
  flex-direction: column;
  gap: var(--space-2m);
  padding: var(--space-md);
  border-radius: var(--radius-lg);
  /* Haken fuer Glas, siehe karte.css. Das Modal nimmt die STARKE Glasstufe
     der App (`--menue-flaeche`): es liegt ueber Text. */
  background: var(--menue-flaeche, var(--fl-over));
  -webkit-backdrop-filter: var(--glas-filter, none);
  backdrop-filter: var(--glas-filter, none);
  box-shadow: var(--shadow-over);
}

[data-bulung] .bul-modal-titel {
  margin: 0;
  font-size: var(--fs-app-h3);
  font-weight: var(--fw-semi);
  line-height: var(--lh-heading);
  color: var(--text);
}

[data-bulung] .bul-modal-rumpf {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  color: var(--text-secondary);
}

/* Die Fussleiste BRICHT UM statt zu kappen. Zwei Knopfbeschriftungen passen
   am Telefon nicht immer in eine Zeile, und ein abgeschnittener Knopf einer
   Rueckfrage ist die schlechteste denkbare Stelle dafuer. */
[data-bulung] .bul-modal-fuss {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-sm);
  padding-top: var(--space-xs);
}

/* ── Zustand: Gefahr ─────────────────────────────────────────────────────
   Nur der TITEL wird rot, nicht die Flaeche. Ein rot hinterlegtes Fenster
   schreit, bevor man gelesen hat, worum es geht — und die eigentliche
   Warnung steht im Knopf (`.bul-knopf--gefahr`), nicht im Rahmen. */
[data-bulung] .bul-modal--gefahr .bul-modal-titel {
  color: var(--danger);
}

/* ── bauteile/menue.css ──────────────────────────────────────────────── */
/* Bulung — Menue
   ==========================================================================
   Ein kleines aufklappendes Menue: Zeilenaktionen, Kontomenue. EIN Bauteil
   fuer beide, damit sie gleich aussehen. Seit 2026-09-27.

   Das Menue ist eine LISTE VON LINKS UND KNOEPFEN, kein ARIA-`menu`: die
   Rolle `menu` verspricht Pfeiltasten-Bedienung, die ein <details> nicht
   hat. Tab und Enter reichen und sind ehrlich.

   Gefaehrliche Eintraege stehen unten, hinter einem Trenner, in Rot — die
   Farbe steht am TEXT, nicht an einer Flaeche.
   ========================================================================== */

[data-bulung] .bul-menue {
  min-width: 200px;
  padding: var(--space-xs);
  /* Haken fuer Glas, siehe karte.css. */
  background: var(--menue-flaeche, var(--surface));
  -webkit-backdrop-filter: var(--glas-filter, none);
  backdrop-filter: var(--glas-filter, none);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  z-index: var(--z-dropdown);
}

[data-bulung] .bul-menue-kopf {
  padding: var(--space-sm) var(--space-2m);
  font-size: var(--fs-app-caption);
  color: var(--text-muted);
}

[data-bulung] .bul-menue-eintrag {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  width: 100%;
  min-height: 36px;
  padding: 0 var(--space-2m);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-app-body);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
[data-bulung] .bul-menue-eintrag:hover,
[data-bulung] .bul-menue-eintrag:focus-visible {
  background: var(--fl-2);
}

[data-bulung] .bul-menue-eintrag--gefahr {
  color: var(--danger);
}
[data-bulung] .bul-menue-eintrag--gefahr:hover,
[data-bulung] .bul-menue-eintrag--gefahr:focus-visible {
  background: var(--status-error-bg);
  color: var(--danger-hover);
}

[data-bulung] .bul-menue-trenner {
  height: var(--border-width);
  margin: var(--space-xs) 0;
  background: var(--border);
  border: 0;
}

/* ── bauteile/diagramm.css ───────────────────────────────────────────── */
/* Bulung — Diagramm-Typografie
   ==========================================================================
   SEIT 2026-10-01 (HR-Portal, Ansage „bessere Typografie in allen
   Diagrammen"). Kein Diagramm, nur die SCHRIFT um ein Diagramm herum: die
   Legende, die Zahl am Balken, die Achse, die grosse Zahl in einem Ring.

   WARUM IM SYSTEM: das HR-Portal hatte drei Diagramme mit drei Legenden —
   Kreise am Ring, Quadrate an den Monatssaeulen, eigene Marken an der
   Arbeitszeit, je mit eigenem Abstand. Und die Zahl, um die es geht, stand
   in jedem Diagramm am leisesten (12 px, grau). Eine Regel an einer Stelle.

   DIE RANGFOLGE, laut nach leise:
     .bul-diagramm-hauptzahl   die EINE Zahl (Mitte eines Rings)   28 / 600
     .bul-diagramm-wert        die Zahl an einem Balken, in einer
                               Legende                              13 / 600
     .bul-diagramm-achse       Monat, Tag, Kategorie                12 / 500
     .bul-diagramm-einheit     „Tage", „Std.", „frei"               12 / 500
   Alle Ziffern mit fester Laufweite (`--num-tabular`): Werte untereinander
   stehen auf einer Kante.

   Die Legende ist IMMER da, sobald mehr als eine Reihe im Bild ist —
   Farbe allein traegt keine Bedeutung (WCAG 1.4.1). Die Marke ist ein
   kleines Quadrat mit weicher Ecke, an jedem Diagramm dieselbe.
   ========================================================================== */

[data-bulung] .bul-diagramm-hauptzahl {
  font-family: var(--font-num);
  font-variant-numeric: var(--num-tabular);
  font-size: var(--fs-app-kpi);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-tight);
  line-height: 1.1;
  color: var(--text);
}

[data-bulung] .bul-diagramm-wert {
  font-family: var(--font-num);
  font-variant-numeric: var(--num-tabular);
  font-size: var(--fs-meta);
  font-weight: var(--fw-semi);
  line-height: var(--lh-dense);
  color: var(--text);
}

[data-bulung] .bul-diagramm-achse {
  font-size: var(--fs-app-caption);
  font-weight: var(--fw-medium);
  line-height: var(--lh-dense);
  color: var(--text-secondary);
}
/* Die Stelle, an der man steht (heute, dieser Monat): Tinte statt Grau. */
[data-bulung] .bul-diagramm-achse--aktuell {
  color: var(--text);
  font-weight: var(--fw-semi);
}

[data-bulung] .bul-diagramm-einheit {
  font-size: var(--fs-app-caption);
  font-weight: var(--fw-medium);
  line-height: var(--lh-dense);
  color: var(--text-muted);
}

/* ── Legende ─────────────────────────────────────────────────────────── */

[data-bulung] .bul-legende {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm) var(--space-lg);
  font-size: var(--fs-app-caption);
  font-weight: var(--fw-medium);
  line-height: var(--lh-dense);
  color: var(--text-secondary);
}
[data-bulung] .bul-legende > li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2s);
}
/* Senkrecht, mit Wert rechts: die Legende NEBEN einem Ring. */
[data-bulung] .bul-legende--liste {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: var(--space-sm);
  font-size: var(--fs-app-body);
}
[data-bulung] .bul-legende--liste > li {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-sm);
}

/* Die Marke: 10 px, Ecke 3 px. Die Farbe kommt als `--marke` (Token-Name
   am Aufrufer, nie ein Wert — G5). */
[data-bulung] .bul-legende-marke {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: calc(var(--radius-xs) / 2);
  background: var(--marke, var(--text-muted));
}
/* Beantragt, noch nicht entschieden: schraffiert — erkennbar ohne Farbe. */
[data-bulung] .bul-legende-marke--schraffiert {
  background: repeating-linear-gradient(
    45deg,
    var(--marke, var(--text-muted)) 0 2px,
    var(--surface) 2px 4px
  );
  box-shadow: inset 0 0 0 var(--border-width) var(--marke, var(--text-muted));
}
/* Eine Bezugslinie (Soll, Ziel): gestrichelt statt Flaeche. */
[data-bulung] .bul-legende-marke--linie {
  width: 14px;
  height: 0;
  border-radius: 0;
  background: none;
  border-top: 2px dashed var(--marke, var(--text-muted));
}
