/* ══════════════════════════════════════════════════════════════════════════════
   VICORE · DESIGN SYSTEM (Victor CI)  —  EINZIGE QUELLE für Design-Tokens & Komponenten
   ──────────────────────────────────────────────────────────────────────────────
   UI-Refactor 2026-07-06. Diese Datei definiert die verbindliche Victor-Corporate-
   Identity (Farben, Typografie, Abstände, Radien, Schatten) und die kanonischen
   Komponenten. Sie wird als LETZTES Stylesheet geladen (nach allen Alt-Modul-CSS),
   damit ihre Token-Werte und Komponentendefinitionen die gewachsenen Stile
   überschreiben und die ganze App EINHEITLICH auf die Victor-CI umstellen.

   REGELN (siehe CLAUDE.md §UI-Regeln):
   • Keine Hex-Farben, keine rohen px-Abstände, keine font-size AUSSERHALB dieser Datei.
   • Ausschließlich Tokens (var(--…)) und die hier definierten Komponentenklassen nutzen.
   • EINE Schrift (Outfit) für alles — kein Serif; JetBrains Mono nur für Daten/IDs; Gold nur als Akzent.

   Der Legacy-Token-Layer weiter unten (»BRIDGE«) mappt alle gewachsenen Token-Namen
   (--vi-*, --brand-*, --color-*, --font-size-*, --table-*, --vitab-* …) auf die neue
   Victor-CI. Dadurch folgt die token-getriebene Bestands-App zentral, ohne dass
   irgendwo Farben/Fonts hart ersetzt werden müssen. Mandanten-Branding (branding.js)
   überschreibt die --brand-* weiterhin zur Laufzeit (Multi-Tenancy bleibt intakt).
   ══════════════════════════════════════════════════════════════════════════════ */

:root {
  /* ═══════════════ 0 · GERÄTE-SAFE-AREAS (22.08.2026) ═══════════════════════
     EINE zentrale Quelle für die Systembereiche des Geräts (Statusleiste,
     Cutout/Dynamic Island, Home-Indicator, Android-Gestenleiste, seitliche
     Insets im Querformat). Vorher stand `env(safe-area-inset-*)` verstreut in
     einzelnen Regeln — jede Stelle musste den Fallback selbst kennen, und ein
     vergessener Inset fiel erst auf dem Gerät auf.

     REGEL: Safe Area ist ÄUSSERER GERÄTESCHUTZ, kein zusätzliches Innenmaß.
     Sie gehört an die Kanten der App-Schale (Kopfzeile, Bottom-Navigation,
     Vollbildebenen) — NICHT an jede Karte, Liste oder Modulseite. Wer sie ein
     zweites Mal addiert, verschenkt Bildschirmhöhe.

     Auf Desktop und in Browsern ohne Cutout sind alle vier Werte 0 — die Tokens
     sind dort also wirkungslos und erzeugen keinen Abstand.
     Voraussetzung ist `viewport-fit=cover` im Viewport-Meta (public/index.html). */
  --app-safe-top: env(safe-area-inset-top, 0px);
  --app-safe-right: env(safe-area-inset-right, 0px);
  --app-safe-bottom: env(safe-area-inset-bottom, 0px);
  --app-safe-left: env(safe-area-inset-left, 0px);

  /* ═══════════════ 1 · FARBEN (VICore CI 2026 — genau diese) ═══════════════
     Neukalibrierung 16.08.2026 (Produkt-Redesign). Grundsätze:
       · EIN Grün als Marke und Orientierung — frisch statt Flaschengrün, aber
         gedeckt genug für stundenlange Arbeit. Es trägt: Navigation, aktiver
         Zustand, Primäraktion, Auswahl. Sonst nichts.
       · Hintergründe sind NEUTRAL und extrem dezent (kein Beige/Cream mehr):
         Arbeitsfläche = Weiß, Seitenfläche = fast weißes Neutral mit einem Hauch
         Grünstich, damit es zur Marke passt, ohne farbig zu wirken.
       · Statusfarben sind FUNKTIONAL und vom Markenakzent getrennt — eine Warnung
         darf nie aussehen wie ein Highlight (bisher beides Gold).
     Alle Kontraste gegen Weiß bzw. gegen die Navigationsfläche auf ≥4.5:1 geprüft.
     ─────────────────────────────────────────────────────────────────────────── */

  /* ── Marke: EINE grüne Rampe (alles Grün im Produkt kommt von hier) ── */
  --green-50:            #EDF7F2;
  --green-100:           #D8EEE3;
  --green-200:           #AFDCC6;
  --green-300:           #7CC3A2;
  --green-400:           #47A67D;
  --green-500:           #1F8A5F;   /* lebendiges VICore-Grün */
  --green-600:           #147352;   /* Primäraktion (Weiß darauf 5.8:1) */
  --green-700:           #0F5C42;   /* aktiv / Hover / Marken-Ink (7.9:1) */
  --green-800:           #0C4A36;
  --green-900:           #082F23;

  /* Kanonische Rollen (die App spricht in diesen Namen) */
  --color-forest:        var(--green-700);  /* Marken-Ink: Titel, aktive Zustände */
  --color-sage:          var(--green-600);  /* Aktion/Fokus/Links */
  --color-mint:          var(--green-400);  /* positive Akzente */
  --color-gold:          #C8A96E;           /* NUR „jetzt/heute" — max. ~5% Fläche */
  /* EIS-WEISS (17.08.2026). Die Seitenfläche lag bei #F4F6F5 — sichtbar grau.
     Dadurch traf der weiße aktive Navigationspunkt auf eine graue Fläche und die
     Verbindung zum Inhalt bekam eine harte Kante. Jetzt liegt die Seitenfläche
     dicht an Weiß; der aktive Punkt trägt EXAKT diesen Wert (--nav-active-bg),
     sodass er ohne sichtbaren Übergang in den Arbeitsbereich ausläuft.
     Karten bleiben trotzdem lesbar: sie sind reines Weiß MIT Rahmen. */
  --color-cream:         #F6F9F8;           /* Seitenfläche — Eis-Weiß, kein Grau */
  --color-surface:       #FFFFFF;           /* Arbeitsfläche: Tabellen, Karten, Dialoge */
  --color-canvas:        #F6F9F8;           /* gleicher Wert, ehrlicherer Name */
  --color-surface-sunken:#EDF1EF;           /* eingelassene Fläche (Segment-Spur, Zebra) */

  /* Abgeleitete Töne (Hover/weiche Flächen) — bleiben in der Rampe */
  --color-forest-hover:  var(--green-800);
  --color-forest-soft:   var(--green-50);
  --color-sage-hover:    var(--green-700);
  --color-sage-soft:     var(--green-50);   /* ruhige Markenfläche (aktive Chips) */
  --color-sage-tint:     var(--green-100);  /* eine Stufe kräftiger (Auswahl) */
  --color-mint-soft:     var(--green-50);
  --color-mint-ink:      var(--green-600);
  --color-gold-soft:     #F7EFDD;
  --color-gold-ink:      #8A6D28;           /* lesbares Gold auf Weiß (4.8:1) */

  /* ── Neutral — kühle, leicht grünstichige Skala (harmoniert mit der Rampe) ──
     Bewusst mehr Stufen als früher: Trennlinien in Flächen (200) und Rahmen von
     Bedienelementen (300) sind NICHT dieselbe Linie — genau daran erkennt man
     ruhige Oberflächen. */
  --gray-25:             #FBFDFC;
  --gray-50:             #F6F9F8;
  --gray-100:            #EDF1EF;   /* zarte Füllung, Zebra, Hover */
  --gray-200:            #E3E9E7;   /* Trennlinien INNERHALB einer Fläche */
  --gray-300:            #D8DFDC;   /* Rahmen von Feldern, Karten, Panels */
  --gray-400:            #A6B0AC;
  /* --gray-500 trägt ALLE Metadaten (Tabellenkopf, Zähler, Labels, Platzhalter).
     Gemessen gegen Weiß 5.6:1 und gegen die hellste Füllung (--gray-100) 4.9:1 —
     beides über AA. Ein hellerer Ton wirkt „eleganter" und ist bei 11–13 px genau
     die Grauzone, in der Verwaltungsdaten unlesbar werden. */
  --gray-500:            #5F6B66;
  --gray-600:            #4E5955;
  --gray-700:            #3A4441;   /* Sekundärtext (9.2:1) */
  --gray-800:            #263029;
  --gray-900:            #141A17;   /* Haupttext / Ink (16.9:1) */

  /* ── Semantisch — funktional, klar vom Markenakzent unterscheidbar ── */
  --color-success:       #1F8A5F;
  --color-success-soft:  #E4F2EB;
  --color-success-ink:   #12704B;
  --color-warning:       #C8880F;   /* Bernstein — NICHT mehr das Marken-Gold */
  --color-warning-soft:  #FBF0DA;
  --color-warning-ink:   #8A5B08;
  --color-danger:        #C0392C;
  --color-danger-soft:   #FBE8E5;
  --color-danger-ink:    #A32C22;
  --color-info:          #31708F;   /* ruhiges Blaugrau — nie Markengrün */
  --color-info-soft:     #E5EFF4;
  --color-info-ink:      #245C7A;
  --color-neutral-soft:  var(--gray-100);
  --color-neutral-ink:   var(--gray-700);

  /* ── Navigation als eigene Fläche (Ebene 1) ──────────────────────────────
     Die Hauptnavigation ist KEINE Karte auf der Seite, sondern eine eigene,
     durchgehende Fläche in der Markenfarbe. Der aktive Punkt ist weiß — das ist
     der einzige weiße Block in der Navigation und damit unverwechselbar. */
  /* 17.08.2026 eine Stufe dunkler (Nutzerwunsch): #0C6647 wirkte auf großer Fläche
     zu hell und ließ das Logo und die zweite Textebene verblassen. #0A5539 ist
     derselbe Ton, nur satter — alle Kontraste steigen dadurch:
     Weiß 8.9:1 (vorher 7.0) · Fließtext 7.0:1 (vorher 5.9) · Akzent 5.9:1 (vorher 4.6). */
  --nav-bg:              #0A5539;
  /* Kopf und Fuß lagen bis 17.08.2026 eine Tonstufe tiefer. Das erzeugte zwei
     waagerechte Kanten in einer Fläche, die als EINE gelesen werden soll — die
     Vorlage hat genau eine flache Farbe. Der Wert bleibt als Token bestehen
     (Mandanten-Branding kann ihn nutzen), zeigt aber standardmäßig auf --nav-bg. */
  --nav-bg-deep:         var(--nav-bg);
  --nav-line:            rgba(255,255,255,.13);
  --nav-text:            rgba(255,255,255,.86);
  --nav-text-strong:     #FFFFFF;
  --nav-text-muted:      rgba(255,255,255,.74);
  --nav-hover:           rgba(255,255,255,.10);
  --nav-active-bg:       var(--color-canvas);   /* exakt die Fläche, in die er ausläuft */
  --nav-active-ink:      var(--green-700);
  --nav-accent:          var(--green-200);   /* auf --nav-bg gemessen 4.6:1 */
  /* Markenfläche im Navigationskopf: Das Logo bekommt eine eigene helle Fläche, statt
     für den grünen Grund umgefärbt zu werden — nur so bleibt die Farbabstufung des
     Zeichens (graue Dächer, grüner Kern) erhalten. Reinweiß, damit die Marke exakt so
     steht wie in allen anderen Ausgaben (PDF, Login, Briefpapier). Mandanten-Branding
     kann den Wert überschreiben, wenn ein Logo einen anderen Grund braucht. */
  --nav-brand-plate:     #FFFFFF;

  /* ═══════════════ 2 · TYPOGRAFIE ═══════════════ */
  /* Nutzerwunsch 21.07.2026: EINE Schrift für ALLES, ausnahmslos → Inter.
     Kein Serif, kein separater Mono-Font mehr. Technische Daten (IDs, MaLo/MeLo,
     Stände, Beträge) bleiben über --font-mono ansprechbar, rendern aber ebenfalls
     Inter — Zahlen richten sich über font-variant-numeric: tabular-nums aus. */
  --font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; /* alles */
  --font-display: var(--font-body);                                                    /* = Inter */
  --font-mono:    var(--font-body);                                                    /* = Inter (tabular-nums für Datenausrichtung) */

  /* Größenskala (rem, 1rem = 16px).
     Neukalibriert 16.08.2026: die alten Werte (xl 28px, 2xl 40px) stammten aus einer
     Dokument-/Marketingskala. In einer Verwaltungssoftware steht ein 40px-Seitentitel
     über einer 13px-Tabelle — das ist der Bruch, den man als „Hero in der Verwaltung"
     sieht. Die Skala endet jetzt dort, wo Arbeitsflächen sie brauchen; große Zahlen
     regelt --kpi-size, nicht die Textskala. */
  --text-xxs:    0.6875rem; /* 11px — Zähler, Mikro-Label */
  --text-xs:     0.75rem;   /* 12px — Labels, Badges, Tabellenkopf */
  --text-sm:     0.8125rem; /* 13px — Metadaten, sekundäre Zeilen */
  --text-md:     0.875rem;  /* 14px — Standardgröße der Arbeitsfläche */
  --text-base:   0.9375rem; /* 15px — Fließtext, betonter Zeilenwert */
  --text-lg:     1.0625rem; /* 17px — Abschnitts-/Kartentitel */
  --text-xl:     1.375rem;  /* 22px — Seitentitel */
  --text-2xl:    1.75rem;   /* 28px — größter Titel (Detailkopf), große KPI */

  /* Gewichte / Zeilenhöhen */
  --fw-normal:   400;
  --fw-medium:   500;
  --fw-semibold: 600;
  --fw-bold:     700;
  --lh-tight:    1.2;
  --lh-snug:     1.35;
  --lh-normal:   1.5;

  /* ═══════════════ 3 · ABSTÄNDE (4er-Raster, abschließend) ═══════════════
     Genau diese neun Werte. Kein 13/17/23/29 px irgendwo im Projekt. */
  --space-0:     0px;
  --space-1:     4px;
  --space-2:     8px;
  --space-3:     12px;
  --space-4:     16px;
  --space-5:     24px;   /* Standard-Abstand zwischen Seitensektionen */
  --space-6:     32px;
  --space-7:     48px;
  --space-8:     64px;
  --section-gap: var(--space-5);   /* 24px — verbindlicher Sektionsabstand */
  --page-pad-x:  var(--space-6);   /* seitliche Ruhezone der Arbeitsfläche */
  --page-pad-y:  var(--space-5);

  /* ═══════════════ 4 · RADIUS / SCHATTEN / SONSTIGES ═══════════════
     Vier Radien, mehr nicht: Marke (Chip/Marke) · Bedienelement · Fläche · Overlay.
     Enger als bisher (10/16 → 8/12): große Radien lassen dichte Arbeitsflächen
     weich und „konsumig" wirken; 8/12 wirkt präzise. */
  --radius-sm:   6px;    /* Chips, Auswahlmarken, kleine Marker */
  --radius-md:   8px;    /* Buttons, Inputs, Selects, Zeilenaktionen */
  --radius-lg:   12px;   /* Karten, Panels, Tabellenrahmen */
  --radius-xl:   16px;   /* Modale, Drawer, große Overlays */
  --radius-pill: 999px;

  /* Schatten: sehr sparsam, EINE Lichtrichtung (von oben), nie farbig.
     Struktur soll aus Fläche und Abstand entstehen — nicht aus Schlagschatten. */
  --shadow-sm:   0 1px 2px rgba(16, 26, 22, 0.06);
  --shadow-md:   0 6px 16px -4px rgba(16, 26, 22, 0.10), 0 2px 4px rgba(16, 26, 22, 0.05);

  --content-max-width: 1520px;
  --transition:  150ms ease;
  --focus-ring:  0 0 0 3px rgba(20, 115, 82, 0.24);  /* Markengrün 24% */

  /* ═══════════════ 4a · MASSE DER ARBEITSOBERFLÄCHE ═══════════════════════
     UX-Konsolidierung Phase 1 (03.09.2026, docs/UX_UI_SYSTEM_CONCEPT.md §23.2).
     Bis hierher hatte jede Leiste, jedes Bedienelement und jede Zeile ihr eigenes
     Maß — gemessen 30/32/34/36/38/40/42/46 px nebeneinander. Diese Tokens sind die
     EINE Leiter dafür. Sie ERSETZEN keine bestehenden Werte über Nacht: der
     Altbestand zieht in Phase 9 nach, neue und migrierte Bausteine nehmen sie sofort.

     Bewusst NICHT hier: Statusfarben. Sie kommen mit StatusBadge/AttentionBadge in
     Phase 2 — ein Token ohne Renderer wäre eine Einladung, ihn falsch zu benutzen. */

  /* Bedienelemente — drei Größen, mehr nicht.
     sm = in Tabellenzeilen und Listenköpfen · md = Formulare, Filter, Werkzeugleisten
     · lg = Primäraktion im Seitenkopf und Dialogfuß. */
  --control-h-sm:  32px;
  --control-h-md:  36px;
  --control-h-lg:  40px;

  /* Tabellen- und Listenzeilen (TABLE_STANDARD §3.1).
     „Normal" muss ohne Umschalten funktionieren — es ist die Vorgabe. */
  --row-h-compact: 36px;
  --row-h-normal:  44px;
  --row-h-comfort: 56px;

  /* Waagerechte Leisten der Seitenschale (Konzept §11.1, Zonen R1–R5).
     Die Summe dieser vier plus Topbar ist das Budget bis zur ersten Datenzeile. */
  --bar-h-module:   44px;   /* R1 Modulkopf: „Modul › Fachbereich" + Primäraktion */
  --bar-h-tabs:     44px;   /* R2 Modultabs */
  --bar-h-tools:    40px;   /* R3/R4 Ansicht·Status und Filterleiste */
  --bar-h-listhead: 32px;   /* R5 Listenkopf: Anzahl · Export · Dichte · Spalten */

  /* Inhaltsbreiten. Listen laufen voll (Datendichte), Fließtext und Formulare nicht. */
  --content-max-detail: 1440px;   /* Akten (A3) — mehr wird als Textzeile unlesbar */
  --form-max:            640px;   /* Formularspalte in Dialogen und Masken */
  --workflow-max:        860px;   /* Schrittinhalt eines Workflows (A4) */

  /* Breakpoints als Tokens. CSS kann sie in @media noch nicht auswerten — sie sind
     die verbindliche Referenz für JS (matchMedia) und für jede neue Media-Query,
     damit die heute 73 verschiedenen Ausdrücke auf fünf zusammenlaufen. */
  --bp-sm:   767px;    /* darüber Desktopschale, darunter mobile Arbeitslogik */
  --bp-md:  1023px;    /* Tablet / kleiner Desktop */
  --bp-lg:  1279px;    /* Standard-Desktop — Split-Ansichten stapeln darunter */
  --bp-xl:  1599px;    /* großer Desktop */

  /* ════════════════════════════════════════════════════════════════════
     BRIDGE · Legacy-Tokens → Victor-CI  (damit die Bestands-CSS mitzieht)
     ════════════════════════════════════════════════════════════════════ */
  /* ── Mandanten-Branding-Layer (Default = VICore CI; branding.js überschreibt zur Laufzeit) ──
     --brand-primary ist die FARBE DER AKTION (Primärbutton), nicht die dunkelste
     Markenfarbe. Sie lag bisher auf dem Marken-Ink; Knopf und Überschrift hatten
     damit denselben Ton, und der Knopf gewann seine Wirkung nur über die Fläche. */
  --brand-primary:         var(--green-600);
  --brand-primary-hover:   var(--green-700);
  --brand-secondary:       var(--green-50);
  --brand-accent:          var(--green-600);
  --brand-bg-soft:         var(--green-50);
  --brand-text-on-primary: #FFFFFF;

  /* ── VICore-Kern-Neutrals / Marke ── */
  --vi-green:      var(--color-forest);
  --vi-green-deep: var(--color-sage);
  --vi-green-dark: var(--color-forest-hover);
  --vi-green-soft: var(--color-sage-soft);
  --vi-ink:        var(--gray-900);
  --vi-ink-70:     var(--gray-700);
  --vi-muted:      var(--gray-500);
  --vi-sand:       var(--gray-100);
  --vi-cream:      var(--color-cream);
  --vi-border:     var(--gray-300);
  --vi-roof-gray:  var(--gray-500);
  --vi-success:      var(--color-success-ink);
  --vi-success-soft: var(--color-success-soft);
  --vi-warning:      var(--color-warning-ink);
  --vi-warning-soft: var(--color-warning-soft);
  --vi-error:        var(--color-danger);
  --vi-error-soft:   var(--color-danger-soft);
  --vi-info:         var(--color-info);
  --vi-info-soft:    var(--color-info-soft);
  --vi-r-md:   var(--radius-md);
  --vi-r-lg:   var(--radius-lg);
  --vi-r-xl:   var(--radius-lg);
  --vi-r-pill: 999px;
  --vi-font-display: var(--font-body);   /* Bestands-„Display"-Nutzungen → Outfit (kein Serif) */
  --vi-font-ui:      var(--font-body);
  --vi-font-mono:    var(--font-mono);

  /* ── Legacy-Rampen: Primär (Grün → Forest/Sage) ── */
  --color-primary-50:    var(--color-forest-soft);
  --color-primary-100:   var(--color-sage-soft);
  --color-primary-200:   #C4D6C9;
  --color-primary-300:   #9BBBA5;
  --color-primary-400:   #6E9C7E;
  --color-primary-500:   var(--color-sage);
  --color-primary-600:   var(--color-forest);
  --color-primary-700:   var(--color-forest-hover);
  --color-primary-800:   #142418;
  --color-primary-900:   #0E1C14;

  /* ── Legacy „slate" → warme Neutrals ── */
  --color-slate-50:      var(--color-cream);
  --color-slate-100:     var(--gray-100);
  --color-slate-200:     var(--gray-300);
  --color-slate-300:     #D6CFC1;
  --color-slate-400:     var(--gray-500);
  --color-slate-500:     var(--gray-500);
  --color-slate-600:     var(--gray-700);
  --color-slate-700:     #423E37;
  --color-slate-800:     #302D27;
  --color-slate-900:     var(--gray-900);

  /* ── Legacy Grün-Rampe (Energie/Erfolg) → auf die EINE Marken-Rampe gemappt ── */
  --color-green-50:      var(--green-50);
  --color-green-100:     var(--green-100);
  --color-green-200:     var(--green-200);
  --color-green-300:     var(--green-300);
  --color-green-400:     var(--green-400);
  --color-green-500:     var(--green-500);
  --color-green-600:     var(--green-600);
  --color-green-700:     var(--green-700);
  --color-green-800:     var(--green-800);
  --color-green-900:     var(--green-900);

  /* ── Legacy Status ── */
  --color-red-500:       var(--color-danger);
  --color-red-600:       var(--color-danger-ink);
  --color-red-700:       #7A362B;
  --color-amber-500:     var(--color-warning);
  --color-amber-600:     var(--color-warning-ink);
  --color-blue-500:      var(--color-info);
  --color-blue-600:      var(--color-info-ink);

  /* ── Legacy Semantik-Aliase (weit genutzt) ── */
  --text-primary:        var(--gray-900);
  --text-secondary:      var(--gray-700);
  --text-muted:          var(--gray-500);
  --text-subtle:         var(--gray-500);
  --text-inverse:        #FFFFFF;
  --bg-primary:          var(--color-surface);
  --bg-secondary:        var(--gray-100);
  --bg-tertiary:         var(--gray-50);
  --border-default:      var(--gray-300);
  --border-color:        var(--gray-300);
  /* Zwei Linienstärken, bewusst getrennt: Rahmen um eine Fläche (border-color) und
     Trenner INNERHALB einer Fläche (border-subtle). Wer beides gleich zeichnet,
     bekommt das graue Excel-Raster zurück. */
  --border-subtle:       var(--gray-200);
  --border-light:        var(--gray-300);
  --border-strong:       var(--gray-400);
  --color-white:         #FFFFFF;
  /* Eingabefelder haben weißen Grund (nicht die Seitenfläche): ein Feld ist ein Ort,
     an dem man schreibt — es muss heller sein als das, worauf es liegt. */
  --bg-input:            #FFFFFF;
  --primary:             var(--color-forest);
  --accent:              var(--color-sage);

  /* ── Legacy Typo-Skala (--font-size-*) — 16.08.2026 auf EINE Leiter gezogen ──────
     Die gewachsene Skala begann bei 10 px (xs) und endete bei 32 px (6xl). Beides war
     falsch herum: 10-px-Beschriftungen sind an einem Arbeitsplatz-Bildschirm kaum zu
     lesen, während 28–32-px-Überschriften in einer Verwaltungsliste wie eine
     Marketingseite wirken. Das untere Ende steigt deshalb um genau 1 px, das obere
     sinkt — die Mitte (lg = 14 px = Grundtext) bleibt bewusst unangetastet, damit
     sich der geerbte Grundwert der ganzen App NICHT verschiebt. */
  --font-size-xs:        11px;   /* war 10 — kleinste Beschriftung, Badge */
  --font-size-sm:        12px;   /* war 11 — Formularlabel, Bildunterschrift */
  --font-size-base:      13px;   /* war 12 — Metadaten, sekundäre Zeile */
  --font-size-md:        14px;   /* war 13 */
  --font-size-lg:        14px;   /* unverändert — Grundtext, Navigationseintrag */
  --font-size-xl:        16px;   /* unverändert */
  --font-size-2xl:       17px;   /* war 18 — Abschnitts-/Kartentitel */
  --font-size-3xl:       19px;   /* war 20 */
  --font-size-4xl:       22px;   /* war 24 — Seitentitel */
  --font-size-5xl:       24px;   /* war 28 */
  --font-size-6xl:       28px;   /* war 32 — größter Titel im Produkt */

  --font-family-display: var(--font-body);
  --font-family-body:    var(--font-body);
  --font-family-mono:    var(--font-mono);

  /* ── Legacy Radius-Aliase (--radius-xl steht oben und bleibt 16px) ── */
  --radius-0:    0px;
  --radius-2xl:  var(--radius-xl);
  --radius-full: var(--radius-pill);

  /* ── Tabellenkopf / Tabs (zentral) ──────────────────────────────────────────
     Der Kopf war bisher eine dunkelgrüne Vollfläche mit weißen Versalien. Er war
     damit das kräftigste Element der Liste — kräftiger als die Daten, die er
     beschriftet. Ab jetzt: ruhige helle Fläche, gedämpfte Beschriftung, EINE feine
     Abschlusslinie. Die Aufmerksamkeit gehört den Zeilen. */
  --table-head-bg:      var(--gray-50);
  --table-head-color:   var(--gray-500);
  --table-head-line:    var(--gray-300);
  --table-row-hover:    var(--gray-100);
  --table-row-line:     var(--gray-200);
  --table-row-sel:      var(--green-50);
  --tab-active-bg:      var(--color-sage-soft);
  --tab-active-color:   var(--color-forest);
  --tab-inactive-color: var(--gray-500);
  --tab-hover-bg:       var(--gray-100);
  /* Tabs = „Ink-Underline" (22.07.2026, Nutzerwunsch): Pill-/Segment-Optik abgelöst.
     Transparente Spur mit feiner Basislinie; aktiver Tab = Forest-Schrift + einwachsender
     Unterstrich-Indikator (Struktur/Animation: ui-standard.css §3). */
  --vitab-track-bg:        transparent;
  --vitab-track-radius:    0;
  --vitab-track-pad:       0;
  --vitab-track-line:      var(--gray-200);      /* Basislinie der Spur */
  --vitab-gap:             2px;
  --vitab-radius:          var(--radius-md);     /* nur noch Hover-Fläche */
  --vitab-inactive-color:  var(--gray-500);
  --vitab-hover-bg:        var(--gray-100);
  --vitab-hover-color:     var(--gray-900);
  --vitab-active-bg:       transparent;
  /* Aktiver Tab: dunkle Schrift + grüner Indikator. Grüne SCHRIFT wäre die dritte
     grüne Ebene neben Navigation und Primäraktion — die Farbe soll zeigen WO man
     ist, der Text soll lesbar sein. */
  --vitab-active-color:    var(--gray-900);
  --vitab-active-shadow:   none;
  --vitab-ink:             var(--green-600);     /* Indikator-Farbe */
  --vitab-ink-h:           2px;                  /* Indikator-Dicke */
  --vitab-badge-bg:        var(--gray-100);
  --vitab-badge-color:     var(--gray-500);
  --vitab-badge-active-bg: var(--green-50);
  --vitab-badge-active-color: var(--green-700);
  --vitab-focus-ring:      var(--color-sage);

  /* ── Schatten-Aliase ── */
  --shadow-none:   none;
  --shadow-xs:     var(--shadow-sm);
  --shadow-lg:     0 16px 32px -8px rgba(16, 26, 22, 0.14), 0 4px 8px rgba(16, 26, 22, 0.05);
  --shadow-xl:     0 28px 56px -12px rgba(16, 26, 22, 0.18);
  --shadow-2xl:    0 40px 80px -16px rgba(16, 26, 22, 0.24);
  /* Overlays (Menü/Popover/Dropdown) — EIN Wert für alle schwebenden Flächen. */
  --shadow-pop:    0 10px 30px -8px rgba(16, 26, 22, 0.18), 0 2px 6px rgba(16, 26, 22, 0.06);
  /* KARTENSCHATTEN (Nutzerentscheidung 05.09.2026): „Die Boxen gerne modern mit
     leichtem Schatten." Das lockert die Regel „Flächen tragen keinen Schatten"
     für die Kartenfamilie (`.vic-cd`, `.vic-ch-i`) — und NUR für sie. Der Wert ist
     bewusst flach und fast farblos: er hebt die Karte einen Millimeter vom Grund,
     er lässt sie nicht schweben. Tabellen, Filterleisten und Panels bleiben flach;
     Menü, Dialog und Toast behalten ihre eigenen, kräftigeren Werte. EIN Wert für
     alle Karten — wer einen zweiten Schatten erfindet, bekommt die Kachelwand. */
  --shadow-card:   0 1px 2px rgba(16, 26, 22, 0.06), 0 6px 16px -6px rgba(16, 26, 22, 0.14);
  --shadow-card-hover: 0 2px 4px rgba(16, 26, 22, 0.07), 0 10px 24px -8px rgba(16, 26, 22, 0.20);

  /* ── Transition-Aliase ── */
  --transition-fast: var(--transition);
  --transition-base: 200ms ease;
  --transition-slow: 300ms ease;
  --transition-slower: 500ms ease;
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-in:     cubic-bezier(0.4, 0, 1, 1);
  --ease-out:    cubic-bezier(0, 0, 0.2, 1);

  /* ════════════════════════════════════════════════════════════════════
     ÜBERNOMMEN AUS `public/design-system.css` (Konsolidierung 16.08.2026)
     ────────────────────────────────────────────────────────────────────
     Bis hierher definierten ZWEI Dateien dieselben Tokens mit verschiedenen
     Werten (149 Doppeldefinitionen). Die alte Datei ist jetzt tokenfrei; die
     81 Tokens, die es nur dort gab, stehen ab sofort HIER — mit auf das neue
     System kalibrierten Werten. Es gibt damit genau EINEN Ort für Tokens.
     ════════════════════════════════════════════════════════════════════ */

  /* ── Legacy-Abstandsaliase (--spacing-*, 116× in style.css) → 4er-Raster ── */
  --spacing-xs:  var(--space-1);
  --spacing-sm:  var(--space-2);
  --spacing-md:  var(--space-3);
  --spacing-lg:  var(--space-4);
  --spacing-xl:  var(--space-5);
  --spacing-2xl: var(--space-5);
  --spacing-3xl: var(--space-6);
  --space-9:  36px;
  --space-10: var(--space-6);
  --space-12: var(--space-7);
  --space-16: var(--space-8);

  /* ── Medienfarben (Energie) — funktional, nicht dekorativ ── */
  --color-electricity: #31708F;   /* Strom  */
  --color-gas:         #C8880F;   /* Gas    */
  --color-water:       #2F8C9E;   /* Wasser */
  --color-heat:        #C0392C;   /* Wärme  */
  --color-solar:       #12704B;   /* PV     */

  /* ── Weitere Flächen-/Textrollen ── */
  --text-light:   var(--gray-400);
  --color-black:  #000000;
  --bg-overlay:   rgba(12, 20, 17, 0.42);
  --bg-disabled:  var(--gray-100);
  --bg-hover:     var(--gray-100);
  --bg-active:    var(--green-50);
  --bg-alt:       var(--gray-50);

  /* ── Gewichte, Zeilenhöhen, Laufweiten (Legacy-Namen der Typo-Schicht) ── */
  --font-weight-light:    300;
  --font-weight-normal:   var(--fw-normal);
  --font-weight-medium:   var(--fw-medium);
  --font-weight-semibold: var(--fw-semibold);
  --font-weight-bold:     var(--fw-bold);
  --line-height-tight:   var(--lh-tight);
  --line-height-snug:    var(--lh-snug);
  --line-height-normal:  var(--lh-normal);
  --line-height-relaxed: 1.625;
  --line-height-loose:   1.75;
  --letter-spacing-tight:  -0.01em;
  --letter-spacing-normal: 0em;
  --letter-spacing-wide:   0.02em;

  /* ── Maße der Bedienelemente — EINE LEITER, app-weit (UX-Phase 9 §6) ──────
     Bis zum 03.09.2026 liefen hier ZWEI Leitern nebeneinander: die Phase-1-Leiter
     `--control-h-sm/md/lg` (32/36/40) und diese gewachsene (30/38/44 + 38 + 42).
     Ergebnis waren sechs Bedienelement-Höhen auf EINER Seite. Die gewachsenen
     Namen bleiben — sie stehen in rund hundert Regeln —, sie ZEIGEN aber jetzt
     auf die Leiter:
        sm 32  Chips, kleine Knöpfe in Zeilen
        md 36  Formularfelder und ihre Knöpfe
        lg 40  Filter-/Suchleisten, Tabs
     Wer eine Höhe ändern will, ändert `--control-h-*` — nicht sein Modul. */
  --btn-height-sm:   var(--control-h-sm);
  --btn-height-md:   var(--control-h-md);
  --btn-height-lg:   var(--control-h-lg);
  --btn-padding-x-sm: var(--space-3);
  --btn-padding-x-md: var(--space-4);
  --btn-padding-x-lg: var(--space-5);
  --input-height:     var(--control-h-md);
  --input-padding-x:  var(--space-3);
  --input-padding-y:  var(--space-2);

  /* ── SUCHFELD (Primitive `.vi-search`) — EINE Definition für die ganze Anwendung ──
     Module ändern hiervon NICHTS. Wer ein Suchfeld anders aussehen lassen will,
     ändert diese Tokens — nicht sein Modul-CSS. */
  --search-height:       var(--control-h-lg);   /* Standardhöhe (Filter-/Suchleiste) */
  --search-height-sm:    var(--control-h-sm);   /* in Dropdowns/Comboboxen/Command-Menüs */
  --search-radius:       var(--radius-md);
  --search-bg:           var(--color-surface);
  --search-bg-disabled:  var(--gray-100);
  --search-border:       var(--gray-300);
  --search-border-hover: var(--gray-400);
  --search-border-focus: var(--green-600);
  --search-border-error: var(--color-danger, #A32B22);
  --search-ink:          var(--gray-900);
  --search-placeholder:  var(--gray-500);
  --search-icon:         var(--gray-500);
  --search-icon-size:    17px;
  --search-font:         var(--text-md);       /* 14px */
  --search-pad-x:        var(--space-3);       /* 12px links/rechts */
  --search-gap:          9px;                  /* Abstand Lupe → Text */
  --search-ring:         var(--focus-ring);
  --icon-size-xs: 16px;
  --icon-size-sm: 20px;
  --icon-size-md: 24px;
  --icon-size-lg: 32px;
  --icon-size-xl: 48px;

  /* ── Tabellen-/Tab-Maße ── */
  --table-head-size:    var(--text-xs);
  --table-head-spacing: normal;   /* Satzschreibung braucht keine Sperrung (Block 3, 10.1) */
  --table-cell-pad:     10px var(--space-4);
  --table-radius:       var(--radius-lg);
  --tab-radius:         var(--radius-md) var(--radius-md) 0 0;
  --vitab-h:            40px;
  --vitab-h-secondary:  34px;
  --vitab-h-compact:    30px;
  --vitab-pad-x:           var(--space-3);
  --vitab-pad-x-secondary: 11px;
  --vitab-pad-x-compact:   10px;
  --vitab-font:           var(--text-md);
  --vitab-font-secondary: var(--text-sm);
  --vitab-font-compact:   var(--text-sm);
  --vitab-icon-size: 16px;

  /* ── Schalenmaße ── */
  --sidebar-width:        272px;
  --sidebar-width-sm:     200px;
  --sidebar-width-tablet: 180px;
  --topbar-height:        56px;

  /* ── Ebenen ── */
  --z-base: 0;
  --z-sticky: 10;
  --z-dropdown: 100;
  --z-modal-bg: 1000;
  --z-modal: 1001;
  --z-tooltip: 1002;
  --z-notification: 1003;

  /* ════════════════════════════════════════════════════════════════════
     ÜBERNOMMEN AUS `public/style.css` (Konsolidierung 16.08.2026)
     ────────────────────────────────────────────────────────────────────
     style.css begann mit einem eigenen 105-Token-Block, der sich selbst als
     „die EINZIGE Quelle für Marken-, Neutral-, Status- und Energiefarben,
     Schrift, Radius und Schatten" bezeichnete — 65 dieser Tokens hatte die
     kanonische Datei ebenfalls, mit teils anderen Werten (z. B. --radius-lg
     10px hier gegen 12px dort). Das war die dritte Parallelwelt.
     Der Block ist entfernt; die 40 Tokens, die es nur dort gab, stehen hier.
     ════════════════════════════════════════════════════════════════════ */

  /* Fachfarben Energie (Medien, PV-Flüsse, Effizienzklassen) — funktional. */
  --vi-green-tint:        var(--green-50);
  --vi-pv-produktion:     var(--color-solar);
  --vi-pv-eigenverbrauch: var(--green-600);
  --vi-pv-einspeisung:    var(--color-gas);
  --vi-pv-zukauf:         var(--color-electricity);
  --vi-eff-aplus: #1F8A4C;  --vi-eff-a: #12704B;  --vi-eff-b: #7CB342;
  --vi-eff-c:     #AFC53A;  --vi-eff-d: #E8C223;  --vi-eff-e: #F0A93B;
  --vi-eff-f:     #E8772E;  --vi-eff-g: #D85A2A;  --vi-eff-h: #C0392C;
  --vi-shadow-card:   var(--shadow-sm);
  --vi-shadow-raised: var(--shadow-md);

  /* Deutschsprachige Legacy-Aliase (breit in style.css genutzt). */
  --bg-app:       var(--color-canvas);
  --bg-card:      var(--color-surface);
  --gruen:        var(--brand-primary);
  --gruen-mid:    var(--brand-primary-hover);
  --gruen-hell:   var(--brand-primary);
  --gruen-glow:   var(--brand-primary);
  --gruen-trace:  rgba(20, 115, 82, 0.07);
  --creme:        var(--color-canvas);
  --creme-dunkel: var(--gray-200);
  --sand:         var(--gray-500);
  --c-strom:  var(--color-electricity);
  --c-gas:    var(--color-gas);
  --c-wasser: var(--color-water);
  --c-waerme: var(--color-heat);
  --c-pv:     var(--color-solar);
  --rot:       var(--color-danger);
  --gelb:      var(--color-warning-ink);
  --gruen-ok:  var(--color-success-ink);
  --text:   var(--gray-900);
  --muted:  var(--gray-500);
  --subtle: var(--gray-500);
  --white:  #FFFFFF;
  --border: var(--gray-300);
}

/* ══════════════════════════════════════════════════════════════════════════════
   BASIS-STILE
   ══════════════════════════════════════════════════════════════════════════════ */
body {
  background: var(--color-cream);
  color: var(--gray-900);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Überschriften & große KPI-Zahlen: EINE Schrift, EIN Gewicht, DUNKLE Typografie.
   Neu 16.08.2026: Überschriften stehen in Ink (--gray-900), nicht mehr in Markengrün.
   Grün ist die Farbe der Orientierung (Navigation, aktiver Zustand, Primäraktion) —
   wenn zusätzlich jede Überschrift grün ist, verliert der Akzent seine Bedeutung und
   die Seite wirkt eingefärbt statt geordnet.
   font-variant-numeric: lining/tabular → gleich hohe, spaltengerechte Ziffern. */
h1,
.ds-page-title,
.ds-page-header__title,
.kpi-value,
.ds-kpi__value,
.ckpi-value,
.stat-value,
.stat-number,
.hp-kpi-value,
.hp-stat-value,
.vi-prio-n,
.dq-score-num,
.energy-kpi-value {
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.015em;
  line-height: var(--lh-tight);
  color: var(--gray-900);
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* Daten (früher Monospace) — jetzt Inter mit tabular-nums für spaltengerechte Zahlen */
.mono, .ds-mono, .ds-id, .ds-amount { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Inter ausnahmslos (Nutzerwunsch 21.07.2026): niedrig-spezifischer Sockel, damit
   Form-Controls und Code/Pre NIE auf einen UA-Default (Arial/monospace) zurückfallen.
   Klassenregeln überschreiben dies weiterhin — sie sind aber ebenfalls Inter. */
button, input, select, textarea, optgroup { font-family: var(--font-body); }
code, kbd, samp, pre, tt { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ── KENNZAHLEN / GROSSE ZAHLEN — EINE verbindliche Darstellung ───────────────────
   Nutzerwunsch 22.07.2026 („Warum sehen manche Zahlen anders aus als andere?"):
   Große Zahlen liefen app-weit mit unterschiedlichen Gewichten (300 / 600 / 700) und
   Tracking nebeneinander — im Cockpit z. B. „Jetzt wichtig" 30px/300 (dünn) direkt über
   „Überblick" 25px/600 (fett). Diese Schicht lädt ZULETZT und ist die Single Source:
   Schrift, Gewicht, Tracking, Ziffernform und Zeilenhöhe sind ab hier überall gleich.
   Bewusst NICHT gesetzt: Farbe (Ampel/Severity je Kontext) und — außer im Cockpit —
   die Größe (bleibt pro Kontext bzw. responsiv steuerbar).
   Neue Kennzahl-Klassen hier eintragen, NICHT eigene Zahlen-Typografie erfinden. */
:root {
  --kpi-weight:   var(--fw-semibold);   /* 600 — Kanon für Überschriften & Kennzahlen */
  --kpi-tracking: -0.02em;
  --kpi-size:     28px;                 /* Cockpit: beide Kennzahlen-Blöcke gleich groß */
}
.ds-kpi__value,
.ckpi-value,
.ck-mine-c-num,
.vi-kpi, .vi-kpi__value,
.cf-kpi-n,
.cck-rech-n,
.ph-kpi-v, .ph-sum-v {
  font-family: var(--font-body);
  font-weight: var(--kpi-weight);
  letter-spacing: var(--kpi-tracking);
  line-height: 1.1;
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: "lnum" 1, "tnum" 1;
}
/* Cockpit: „Jetzt wichtig" und „Überblick" stehen direkt untereinander → identische Größe. */
.ck-mine-c-num, .ckpi-value { font-size: var(--kpi-size); }
@media (max-width: 640px) { :root { --kpi-size: 32px; } }  /* mobil größer, da Kacheln stapeln */

a { color: var(--color-sage); }
a:hover { color: var(--color-sage-hover); }

::selection { background: var(--color-sage-soft); color: var(--color-forest); }

:focus-visible {
  outline: 2px solid transparent;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

/* ══════════════════════════════════════════════════════════════════════════════
   GLOBALER RAHMEN · Sidebar in Forest (helle Schrift), Inhalt zentriert auf Cream
   ══════════════════════════════════════════════════════════════════════════════ */
/* Forest-Sidebar für JEDEN Theme-Zustand (light/dark-Toggle) — Attribut-Selektoren
   matchen die Spezifität der bestehenden .sidebar[data-theme="…"]-Regeln und gewinnen
   durch die spätere Ladereihenfolge. Spec: „Sidebar Forest mit heller Schrift". */
.sidebar,
.sidebar[data-theme="light"],
.sidebar[data-theme="dark"] {
  --sb-bg:        var(--nav-bg);
  --sb-border:    var(--nav-line);
  --sb-text:      var(--nav-text);
  --sb-muted:     var(--nav-text-muted);
  --sb-faint:     var(--nav-text-muted);
  --sb-hover:     var(--nav-hover);
  --sb-active-bg: var(--nav-active-bg);
  --sb-active-text: var(--nav-active-ink);
  --sb-accent:    var(--nav-accent);
  --sb-rail:      var(--nav-line);
  --sb-on-accent: var(--nav-active-ink);
}

/* ══════════════════════════════════════════════════════════════════════════════
   KOMPONENTEN · EINE Definition pro Komponente
   ──────────────────────────────────────────────────────────────────────────────
   WICHTIG: Diese Kanon-Komponenten sind bewusst `.ds-…`-NAMESPACED. Die gewachsene
   App nutzt gleichnamige Klassen (`.btn`,`.card`,`.modal`,`.table`,`.badge`,`.page-header`)
   mit EIGENER Struktur — insbesondere ist die App-`.modal` das DIALOG-Feld selbst
   (nicht der Overlay-Container). Würden wir diese Namen hart überschreiben, zerlegte
   das die Bestands-Layouts (z. B. alle Detail-Pop-ups). Daher: die App-Komponenten
   werden ausschließlich über die TOKEN-Schicht (oben) re-thematisiert, und NEUE
   Seiten/Markup nutzen die kanonischen `.ds-…`-Komponenten. Der Styleguide zeigt sie.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── BUTTON ── Höhe 40px · .ds-btn-sm 32px · genau 4 Optiken ── */
.ds-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--ui-btn-h, 38px); padding: 0 var(--space-4);
  font-family: var(--font-body); font-size: var(--text-md); font-weight: var(--fw-semibold);
  line-height: 1; white-space: nowrap; overflow-wrap: anywhere;
  border: 1px solid transparent; border-radius: var(--radius-md);
  cursor: pointer; text-decoration: none; user-select: none;
  transition: background var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);
}
.ds-btn:disabled, .ds-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.ds-btn:focus-visible { box-shadow: var(--focus-ring); outline: none; }

.ds-btn-primary   { background: var(--green-600); color: #FFFFFF; }
.ds-btn-primary:hover:not(:disabled)   { background: var(--green-700); }

/* Sekundär = neutrale Umrandung, nicht grün. Grün bleibt der EINEN Aktion je Seite
   vorbehalten; zwei grüne Knöpfe nebeneinander heben sich gegenseitig auf. */
.ds-btn-secondary { background: var(--color-surface); color: var(--gray-700); border-color: var(--gray-300); }
.ds-btn-secondary:hover:not(:disabled) { background: var(--gray-50); color: var(--gray-900); border-color: var(--gray-400); }

.ds-btn-ghost     { background: transparent; color: var(--gray-700); }
.ds-btn-ghost:hover:not(:disabled)     { background: var(--gray-100); color: var(--gray-900); }

.ds-btn-danger    { background: var(--color-danger); color: #FFFFFF; }
.ds-btn-danger:hover:not(:disabled)    { background: var(--color-danger-ink); }

.ds-btn-sm { height: var(--ui-btn-sm-h, 30px); padding: 0 var(--space-3); font-size: var(--text-sm); }

/* ── CARD ── weiß, radius-lg, KEIN Schatten im Normalfall ──────────────────────
   Eine Karte ist eine SEMANTISCHE GRUPPE, keine Dekoration. Sie trägt deshalb den
   leisesten Rahmen, der die Fläche gerade noch abgrenzt — und keinen Schatten:
   auf einer fast weißen Seitenfläche liegen sonst dutzende schwebende Rechtecke
   übereinander. Schatten bleibt den Dingen vorbehalten, die wirklich schweben
   (Menü, Dialog, Drawer). Karten in Karten sind ausdrücklich nicht vorgesehen. */
.ds-card {
  background: var(--color-surface);
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.ds-card__header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); }
.ds-card__title  { font-size: var(--text-lg); font-weight: var(--fw-semibold); color: var(--gray-900); letter-spacing: -0.01em; }
.ds-card__body   { color: var(--gray-900); }
/* Eine Karte in einer Karte verliert ihren Rahmen — sie ist dann nur noch eine
   Gruppe, kein zweites Blatt Papier. Fängt das „Card in Card in Card" strukturell ab. */
.ds-card .ds-card { border: 0; border-radius: 0; padding: 0; background: none; }

/* ── MODAL ── feste Breiten · Header/Body/Footer · Buttons rechts (Abbrechen links) ── */
.ds-modal { position: fixed; inset: 0; z-index: 1001; display: flex; align-items: center; justify-content: center; padding: var(--space-4); }
.ds-modal__backdrop { position: fixed; inset: 0; background: rgba(12, 20, 17, 0.42); }
.ds-modal__dialog {
  position: relative; z-index: 1; display: flex; flex-direction: column;
  width: 100%; max-height: calc(100vh - var(--space-7));
  background: var(--color-surface); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl);
  overflow: hidden;
}
.ds-modal-sm .ds-modal__dialog { max-width: 420px; }
.ds-modal-md .ds-modal__dialog { max-width: 640px; }
.ds-modal-lg .ds-modal__dialog { max-width: 960px; }
.ds-modal__header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border-subtle); }
.ds-modal__title  { font-size: var(--text-lg); font-weight: var(--fw-semibold); color: var(--gray-900); }
.ds-modal__close  { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; background: transparent; color: var(--gray-500); border-radius: var(--radius-md); cursor: pointer; }
.ds-modal__close:hover { background: var(--gray-100); color: var(--gray-900); }
.ds-modal__body   { padding: var(--space-5); overflow-y: auto; }
.ds-modal__footer { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border-subtle); background: var(--gray-25); }

/* ── TABLE ── EINE Optik · heller Kopf · KEINE senkrechten Linien ─────────────
   Struktur entsteht durch Zeilenhöhe, Ausrichtung und Typografie — nicht durch ein
   Raster. Deshalb: nur waagerechte Trenner, und die in der leisesten Linienstärke. */
.ds-table { width: 100%; border-collapse: collapse; font-size: var(--text-md); }
.ds-table thead th {
  text-align: left; padding: var(--space-3) var(--space-3);
  font-family: var(--font-body); font-size: var(--text-xs); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--table-head-color);
  background: var(--table-head-bg); border-bottom: 1px solid var(--table-head-line); white-space: nowrap;
}
.ds-table tbody td { padding: var(--space-3) var(--space-3); border-bottom: 1px solid var(--table-row-line); color: var(--gray-900); vertical-align: middle; }
.ds-table tbody tr:hover { background: var(--table-row-hover); }
.ds-table tbody tr[aria-selected="true"] > td { background: var(--table-row-sel); }
.ds-table .num, .ds-table [data-num] { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ── FORM FIELD ── Label über dem Feld · Input 40px · Fokus Sage ── */
.ds-form-field { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-4); }
.ds-form-field > label { font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--fw-medium); color: var(--gray-700); }
.ds-form-field input:not([type=checkbox]):not([type=radio]),
.ds-form-field select,
.ds-form-field textarea {
  min-height: 40px; padding: var(--space-2) var(--space-3);
  font-family: var(--font-body); font-size: var(--text-sm); color: var(--gray-900);
  background: var(--color-surface); border: 1px solid var(--gray-300); border-radius: var(--radius-md);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.ds-form-field textarea { min-height: 96px; resize: vertical; }
.ds-form-field input:focus, .ds-form-field select:focus, .ds-form-field textarea:focus { outline: none; border-color: var(--color-sage); box-shadow: var(--focus-ring); }
.ds-form-field .ds-form-hint { font-size: var(--text-xs); color: var(--gray-500); }

/* ══════════════════════════════════════════════════════════════════════════════
   SUCHFELD — `.vi-search` · EIN Control · EIN Rahmen · EIN Fokuszustand
   ------------------------------------------------------------------------------
   Verbindlich für ALLE regulären Suchfelder (Listen, Tabellen, Toolbars, Dialoge).
   Markup erzeugt ausschließlich `public/vi-search.js` (VISearch/VISearchField).

   Warum genau so:
   • Der Rahmen gehört dem WRAPPER. Das <input> ist rahmenlos und transparent — sonst
     entsteht der bis 16.08.2026 sichtbare „Rahmen im Rahmen".
   • KEIN schwebendes Label im Rahmen. Ein Suchfeld ist durch Lupe + Placeholder
     eindeutig; die Beschriftung für Screenreader trägt `aria-label`.
   • Der Fokus ändert NUR Farbe und Ring — Höhe, Breite und Position bleiben in JEDEM
     Zustand identisch (default → hover → focus → typing → blur), deshalb wird die
     Rahmenstärke nie verändert und der Ring liegt als `box-shadow` außen an.
   • Browser-Eigenheiten werden kontrolliert abgeschaltet (WebKit-Such-Dekoration,
     native Outline, Autofill-Gelb) und durch einen eigenen `:focus-visible` ersetzt.
   ══════════════════════════════════════════════════════════════════════════════ */
.vi-search {
  position: relative;
  display: flex; align-items: center; gap: var(--search-gap);
  box-sizing: border-box;
  height: var(--search-height);
  min-width: 0;
  padding: 0 var(--search-pad-x);
  background: var(--search-bg);
  border: 1px solid var(--search-border);
  border-radius: var(--search-radius);
  color: var(--search-ink);
  /* Nur Farben animieren — nie Maße. So gibt es keinen Layoutsprung. */
  transition: border-color var(--transition, 150ms ease),
              box-shadow  var(--transition, 150ms ease),
              background  var(--transition, 150ms ease);
}
.vi-search--sm { height: var(--search-height-sm); --search-icon-size: 15px; --search-pad-x: 10px; --search-gap: 7px; }

.vi-search:hover:not(.is-disabled) { border-color: var(--search-border-hover); }
/* GENAU EIN Fokuszustand — am Wrapper, nicht zusätzlich am Input. */
.vi-search:focus-within {
  border-color: var(--search-border-focus);
  box-shadow: var(--search-ring);
}
.vi-search.is-disabled { background: var(--search-bg-disabled); border-color: var(--search-border); opacity: .7; cursor: not-allowed; }
.vi-search.has-error { border-color: var(--search-border-error); }
.vi-search.has-error:focus-within { box-shadow: 0 0 0 3px rgba(163, 43, 34, .18); }
/* Gefüllt = KEINE optische Sonderbehandlung. Der Text im Feld ist die Aussage; ein
   zweiter Farbzustand würde mit „gesetzter Filter" verwechselt. */

.vi-search__ic {
  flex: 0 0 auto;
  width: var(--search-icon-size); height: var(--search-icon-size);
  color: var(--search-icon);
  pointer-events: none;
}

.vi-search__input {
  flex: 1 1 auto; min-width: 0; width: 100%;
  /* Höhe explizit: die generische Regel `input, select { height: var(--input-height) }`
     würde das Feld sonst auf 38 px aufblasen und die Zeile sprengen (Fehlerbild bis
     16.08.2026: das Suchfeld war höher als sein eigener Rahmen). */
  height: 100%;
  margin: 0; padding: 0;
  border: 0; background: transparent; box-shadow: none;
  color: inherit;
  font-family: var(--font-body);
  font-size: var(--search-font);
  line-height: 1.2;
  -webkit-appearance: none; appearance: none;
  text-overflow: ellipsis;                 /* langer Text/Placeholder läuft nie heraus */
}
.vi-search__input:focus, .vi-search__input:focus-visible { outline: none; box-shadow: none; border: 0; }
.vi-search__input::placeholder { color: var(--search-placeholder); font-weight: var(--fw-normal, 400); opacity: 1; }
/* Browser-Eigenheiten: native Such-Dekoration und Aufräum-Knopf gehören uns, nicht dem UA. */
.vi-search__input::-webkit-search-decoration,
.vi-search__input::-webkit-search-cancel-button,
.vi-search__input::-webkit-search-results-button,
.vi-search__input::-webkit-search-results-decoration { -webkit-appearance: none; appearance: none; display: none; }
/* Autofill darf die Fläche nicht gelb einfärben (Chrome/Edge). */
.vi-search__input:-webkit-autofill,
.vi-search__input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--search-ink);
  box-shadow: 0 0 0 1000px var(--search-bg) inset;
}

/* Clear-Knopf: fester Platz, damit das Ein-/Ausblenden NIE die Breite verändert. */
.vi-search__clear {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; margin-right: -2px;
  padding: 0; border: 0; border-radius: 999px;
  background: transparent; color: var(--gray-500);
  cursor: pointer;
  visibility: hidden;                      /* nicht display:none → kein Layoutsprung */
  transition: background var(--transition, 150ms ease), color var(--transition, 150ms ease);
}
.vi-search.is-filled .vi-search__clear { visibility: visible; }
.vi-search__clear:hover { background: var(--gray-100); color: var(--gray-900); }
.vi-search__clear:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Ladeanzeige IM Feld — ersetzt nichts, verschiebt nichts. */
.vi-search__spin {
  flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--gray-300); border-top-color: var(--green-600);
  animation: vi-search-spin .7s linear infinite;
}
@keyframes vi-search-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .vi-search, .vi-search__clear { transition: none; }
  .vi-search__spin { animation-duration: 2.4s; }
}

/* Sichtbares Label — nur wo fachlich zwingend, IMMER über dem Feld, nie im Rahmen. */
.vi-search-label {
  display: block; margin-bottom: var(--space-1, 4px);
  font-size: var(--text-sm); font-weight: var(--fw-medium, 500); color: var(--gray-700);
}

/* Volle Breite in Filterleisten/Toolbars: die Leiste bestimmt die Breite, nicht das Feld. */
.vi-search--block { width: 100%; }

/* ── BADGE ── dezenter Hintergrund (~12%) · kein Vollton ── */
.ds-badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 2px var(--space-2); border-radius: 999px;
  font-family: var(--font-body); font-size: var(--text-xs); font-weight: var(--fw-medium); line-height: 1.5;
  background: var(--gray-100); color: var(--gray-700);
}
.ds-badge--success { background: var(--color-success-soft); color: var(--color-success-ink); }
.ds-badge--warning { background: var(--color-warning-soft); color: var(--color-warning-ink); }
.ds-badge--danger  { background: var(--color-danger-soft);  color: var(--color-danger-ink); }
.ds-badge--info    { background: var(--color-info-soft);    color: var(--color-info-ink); }

/* ── TAB-NAV ── Ebene 2: Unterstrich, nie Pills, nie mehrzeilig ── */
.ds-tab-nav { display: flex; gap: var(--space-5); border-bottom: 1px solid var(--gray-300); }
.ds-tab-nav__item {
  appearance: none; background: transparent; border: none; cursor: pointer;
  padding: var(--space-3) 0; margin-bottom: -1px;
  font-family: var(--font-body); font-size: var(--text-md); font-weight: var(--fw-medium); color: var(--gray-500);
  border-bottom: 2px solid transparent; transition: color var(--transition), border-color var(--transition);
}
.ds-tab-nav__item:hover { color: var(--gray-900); }
.ds-tab-nav__item.is-active { color: var(--gray-900); border-bottom-color: var(--green-600); font-weight: var(--fw-semibold); }

/* ── PAGE HEADER ── Ebene 1 der Seitenarchitektur ─────────────────────────────
   Links: Titel + darunter EINE Kontextzeile (Anzahl · Objektbezug · Stand).
   Rechts: genau EINE Primäraktion, wenige Sekundäraktionen, Rest im „⋯"-Menü.
   Kein Hero, keine Erklärtexte, keine Kachelwand darunter. */
.ds-page-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-4); }
.ds-page-header__titles { min-width: 0; }
.ds-page-header__breadcrumb { font-size: var(--text-xs); color: var(--gray-500); margin-bottom: var(--space-1); }
.ds-page-header__title { font-size: var(--text-xl); }
.ds-page-header__subtitle { font-size: var(--text-sm); color: var(--gray-500); margin-top: 2px; font-variant-numeric: tabular-nums; }
.ds-page-header__actions { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }

/* ── KENNZAHLEN ── bewusst KEIN 4er-Raster gleich großer Kacheln ──────────────
   Zwölf identische Kacheln sagen „alles ist gleich wichtig" — also nichts. Die
   Kennzahlleiste ist eine Zeile aus Schaltern in EINER Fläche; Größe entsteht durch
   Rang (`.ds-kpi--lead`), nicht durch Wiederholung. */
.ds-kpi-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  background: var(--color-surface); border: 1px solid var(--gray-300);
  border-radius: var(--radius-lg); overflow: hidden;
}
.ds-kpi { padding: var(--space-4) var(--space-5); border-left: 1px solid var(--border-subtle); }
.ds-kpi:first-child { border-left: 0; }
.ds-kpi__label { font-size: var(--text-xs); color: var(--gray-500); }
.ds-kpi__value { font-size: var(--text-xl); margin-top: 2px; }
.ds-kpi--lead .ds-kpi__value { font-size: var(--text-2xl); }
@media (max-width: 900px) { .ds-kpi { border-left: 0; border-top: 1px solid var(--border-subtle); } .ds-kpi:first-child { border-top: 0; } }

/* ── Formular-/Detail-Layout-Hilfen ── */
.ds-form { max-width: 640px; }

/* ══════════════════════════════════════════════════════════════════════════════
   ARBEITSFLÄCHEN-SKALA  (vi-ui.css · Betrieb-Redesign 03.08.2026)
   ──────────────────────────────────────────────────────────────────────────────
   Die Skala oben (--text-*) ist die Marketing-/Dokumentskala: --text-2xl = 40px.
   Für dichte Arbeitsflächen (Listen, Tabellen, Filter, Akten) ist sie zu grob —
   ein 40px-Seitentitel über einer 12px-Tabelle erzeugt genau den Bruch, den der
   Bereich „Betrieb" zeigte. Deshalb hier EINE eigene, engere Skala.
   Verbindlich für alle vi-*-Bausteine; kein Modul definiert eigene Schriftgrößen.
   Werte bewusst etwas größer als der Bestand (Lesbarkeit bei 1366 px und Zoom).
   ══════════════════════════════════════════════════════════════════════════════ */
:root {
  /* Schriftgrößen der Arbeitsfläche */
  --ui-text-page:    1.375rem;  /* 22px — Seitentitel */
  --ui-text-section: 1rem;      /* 16px — Abschnittstitel */
  --ui-text-body:    0.875rem;  /* 14px — Tabellen- und Formularwerte */
  --ui-text-strong:  0.9375rem; /* 15px — Primärwert einer Zeile */
  --ui-text-meta:    0.8125rem; /* 13px — Sekundärwert, Hilfstext */
  --ui-text-label:   0.75rem;   /* 12px — Feldbeschriftung, Badge, Tabellenkopf */
  --ui-text-metric:  1.25rem;   /* 20px — Kennzahl in der Metrikleiste */

  /* Maße der Bedienelemente — EINE Höhe je Klasse, app-weit */
  --ui-field-h:      var(--control-h-md);   /* Filter-, Auswahl- und Eingabefelder */
  --ui-btn-h:        var(--control-h-md);   /* Schaltflächen in Arbeitsleisten */
  --ui-btn-sm-h:     30px;      /* kompakte Zeilenschaltflächen */
  --ui-row-h:        44px;      /* Tabellenzeile */
  /* Kennzahlkachel bewusst NIEDRIGER als ein Filterfeld: sie ist ein Schalter, keine
     Karte. 46px wirkten wie eine Kachelreihe und drängten die Liste nach unten
     (Nutzerbefund 03.08.2026). 32px reichen für Zahl + Wort in einer Zeile. */
  --ui-metric-h:     32px;      /* Kennzahlkachel */
  --ui-radius:       var(--radius-md);       /* Felder, Kacheln, Chips */
  --ui-radius-lg:    var(--radius-lg);       /* Karten, Tabellenrahmen */

  /* Flächen und Linien der Arbeitsfläche */
  --ui-surface:      var(--color-surface);   /* Weiß — primäre Inhaltsfläche */
  --ui-surface-2:    var(--gray-100);        /* Hover, Zebra, eingelassene Spur */
  --ui-line:         var(--gray-300);        /* Rahmen einer Fläche */
  --ui-line-soft:    var(--gray-200);        /* Zeilentrenner INNERHALB einer Fläche */
}

/* ══════════════════════════════════════════════════════════════════════════════
   TABELLEN — GEMEINSAME VISUELLE BASIS (Block 3, §10)
   ──────────────────────────────────────────────────────────────────────────────
   VITable (public/vi-table.js) ist der Standard für NEUE Listen. Daneben leben
   rund dreißig gewachsene Tabellen mit eigenem Markup und eigener Fachlogik. Sie
   werden hier NICHT auf eine neue Tabellenengine migriert — das wäre ein Umbau
   über Wochen. Was ihnen ab hier genommen wird, sind genau die vier Dinge, die
   eine Liste als „aus einem anderen Programm" erscheinen ließen:

     ① Schreibweise des Kopfes  gesperrte VERSALIEN → Satzschreibung
     ② Ruhe des Kopfes          dunkle Vollflächen → helle Fläche, EINE Abschlusslinie
     ③ Zeilenhöhe               56 px starr → 46 px als MINDESThöhe (mehrzeilig wächst)
     ④ Schriftgröße im Körper   10,5–13 px → 14 px (--text-md)

   Die Selektorliste nennt die betroffenen Tabellen ausdrücklich — es gibt keine
   pauschale `table`-Regel, die irgendwann eine fremde Tabelle mitreißt. Eine neue
   Alt-Tabelle gehört hier ergänzt; eine NEUE Liste nimmt VITable.
   Spaltenbreiten werden bewusst NICHT angefasst: sie kommen aus dem Inhalt bzw.
   aus der vom Nutzer gezogenen Breite (colresize.js).
   ══════════════════════════════════════════════════════════════════════════════ */
:root {
  --table-row-h:       46px;   /* Mindesthöhe einer einzeiligen Datenzeile */
  --table-head-h:      38px;
  --table-body-size:   var(--text-md);
}

/* ── ① + ② Kopf ────────────────────────────────────────────────────────────── */
.ds-table thead th,
.data-table thead th,
.obj-table thead th,
.sc-table thead th, .sc-pos-table thead th,
.ho-table thead th, .ho-dtable thead th, .ho-kv thead th,
.abl-table thead th, .abl-detail-table thead th,
.gasp-tbl thead th,
.fba-table thead th,
.sa-table thead th,
.stammdaten-table thead th,
.pruef-table thead th, .rd-pruef-tbl thead th,
.imp2-hist thead th, .imp2-preview thead th,
.dvc-table thead th, .dt-table thead th, .dte-tbl thead th,
.dok-table thead th, .doc-table thead th, .doc-vh-table thead th,
.cx-table thead th, .cmp-dangling-table thead th,
.cck-cases-table thead th, .adm-audit-table thead th,
.ph-table thead th, .rfu-table thead th,
.wo-list thead th, .wk-wl thead th, .fk-table thead th {
  text-transform: none;
  letter-spacing: normal;
  font-size: var(--table-head-size);
  font-weight: var(--fw-semibold);
  color: var(--table-head-color);
  background: var(--table-head-bg);
  border-bottom: 1px solid var(--table-head-line);
  height: var(--table-head-h);
  text-align: left;
}
/* Zahlenspalten behalten ihre Rechtsbündigkeit. */
.ds-table thead th.num, .data-table thead th.num, .obj-table thead th.num,
.sc-table thead th.num, .sc-pos-table thead th.num,
.abl-detail-table thead th.num, .cx-table thead th.num,
.ds-table thead th[data-num], .data-table thead th[data-num] { text-align: right; }

/* ── ③ + ④ Zeilen ─────────────────────────────────────────────────────────────
   `height` wirkt in Tabellen als MINDESThöhe: einzeilige Zellen stehen auf 46 px,
   umbrechender Inhalt wächst von selbst. Keine starre Höhe, kein Abschneiden. */
.ds-table tbody td,
.data-table tbody td,
.obj-table tbody td,
.sc-table tbody td, .sc-pos-table tbody td,
.ho-table tbody td, .ho-dtable tbody td, .ho-kv tbody td,
.abl-table tbody td, .abl-detail-table tbody td,
.gasp-tbl tbody td,
.fba-table tbody td,
.sa-table tbody td,
.stammdaten-table tbody td,
.pruef-table tbody td, .rd-pruef-tbl tbody td,
.imp2-hist tbody td, .imp2-preview tbody td,
.dvc-table tbody td, .dt-table tbody td, .dte-tbl tbody td,
.dok-table tbody td, .doc-table tbody td, .doc-vh-table tbody td,
.cx-table tbody td, .cmp-dangling-table tbody td,
.cck-cases-table tbody td, .adm-audit-table tbody td,
.ph-table tbody td, .rfu-table tbody td,
.wo-list tbody td, .wk-wl tbody td, .fk-table tbody td {
  height: var(--table-row-h);
  font-size: var(--table-body-size);
  line-height: var(--lh-normal);
  vertical-align: middle;
}

/* ── Touch-Ziele feldinterner Zusätze (UI-Welle §47/§61) ──────────────────────
   Das Löschkreuz im Suchfeld ist optisch bewusst klein (20 px) — mit dem Finger
   ist es so aber kaum zu treffen. Auf Zeigegeräten ohne Präzision bekommt es
   deshalb eine größere TREFFFLÄCHE, ohne optisch zu wachsen. */
@media (pointer: coarse) {
  .vi-search__clear {
    min-width: 40px; min-height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════════
   PFLICHTFELD-MARKIERUNG UND FELDFEHLER — EINE Definition (28.08.2026, AP 0.6)
   ───────────────────────────────────────────────────────────────────────────────
   Regel aus dem Dialogstandard: „Pflichtfeld in Markenfarbe (NIE rot, rot heißt
   Fehler), Fehler immer als Rahmen PLUS Meldung." Der Stern im Erfassen-Dialog war
   rot (.aaw-req) — damit sah ein völlig normales Formular nach Fehler aus. Die
   Selektorliste nennt beide Namen ausdrücklich; es gibt keine zweite Definition.

   .ds-req      Pflicht-Stern neben dem Label — Markenfarbe.
   .ds-fielderr Fehlermeldung AM Feld (nicht als Toast, der wandert weg).
   .is-invalid  Rahmen des fehlerhaften Felds (ergänzt die Meldung, ersetzt sie nie).
   ═══════════════════════════════════════════════════════════════════════════════ */
.ds-req,
.aaw-req,
.mx-req { color: var(--brand-primary); font-weight: var(--fw-semibold); }

.ds-fielderr,
.aaw-fielderr,
.mx-fielderr {
  display: block; margin: var(--space-1) 0 0;
  font-size: var(--text-xs); color: var(--color-danger-ink);
}

.form-input.is-invalid,
.form-select.is-invalid,
.is-invalid > .form-input,
.is-invalid > .form-select { border-color: var(--color-danger-ink); }
