/* ==========================================================================
   modus-theme.css — Modus „Slate & Signal" Design-System
   Geladen NACH app.css, VOR dem scoped-Bundle (SalaryCalculation.Web.styles.css).
   Plan: .claude/plans/2026-06-21_design-system.md
   Strang A0: --mo-* Tokens + Fonts + Utilities
   Strang A1: FAST-Token-Override (.fluent-design-system-provider)
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. @font-face — Inter self-hosted (SIL OFL 1.1, FOSS)
      Quelle: fontsource CDN → wwwroot/fonts/inter/
      Lizenz: fonts/inter/OFL.txt
   -------------------------------------------------------------------------- */

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/inter/inter-400.woff2') format('woff2'),
         url('../fonts/inter/inter-400.woff') format('woff');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/inter/inter-500.woff2') format('woff2'),
         url('../fonts/inter/inter-500.woff') format('woff');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/inter/inter-600.woff2') format('woff2'),
         url('../fonts/inter/inter-600.woff') format('woff');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/inter/inter-700.woff2') format('woff2'),
         url('../fonts/inter/inter-700.woff') format('woff');
}

/* --------------------------------------------------------------------------
   2. :root — Modus-Design-Tokens (Light-Theme, alle --mo-*)
      Plan §1.1 — autoritativ, exakte Hex-Werte
   -------------------------------------------------------------------------- */

:root {
    /* --- Grün-Skala --- */
    --mo-green:               #9CCC3C; /* Fläche/Tint/Signal — NIE als Text auf Weiß (2,3:1) */
    --mo-green-interactive:   #5A8A00; /* Buttons-BG, Links, aktiver Text, Focus */
    --mo-green-hover:         #4A7400;
    --mo-green-pressed:       #3D6200;
    --mo-green-tint-hover:    #F4FAE8; /* Row-Hover, Info-Box */
    --mo-green-tint-active:   #E4F0C8; /* Selektierte Zeile / aktiver Nav-BG */
    --mo-on-green:            #1A2E00; /* Text auf --mo-green-Flächen, Badge „erfasst" */
    --mo-on-green-i:          #FFFFFF; /* Text auf Interactive-Grün */

    /* --- Neutral / Slate --- */
    --mo-ink:                 #1A1D21; /* Primärtext, KPI-Zahlen, Geld */
    --mo-ink-2:               #2C3036; /* Top-Bar-BG, Überschriften */
    --mo-ink-3:               #454B54; /* Sekundärtext, Stunden */
    --mo-muted:               #6B7280; /* Labels, Tabellenkopf */
    --mo-muted-2:             #909090; /* Marken-Grau, Wortmarke */

    /* --- Borders --- */
    --mo-border-strong:       #B8BEC7;
    --mo-border:              #D1D5DB;
    --mo-hairline:            #E8EAED;

    /* --- Flächen --- */
    --mo-page:                #F4F5F6; /* App-Shell-Hintergrund */
    --mo-surface:             #FFFFFF; /* Cards, Roster, Dialog */
    --mo-surface-2:           #FAFAFA; /* Sidebar, Zebra-ungerade (eine Stufe tiefer als Content) */
    --mo-surface-3:           #F0F1F3; /* Sidebar Dark, Tablet-Rail (noch eine Stufe tiefer) */
    --mo-topbar:              #2C3036; /* LEGACY: Top-Bar-Hintergrund — ablösbar via --mo-header-bg */

    /* --- Header-Tokens (flach-heller Header) --- */
    --mo-header-bg:           #FFFFFF; /* = Content-Bg; eine Ebene mit Content */
    --mo-header-border:       #E8EAED; /* = --mo-hairline; Haarlinie Trennung */
    --mo-header-title:        #1A1D21; /* = --mo-ink; Titel in Vordergrundfarbe */
    --mo-header-meta:         #6B7280; /* = --mo-muted; Toggle, Kontext-Label */
    --mo-header-shadow-scrolled: 0 1px 4px rgba(0, 0, 0, .10); /* Schatten nur beim Scrollen */

    /* --- Logo-Akzent --- */
    --mo-logo-accent:         #5A8A00; /* M-Monogramm: Interactive-Grün (WCAG AA auf Weiß) */

    /* --- Sidebar-Tokens (Dark: dunkler als Content) --- */
    --mo-sidebar-bg:          #FAFAFA; /* Light: eine Stufe tiefer als #FFFFFF Content */
    --mo-sidebar-border:      #E8EAED; /* = --mo-hairline */

    /* --- Semantische Farben --- */
    --mo-success:             #5A8A00;
    --mo-warning:             #B45309;
    --mo-danger:              #B91C1C;
    --mo-danger-hover:        #991B1B; /* A1: Hover-Zustand für Danger-Aktionen (z. B. Retry-Link) */
    --mo-info:                #1D6FAB;

    /* --- Section-Accent-Tokens (linke Border-Akzente in Zuschlag-Sections) ---
       Ersetzen hardcoded hex in PayrollDetailDialog / PayrollSheet.
       Nur dekorativ (4px left-border auf Dialog-Surface), AA nicht erforderlich.
       Stunden-Section nutzt direkt --mo-green-interactive (kein eigener Alias). */
    --mo-accent-night:        #3B6FB0; /* Blau — Nacht-Zuschläge */
    --mo-accent-sunday:       #C77A0A; /* Amber-Dunkel — Sonntags-Zuschläge */
    --mo-accent-holiday:      #B5462F; /* Rot-Gedämpft — Feiertags-Zuschläge */
    --mo-accent-sick:         #7A4FA0; /* Violett — Krank/Sonderurlaub */
    --mo-accent-extra:        #4A52C8; /* Indigo — Zusatzleistungen */

    /* --- Banner-Tokens (Single-Source, migriert aus MoStatusBanner.razor.css :root) ---
       MoStatusBanner.razor.css referenziert diese Tokens; die dortigen :root/:dark-Blöcke
       werden in Task D entfernt. */
    /* Amber (Disconnected / Unauthorized) */
    --mo-banner-amber-bg:     #FEF3C7; /* Tailwind amber-100 — 4,7:1 ggü. #92400E ✓ */
    --mo-banner-amber-border: #B45309; /* = --mo-warning */
    --mo-banner-amber-text:   #92400E; /* amber-800 — 4,9:1 ggü. #FEF3C7 ✓ */
    --mo-banner-amber-icon:   #B45309; /* = --mo-warning */
    /* Reconnecting (neutral-grau) */
    --mo-banner-grey-bg:      #F4F5F6; /* = --mo-page */
    --mo-banner-grey-border:  #D1D5DB; /* = --mo-border */
    --mo-banner-grey-text:    #454B54; /* = --mo-ink-3 — 7:1 ggü. #F4F5F6 ✓ */
    --mo-banner-grey-icon:    #6B7280; /* = --mo-muted */
    /* Update (Info-Blau) */
    --mo-banner-info-bg:      #EFF6FF; /* blue-50 */
    --mo-banner-info-border:  #1D6FAB; /* = --mo-info */
    --mo-banner-info-text:    #1E40AF; /* blue-800 — 7,1:1 ggü. #EFF6FF ✓ */
    --mo-banner-info-icon:    #1D6FAB; /* = --mo-info */

    /* --- Focus-Ring --- */
    --mo-focus-ring:          #5A8A00;

    /* --- Elevation-Tokens --- */
    --mo-elev-card:           0 1px 3px rgba(0, 0, 0, .06);
    --mo-elev-pop:            0 4px 12px rgba(0, 0, 0, .10);
    --mo-elev-dialog:         0 8px 32px rgba(0, 0, 0, .16);

    /* --- Radius-Tokens --- */
    --mo-radius-xs:           2px;
    --mo-radius-sm:           4px;
    --mo-radius-md:           6px;
    --mo-radius-lg:           8px;

    /* --- Motion-Tokens --- */
    --mo-motion-fast:         120ms ease-out;
    --mo-motion-dialog:       200ms ease-out;

    /* --- Content-Breite-Tokens (§2 Content-Breite) ---
       Seitentyp-abhängige max-width, immer linksbündig (margin-inline: 0).
       Roster/DataGrid: KEIN max-width — immer voll-breit. */
    --modus-content-max-width-header:  1400px;  /* Cockpit-Kopf: Picker + 4 KPI-Cards */
    --modus-content-max-width-list:    1200px;  /* Listen (Mitarbeiter) */
    --modus-content-max-width-form:     800px;  /* Detail-/Edit-Formulare, Tarif-Settings */
    --modus-content-padding-inline:  clamp(16px, 3vw, 48px);  /* Responsive Innenabstand */

    /* --- Sidebar-Breite (L3 prep) --- */
    --sidebar-width:           220px;
}

/* --------------------------------------------------------------------------
   3. Dark-Theme-Overrides — body[data-theme="dark|system-dark"]
      FAST/Blazor-Fluent setzt body[data-theme] — NICHT :root[data-theme]!
      Plan §1.2 — autoritativ, exakte Hex-Werte

      html bekommt den dunklen Seiten-Hintergrund über :has() (Baseline 2023,
      Chrome 105+, Firefox 121+, Safari 15.4+): html selbst kennt data-theme
      nicht (es liegt auf body), aber via :has() kann html auf seinen
      Nachkommen body reagieren. Verhindert weißen Bleed hinter dem body-Element.
   -------------------------------------------------------------------------- */

html:has(body[data-theme="dark"]),
html:has(body[data-theme="system-dark"]) {
    background-color: #15181C; /* = --mo-page dark */
    /* color-scheme vererbt sich → native Scrollbars (und native Controls) rendern dunkel,
       statt der hellen OS-Default-Scrollbar auf dunklem UI. */
    color-scheme: dark;
}

/* Light explizit hell setzen, damit bei dunklem OS + manuell gewähltem Light-Theme die
   Scrollbar trotzdem hell bleibt (sonst zieht der Browser die OS-Präferenz). */
html:has(body[data-theme="light"]),
html:has(body[data-theme="system-light"]) {
    color-scheme: light;
}

body[data-theme="dark"],
body[data-theme="system-dark"] {
    /* --- Grün-Skala (Dark) --- */
    --mo-green:               #9CCC3C; /* Marken-Grün bleibt (Badge „erfasst", Progress-Fill) */
    --mo-green-interactive:   #A6D63D; /* Aufgehellt: AA-Ziel ≥ 4,5:1 gegen #1B1E22 (≈ 9:1 ✓) */
    --mo-green-hover:         #B6E25A;
    --mo-green-pressed:       #8FC02E;
    --mo-green-tint-hover:    #23301A; /* Dunkler grün getönter Row-Hover */
    --mo-green-tint-active:   #2E3F1E;
    --mo-on-green:            #13230A; /* Dunkler Text auf hellem --mo-green (Badge „erfasst") */
    --mo-on-green-i:          #13230A; /* Button-Primary auf Dunkel = helles Grün-BG → dunkler Text */

    /* --- Neutral / Slate (Dark) --- */
    --mo-ink:                 #ECEEF1; /* Primärtext (≈ 13:1 ✓) */
    --mo-ink-2:               #D4D8DE;
    --mo-ink-3:               #AEB4BD; /* Sekundär (AA ✓) */
    --mo-muted:               #8B929C; /* Labels (≈ 5,6:1 ✓) */
    --mo-muted-2:             #6E747D;

    /* --- Borders (Dark) --- */
    --mo-border-strong:       #4A515B;
    --mo-border:              #3A404A;
    --mo-hairline:            #2A2F37;

    /* --- Flächen (Dark) --- */
    --mo-page:                #15181C;
    --mo-surface:             #1B1E22;
    --mo-surface-2:           #212429;
    --mo-surface-3:           #141418; /* DUNKLER als page — Sidebar Dark (Schlüssel-Änderung) */
    --mo-topbar:              #101216; /* LEGACY */

    /* --- Header-Tokens Dark (flach, = Content-Ebene) --- */
    --mo-header-bg:           #1B1E22; /* = --mo-surface Dark; Header = Content-Ebene */
    --mo-header-border:       #2A2F37; /* = --mo-hairline Dark */
    --mo-header-title:        #ECEEF1; /* = --mo-ink Dark */
    --mo-header-meta:         #8B929C; /* = --mo-muted Dark */
    --mo-header-shadow-scrolled: 0 1px 6px rgba(0, 0, 0, .40); /* Schatten on-scroll Dark */

    /* --- Logo-Akzent Dark --- */
    --mo-logo-accent:         #9CCC3C; /* M-Monogramm: Frisch-Grün (WCAG AA auf Dunkel ~9:1) */

    /* --- Sidebar-Tokens Dark (dunkler als Content → Hierarchie!) --- */
    --mo-sidebar-bg:          #141418; /* = --mo-surface-3 = DUNKLER als --mo-surface Content */
    --mo-sidebar-border:      #2A2F37; /* = --mo-hairline Dark */

    /* --- Semantisch (Dark) --- */
    --mo-success:             #A6D63D;
    --mo-warning:             #E0922F;
    --mo-danger:              #F0726B;
    --mo-danger-hover:        #F0908A; /* A1: Hover-Zustand für Danger-Aktionen (Dark) */
    --mo-info:                #5AAEEA;

    /* --- Section-Accent-Tokens Dark (aufgehellt ~+30% L für AA auf dunkler Surface) --- */
    --mo-accent-night:        #6BA3E0; /* Blau-Hell */
    --mo-accent-sunday:       #E0A445; /* Amber-Hell */
    --mo-accent-holiday:      #E08066; /* Rot-Hell */
    --mo-accent-sick:         #B08FD8; /* Violett-Hell */
    --mo-accent-extra:        #8A90E8; /* Indigo-Hell */

    /* --- Banner-Tokens Dark (Single-Source, migriert aus MoStatusBanner.razor.css) --- */
    /* Amber (Disconnected / Unauthorized) */
    --mo-banner-amber-bg:     rgba(180, 83, 9, 0.15); /* Amber-Tint auf dunkler Fläche */
    --mo-banner-amber-border: #FCD34D;                /* amber-300 — sichtbar auf dunkel ✓ */
    --mo-banner-amber-text:   #FDE68A;                /* amber-200 — 8:1 ggü. #1B1E22 ✓ */
    --mo-banner-amber-icon:   #FCD34D;                /* amber-300 */
    /* Reconnecting (neutral-grau dark) */
    --mo-banner-grey-bg:      #212429; /* = --mo-surface-2 dark */
    --mo-banner-grey-border:  #3A404A; /* = --mo-border dark */
    --mo-banner-grey-text:    #AEB4BD; /* = --mo-ink-3 dark — 5,5:1 ggü. #212429 ✓ */
    --mo-banner-grey-icon:    #8B929C; /* = --mo-muted dark */
    /* Update (Info-Blau dark) */
    --mo-banner-info-bg:      rgba(29, 111, 171, 0.15); /* Info-Tint auf dunkel */
    --mo-banner-info-border:  #5AAEEA;                  /* = --mo-info dark */
    --mo-banner-info-text:    #93C5FD;                  /* blue-300 — 6,8:1 ggü. #1B1E22 ✓ */
    --mo-banner-info-icon:    #5AAEEA;                  /* = --mo-info dark */

    /* --- Focus-Ring (Dark) --- */
    --mo-focus-ring:          #A6D63D;

    /* --- Elevation-Tokens (Dark — stärker wegen dunkler Flächen) --- */
    --mo-elev-card:           0 1px 3px rgba(0, 0, 0, .50);
    --mo-elev-pop:            0 4px 12px rgba(0, 0, 0, .55);
    --mo-elev-dialog:         0 8px 32px rgba(0, 0, 0, .60);

    /* Radius + Motion identisch zu Light */
}

/* --------------------------------------------------------------------------
   4. Basis-Typografie — Inter als globaler Font-Stack
      Überschreibt app.css Z.1-3 (Helvetica-Stack)
      background-color auf html+body → kein weißer Bleed im Dark-Mode
      (html/body sind by default transparent; .page-content setzt --mo-page
       nur für den Scroll-Wrapper, nicht für den sichtbaren html/body-Grund).
   -------------------------------------------------------------------------- */

html, body {
    font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    background-color: var(--mo-page);
    /* App-Shell (2026-06-21): Die Shell füllt 100dvh selbst; html/body dürfen
       nicht scrollen (würde Doppel-Scrollbar und Footer-Wegrutschen verursachen).
       margin:0 entfernt Browser-Default (8px), damit div.layout flush am Fenster liegt. */
    margin: 0;
    padding: 0;
    overflow: hidden;
    height: 100%;
}

/* --------------------------------------------------------------------------
   5. Tabular-Nums-Utilities — Geld/Stunden/KPI numerisch korrekt
      Plan §3
   -------------------------------------------------------------------------- */

/* .num — generische Ziffern-Utility */
.num {
    font-variant-numeric: tabular-nums slashed-zero lining-nums;
    font-feature-settings: 'tnum' 1, 'zero' 1;
}

/* Verstärkung der bestehenden Lohnlauf-Klassen */
.money,
.money-hero,
.hours {
    font-variant-numeric: tabular-nums slashed-zero lining-nums;
    font-feature-settings: 'tnum' 1, 'zero' 1;
}

/* --------------------------------------------------------------------------
   6. .payroll-surcharge Override
      FAST-Override würde --accent-fill-rest = grellgrüne Fläche.
      Explizit auf dezente Modus-Tints setzen.
      Plan §5 / §0.1
   -------------------------------------------------------------------------- */

.payroll-readonly.payroll-surcharge {
    background-color: var(--mo-green-tint-hover);
    border-color: var(--mo-green-interactive);
    color: var(--mo-green-interactive);
}

/* --------------------------------------------------------------------------
   7. prefers-reduced-motion — Barrierefreiheit (Plan §3.3 / §5)
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: 0ms !important;
        animation-duration: 0ms !important;
        animation-iteration-count: 1 !important;
    }
}

/* --------------------------------------------------------------------------
   8. Status-Badge-Klassen — 4-stufig (A2: hex → --mo-*-Tokens, +.mo-badge--error)
      Strang C entscheidet ob class oder Style genutzt wird.
      LIGHT-Defaults hier auf :root-Kontext.
      SCOPED Part-Neutralisierung am Ende dieses Abschnitts:
        → NUR .mo-badge--*::part(control) (kein globales fluent-badge::part),
          damit Progress-Badge (Cockpit:68) und „Inaktiv" (EmployeeDetail:54)
          ihren FAST-Appearance-Fill behalten.
   -------------------------------------------------------------------------- */

/* Gemeinsame Typografie/Spacing-Basis (alle Badge-Varianten) */
.mo-badge--open,
.mo-badge--captured,
.mo-badge--committed,
.mo-badge--error {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    border-radius: var(--mo-radius-sm, 4px);
    padding: 2px 8px;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
}

/* open: Hairline-BG, Sekundärtext, dezente Border */
.mo-badge--open {
    background-color: var(--mo-hairline);
    color: var(--mo-ink-3);
    border: 1px solid var(--mo-border);
}

/* captured: Marken-Grün, dunkler Text auf grüner Fläche */
.mo-badge--captured {
    background-color: var(--mo-green);
    color: var(--mo-on-green);
    border: none;
}

/* committed: Tief-Dunkel, heller Text (="abgerechnet") */
.mo-badge--committed {
    background-color: var(--mo-ink-2);
    color: var(--mo-page);
    border: none;
}

/* error: Danger-Tint via color-mix (passt sich Surface-Farbe in Light+Dark an) */
.mo-badge--error {
    background-color: color-mix(in srgb, var(--mo-danger) 10%, var(--mo-surface));
    color: var(--mo-danger);
    border: 1px solid color-mix(in srgb, var(--mo-danger) 45%, var(--mo-surface));
}

/* Dark-Overrides für Status-Badge-Klassen */
body[data-theme="dark"] .mo-badge--open,
body[data-theme="system-dark"] .mo-badge--open {
    background-color: var(--mo-hairline); /* Dark: #2A2F37 */
    color: var(--mo-ink-3);              /* Dark: #AEB4BD */
    border: 1px solid var(--mo-border);  /* Dark: #3A404A */
}

body[data-theme="dark"] .mo-badge--captured,
body[data-theme="system-dark"] .mo-badge--captured {
    background-color: var(--mo-green);   /* Dark: #9CCC3C (Marken-Grün bleibt) */
    color: var(--mo-on-green);           /* Dark: #13230A */
    border: none;
}

body[data-theme="dark"] .mo-badge--committed,
body[data-theme="system-dark"] .mo-badge--committed {
    background-color: var(--mo-border);  /* Dark: #3A404A */
    color: var(--mo-ink);               /* Dark: #ECEEF1 */
    border: none;
}

/* error dark: color-mix ist theme-aware via --mo-danger/--mo-surface Dark-Werte,
   kein separater Override nötig. */

/* SCOPED Part-Neutralisierung: tötet den FAST-Appearance-Fill (Halo) UNTER dem Host
   NUR für unsere .mo-badge--*-Klassen. Greift NICHT auf fluent-badge ohne Klasse
   → Progress-Badge (Appearance.Accent) + „Inaktiv" (Appearance.Neutral) unverändert. */
fluent-badge.mo-badge--open::part(control),
fluent-badge.mo-badge--captured::part(control),
fluent-badge.mo-badge--committed::part(control),
fluent-badge.mo-badge--error::part(control) {
    background: transparent !important;
    /* Textfarbe vom Host erben — sonst überschreibt FASTs Part-Foreground (weiß) die
       gesetzte color (z. B. dunkler Text #13230A auf dem grünen „erfasst"-Badge). */
    color: inherit !important;
    padding: 0 !important;
    border: 0 !important;
}

/* --------------------------------------------------------------------------
   9. KPI-Card-Helfer (für Strang C)
      Plan §5 / §6
   -------------------------------------------------------------------------- */

.mo-kpi-card {
    background-color: var(--mo-surface);
    border: 1px solid var(--mo-hairline);
    border-top: 3px solid var(--mo-green);
    border-radius: var(--mo-radius-md);
    box-shadow: var(--mo-elev-card);
    padding: 1rem;
}

/* --------------------------------------------------------------------------
   10. Button-Grundregeln (ergänzend, falls FluentDesignTheme/CustomColor
       nicht alle Fälle abdeckt; minimal halten — CustomColor regelt Hauptteil)
       Plan §5
   -------------------------------------------------------------------------- */

/* Focus-Ring global (für Nicht-Fluent-Elemente) */
:focus-visible {
    outline: 2px solid var(--mo-focus-ring);
    outline-offset: 2px;
}

/* ==========================================================================
   11. FAST-Token-Override — Strang A1
       SPIKE-BEFUND: In Microsoft.FluentUI.AspNetCore.Components 4.14.2 setzt
       das @fluentui/web-components@2-CDN-Bundle die FAST-Design-Tokens direkt
       auf :root via JS (DesignToken.setValueFor). Es gibt kein
       .fluent-design-system-provider-Element im Light-DOM (nur ein registriertes
       CE ohne DOM-Instanz). Die CSS-Kaskade muss deshalb über :root mit
       !important gewinnen, damit der CSS-Wert nach dem JS-Setzen greift.

       Verifiziert per DevTools:
       - getComputedStyle(document.documentElement).getPropertyValue('--accent-fill-rest')
         vor Override: #036ac4 (MS-blau)
       - nach :root { --accent-fill-rest: #5A8A00 !important }: #5A8A00 (Grün)
       - FluentButton[appearance="accent"] .control → backgroundColor: rgb(90,138,0) ✓

       Plan §2.1 — DevTools-Spike-Beweis: FluentButton/FluentNavLink grün
       statt MS-blau in Light UND Dark.
   ========================================================================== */

/* --- Light (Default) --- */
:root {
    /* Accent-Tokens — !important nötig, da FAST-JS sie ohne !important auf :root setzt */
    --accent-fill-rest:             #5A8A00 !important;
    --accent-fill-hover:            #4A7400 !important;
    --accent-fill-active:           #3D6200 !important;
    --accent-foreground-rest:       #5A8A00 !important;
    --accent-foreground-hover:      #4A7400 !important;
    --accent-foreground-active:     #3D6200 !important;
    --accent-stroke-control-rest:   #5A8A00 !important;
    --accent-stroke-control-hover:  #4A7400 !important;
    --accent-stroke-control-active: #3D6200 !important;
    --foreground-on-accent-rest:    #FFFFFF !important;
    --foreground-on-accent-hover:   #FFFFFF !important;
    --foreground-on-accent-active:  #FFFFFF !important;

    /* Neutral-Tokens — Foreground/Surface/Border */
    --neutral-foreground-rest:      #1A1D21 !important;
    --neutral-foreground-hint:      #6B7280 !important;
    --neutral-fill-rest:            #FFFFFF !important;
    --neutral-fill-secondary-rest:  #FAFAFA !important;
    --neutral-fill-layer-rest:      #FFFFFF !important;
    --neutral-stroke-rest:          #D1D5DB !important;
}

/* --- Dark --- */
body[data-theme="dark"],
body[data-theme="system-dark"] {
    /* Accent-Tokens (aufgehellt auf #A6D63D für AA ≥ 4,5:1 gegen dunkle Flächen) */
    --accent-fill-rest:             #A6D63D !important;
    --accent-fill-hover:            #B6E25A !important;
    --accent-fill-active:           #8FC02E !important;
    --accent-foreground-rest:       #A6D63D !important;
    --accent-foreground-hover:      #B6E25A !important;
    --accent-foreground-active:     #8FC02E !important;
    --accent-stroke-control-rest:   #A6D63D !important;
    --accent-stroke-control-hover:  #B6E25A !important;
    --accent-stroke-control-active: #8FC02E !important;
    --foreground-on-accent-rest:    #13230A !important;
    --foreground-on-accent-hover:   #13230A !important;
    --foreground-on-accent-active:  #13230A !important;

    /* Neutral-Tokens — Dark */
    --neutral-foreground-rest:      #ECEEF1 !important;
    --neutral-foreground-hint:      #8B929C !important;
    --neutral-fill-rest:            #1B1E22 !important;
    --neutral-fill-hover:           #212429 !important;
    --neutral-fill-active:          #2A2F37 !important;
    --neutral-fill-secondary-rest:  #212429 !important;
    --neutral-fill-layer-rest:      #1B1E22 !important;
    --neutral-stroke-rest:          #3A404A !important;
    /* Stealth-Fill — NavMenu .positioning-region Hintergrund (FluentNavLink/NavGroup).
       FAST-Algorithmus erzeugt in Dark-Mode für --neutral-fill-stealth-rest fälschlicherweise
       einen fast-weißen Wert (#FBFBFB). Transparent (=inherit von Sidebar-BG) ist korrekt
       für „stealth"-Buttons, die keinen eigenen Hintergrund haben sollen.
       Quelle: FluentUI-Bundle [b-vs37bumpa7] .fluent-nav-item .positioning-region { background: var(--neutral-fill-stealth-rest) } */
    --neutral-fill-stealth-rest:    transparent !important;
    --neutral-fill-stealth-hover:   var(--mo-green-tint-hover) !important;
    --neutral-fill-stealth-active:  var(--mo-green-tint-active) !important;

    /* Input-Flächen (fluent-text-field, fluent-number-field, fluent-combobox outline)
       FAST leitet --neutral-fill-input-* algorithmisch aus --base-layer-luminance ab.
       In Dark ergibt der Algorithmus fast-weiße Werte, da die Luminance-Reihe nicht
       umgekehrt wird. Direktes Pinnen auf --mo-surface überschreibt die Algorithmus-Ausgabe.
       Quelle: lib.module.js mo()-Behavior (neutral-fill-input-behavior). */
    --neutral-fill-input-rest:      #1B1E22 !important; /* = --mo-surface */
    --neutral-fill-input-hover:     #212429 !important; /* = --mo-surface-2 */
    --neutral-fill-input-focus:     #1B1E22 !important; /* = --mo-surface */
    --neutral-fill-input-active:    #2A2F37 !important;

    /* Layer-Tokens — Hintergrund-Ebenen für Cards, DataGrid-Header, allg. Fläche
       --fill-color ist der Universalfallback für interne FAST-Komponenten.
       --neutral-layer-floating steuert Dropdown-Listbox-Panels (fluent-select, fluent-combobox).
       Quelle: lib.module.js sa()-/L.-setValueFor()-Behavior (neutral-layer-floating). */
    --fill-color:                   #1B1E22 !important; /* = --mo-surface */
    --neutral-layer-1:              #15181C !important; /* = --mo-page */
    --neutral-layer-2:              #1B1E22 !important; /* = --mo-surface */
    --neutral-layer-3:              #212429 !important; /* = --mo-surface-2 */
    --neutral-layer-4:              #2A2F37 !important;
    --neutral-layer-card:           #1B1E22 !important; /* = --mo-surface */
    --neutral-layer-card-container: #15181C !important; /* = --mo-page */
    --neutral-layer-floating:       #212429 !important; /* = --mo-surface-2 (Dropdown-Panel) */
}

/* ==========================================================================
   12. Shell-Overrides (GLOBAL, NICHT scoped) — LEAD-Fix nach Browser-Verifikation
   Grund: FluentHeader und FluentNavMenu rendern interne DOM-Elemente
   (<header>, <fluent-nav-menu>) auf die das scoped-CSS-Attribut (b-xxx) von
   Blazor NICHT durchgereicht wird — daher matchten die scoped Regeln in
   MainLayout.razor.css nicht. Diese globalen Regeln (ohne scoped-Attribut)
   treffen die echten Elemente direkt und erzwingen die Shell-Farben.

   HEADER-ÄNDERUNG (2026-06-21): Dunkle #2C3036-Bar abgelöst → flach-hell.
   Header = Content-Ebene (--mo-header-bg), Trennung via Haarlinie (--mo-header-border).
   Schatten (.scrolled) nur beim Scrollen via IntersectionObserver (JS im MainLayout).
   DARK-MODE-KERN: Sidebar-BG = --mo-sidebar-bg (dunkler als Content) → Hierarchie.
   ========================================================================== */

/* ── Header: flach-hell — eine Ebene mit Content ───────────────────────── */
header.mo-topbar,
.fluent-header.mo-topbar,
header.header.mo-topbar {
    height: 48px !important;
    background: var(--mo-header-bg) !important;
    background-color: var(--mo-header-bg) !important;
    border-bottom: 1px solid var(--mo-header-border) !important;
    box-shadow: none !important;
    position: sticky !important;
    top: 0 !important;
    z-index: 100 !important;
    transition: box-shadow 150ms ease !important;
    color: var(--mo-header-title) !important;
}

/* Scroll-Elevation: .scrolled-Klasse wird via JS-IntersectionObserver gesetzt */
header.mo-topbar.scrolled,
.fluent-header.mo-topbar.scrolled,
header.header.mo-topbar.scrolled {
    box-shadow: var(--mo-header-shadow-scrolled) !important;
}

/* Titel und Meta-Elemente in neutraler Vordergrundfarbe (nicht Weiß-auf-Dunkel) */
header.mo-topbar a,
header.mo-topbar span,
header.mo-topbar .mo-topbar-title {
    color: var(--mo-header-title) !important;
}

/* Theme-Toggle-Buttons in der Header-Bar */
header.mo-topbar .mo-theme-btn {
    color: var(--mo-header-meta) !important;
}
header.mo-topbar .mo-theme-btn.active {
    color: var(--mo-header-title) !important;
}

/* Signet im Header: grau-auf-transparent → im Dark-Mode aufhellen (kein SVG/Dark-Asset vorhanden). */
body[data-theme="dark"] .mo-header-sign,
body[data-theme="system-dark"] .mo-header-sign {
    filter: brightness(0) invert(0.85);
}

/* Sidebar-Hintergrund — Light: eine Stufe tiefer als Content; Dark: DUNKLER als Content.
   FluentNavMenu rendert in Blazor 4.14.2 als <div class="mo-sidebar fluent-nav-menu">
   (kein echtes Web-Component). Das scoped-CSS-Kompilat landet als
   "[b-nydnr870gb] .mo-sidebar" (falscher Scope-Anker), das nie matcht.
   Globale Regeln ohne Scope-Attribut treffen das Element direkt.
   App-Shell (2026-06-21): align-self:stretch + overflow-y:auto → Sidebar füllt die
   gesamte mittlere Reihe (Stack-Höhe) und scrollt intern bei vielen Nav-Punkten. */
.mo-sidebar {
    background-color: var(--mo-sidebar-bg) !important;
    border-right: 1px solid var(--mo-sidebar-border) !important;
    align-self: stretch !important;
    overflow-y: auto !important;
}

/* Footer-Hintergrund — FluentFooter reicht b-xxx ebenfalls nicht weiter.
   Footer-Styles werden primär via .app-footer in MainLayout.razor.css gesetzt;
   diese globale Regel greift als Fallback auf das <fluent-footer>-Element. */
fluent-footer {
    border-top: 1px solid var(--mo-hairline) !important;
    background-color: var(--mo-surface-2) !important;
}

/* FluentBodyContent — Haupt-Content-Wrapper
   Blazor Fluent UI 4.14.2 renders <FluentBodyContent> as <div class="body-content">.
   min-height: 0 is the flexbox fix: without it a flex child defaults to
   min-height: auto and refuses to shrink, preventing inner scroll. */
div.body-content {
    background-color: var(--mo-page) !important;
    flex: 1 !important;
    min-height: 0 !important;
    display: flex !important;
    flex-direction: column !important;
    overflow: visible !important;
}

/* Scrollbar-Platz im Content-Scroll-Container IMMER reservieren → die Seite aendert ihre Breite
   NICHT, wenn der vertikale Scrollbar erscheint/verschwindet (z. B. beim Schliessen des
   „Neue Version"-Banners sprang sonst die ganze Content-Spalte ~15px breiter). .page-content ist
   der Scroll-Container (overflow-y:auto). */
#mo-page-content {
    scrollbar-gutter: stable;
}

/* About-Dialog: Schließen-× verlässlich oben rechts in die Ecke. Die scoped-Regel
   (.about-dialog__close { margin-left:auto }) greift am FluentButton-Host NICHT — Blazor setzt
   das Scope-Attribut [b-xxx] nicht auf die gerenderte <fluent-button>, daher rutschte das × direkt
   hinter den Titel statt in die Ecke. GLOBALE Regel (matcht per Klasse, ohne Scope) + absolute
   Positionierung relativ zum Header-Lockup. */
.about-dialog__header-lockup {
    position: relative;
}
.about-dialog__close {
    position: absolute !important;
    top: 0;
    right: 0;
    margin: 0 !important;
    color: var(--mo-muted);
}
.about-dialog__close:hover {
    color: var(--mo-ink);
}

/* ── App-Shell: full-height layout ──────────────────────────────────────────
   Blazor Fluent UI 4.14.2 renders:
     <FluentLayout>  → <div class="layout">
     <FluentStack>   → <div class="stack-horizontal"> (Orientation=Horizontal)
     <FluentBodyContent> → <div class="body-content">

   Setting div.layout to 100dvh as a flex-column gives the shell structure:
     [Header 48px fixed] → [middle row flex:1, min-height:0] → [Footer fixed]
   Without min-height:0 on flex children the browser refuses to shrink them
   below their intrinsic height → no inner scroll possible.

   Fallback: height:100vh for browsers without dvh support (Safari <15.4). */
div.layout {
    height: 100vh !important;
    height: 100dvh !important;
    display: flex !important;
    flex-direction: column !important;
    overflow: hidden !important;
}

/* App-Shell-Zeile (Sidebar + Content) zwischen Top-Bar und Footer.
   WICHTIG: gescoped auf .mo-app-row (Marker an der EINEN Shell-FluentStack in
   MainLayout). Früher traf der nackte Selektor div.stack-horizontal JEDEN
   horizontalen FluentStack der App → überall ein --mo-page-farbiger Kasten
   (unterschiedliche Schwarz-/Grautöne hinter Buttons/Toolbars). Jetzt nur noch
   die Shell.
   flex:1 + min-height:0 → füllt den Raum zwischen Header und Footer;
   overflow:visible → Dropdown-Panels werden nicht geclippt. */
div.stack-horizontal.mo-app-row {
    background-color: var(--mo-page) !important;
    flex: 1 !important;
    min-height: 0 !important;
    overflow: visible !important;
    /* Kein Gap zwischen Sidebar und Content-Bereich: sonst sitzt das Content-Banner 10px
       von der Sidebar ab (links 10px / rechts 0px = inkonsequent). Ohne Gap klebt der
       Content (inkl. Banner) buendig an der Sidebar; der Content-Gutter kommt allein aus
       dem 16px-Padding der .page-content (FluentStack-Param Gap=0 greift nicht durch). */
    gap: 0 !important;
}

/* FluentGrid-Gutter: FluentGrid Spacing="…" greift in 4.14.2 faktisch nicht
   (Grid-Items haben 0 padding → Eingabe-Felder kleben aneinander, „gequetscht").
   Wir erzeugen den Abstand selbst über Gutter-Padding an den Grid-Items
   (rechts + unten, box-sizing zählt es zur 25%/33%-Breite → kein Overflow).
   Greift global auf alle FluentGrids (Dialog-Sektionen, Ergebnis-Felder, Detail). */
.fluent-grid > div {
    padding-right: 14px;
    padding-bottom: 14px;
    box-sizing: border-box;
}

/* ==========================================================================
   13. Content-Breite-Wrapper-Klassen (§2 Content-Breite-Entscheidung)
       Seitentyp-abhängige max-width, IMMER linksbündig (margin-inline: 0).
       Sidebar liegt links → Scan-Weg bei sidebar + ~150px, nicht Mitte.
       Zentrierter Content "schwimmt" gegen die Nav — daher linksbündig.

       Verwendung:
         .mo-w-header → Cockpit-Kopf (Picker + KPI-Cards + Buttons): ≤1400px
         .mo-w-list   → Listen (Mitarbeiter): ≤1200px
         .mo-w-form   → Edit-Formulare + Tarif: ≤800px
         .mo-cockpit  → Lohnlauf-Cockpit (Roster-Scroll-Scope, KEIN max-width — voll-breit)
         Roster-DataGrid: KEIN Wrapper — bleibt voll-breit (scrollt intern via .mo-cockpit)

       Section-Header (L1 — §1 Defaults): CSS-Struktur hier, aber noch nicht
       sichtbar anzeigen (kommt mit Modul 2).
   ========================================================================== */

/* Cockpit-Kopf: Picker + 4 KPI-Cards + Buttons ≤ 1400px */
.mo-w-header {
    max-width: var(--modus-content-max-width-header, 1400px);
    margin-inline: 0;   /* linksbündig — kein auto-Zentrieren */
    padding-inline: var(--modus-content-padding-inline, clamp(16px, 3vw, 48px));
    box-sizing: border-box;
    width: 100%;
}

/* Listen (Mitarbeiter): ≤ 1200px */
.mo-w-list {
    max-width: var(--modus-content-max-width-list, 1200px);
    margin-inline: 0;
    padding-inline: var(--modus-content-padding-inline, clamp(16px, 3vw, 48px));
    box-sizing: border-box;
    width: 100%;
}

/* ── Mitarbeiter-Liste: nur die Tabellen-Rows scrollen, der Spaltenkopf (<th>) bleibt fix ──
   GLOBAL (nicht scoped): FluentStack/FluentDataGrid sind Kind-Komponenten und erhalten das
   CSS-Isolation-Scope-Attribut der Seite NICHT — scoped-Regeln auf .stack-vertical/.fluent-data-grid
   greifen daher nicht. .mo-w-list fuellt den (hoehen-begrenzten) #mo-page-content als Flex-Spalte;
   der innere FluentStack fuellt sie; die FluentDataGrid-<table> wird zum Scroll-Container
   (overflow-y:auto). Der sticky Header (§17, tr ohne aria-rowindex) bleibt dadurch oben stehen,
   waehrend nur die Datenzeilen scrollen. Titel + "Neu anlegen" stehen darueber und scrollen nicht mit.

   Doppel-Scrollbar-Fix: #mo-page-content (globaler Scroll-Wrapper) hat padding:1rem +
   box-sizing:border-box und enthaelt neben der Liste noch den 1px-#scroll-sentinel. Ein Kind mit
   height:100% ignoriert dieses Padding + die Sentinel-Hoehe → ~33px Overflow → der Wrapper bekam
   eine ZWEITE Scrollbar zusaetzlich zur Tabellen-Scrollbar. Loesung: Wenn die selbst-scrollende
   Voll-Hoehen-Liste gerendert wird, wird der Wrapper selbst zur Flex-Spalte und die Liste fuellt
   ihn via flex (padding-korrekt, kein Overflow) statt height:100%. Nur fuer .mo-w-list — andere
   Seiten (mo-w-header/mo-w-form) haben natuerliche Content-Hoehe und scrollen weiter normal. */
#mo-page-content:has(> .mo-w-list) {
    display: flex;
    flex-direction: column;
}

.mo-w-list {
    flex: 1 1 auto;   /* fuellt #mo-page-content (Flex-Spalte); ersetzt height:100% → kein Padding-Overflow */
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.mo-w-list > .mo-emp-stack {
    flex: 1 1 auto;
    min-height: 0;
}

.mo-w-list table.fluent-data-grid {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Sticky Spaltenkopf beim Scrollen: FluentDataGrid ist display:grid, die Header-ROW ist
   display:contents (boxlos) → position:sticky auf der Row (§17) wirkt NICHT. Daher die
   Header-ZELLEN sticky machen. Eigener Hintergrund nötig, da die Row-Fläche nicht rendert. */
.mo-w-list table.fluent-data-grid th.column-header {
    position: sticky;
    top: 0;
    z-index: 3;
    background-color: var(--mo-page);
}

/* Sortier-Buttons in sortierbaren Spaltenköpfen: FAST rendert sie als stealth-fluent-button
   mit Rest-Fläche --neutral-fill-stealth-rest (#FBFBFB hell) — hob sich als heller Kasten vom
   Header-Hintergrund (--mo-page #F4F5F6) ab. Rest-Fill an --mo-page angleichen → nahtloser
   Header. Grüne Text-Hervorhebung (stealth-foreground) und Hover/Active bleiben unverändert. */
.mo-w-list table.fluent-data-grid th.column-header fluent-button.col-sort-button {
    --neutral-fill-stealth-rest: var(--mo-page);
}

/* AVR-Jahr-Zelle mit Inline-<select>: das Select verursacht ~2px Overflow, wodurch die
   Zell-Ellipsis (text-overflow:ellipsis der übrigen Spalten) ein störendes „…" hinter dem
   Select rendert. Nur diese Zelle clippen — die Namens-Spalte soll weiter ellipsen. */
.mo-w-list table.fluent-data-grid [role="gridcell"]:has(.mo-inline-year) {
    text-overflow: clip;
}

/* ── Cockpit-Roster: nur das Roster-Grid scrollt (Kopf/Picker/KPI/Buttons fix) ──
   Exakt dasselbe Fill/Scroll-Konstrukt wie .mo-w-list, nur ohne max-width (das Roster ist
   voll-breit). GLOBAL (nicht scoped): FluentStack/FluentDataGrid sind Kind-Komponenten und
   erhalten das CSS-Isolation-Scope-Attribut (b-xxx) der Cockpit-Seite NICHT → scoped-Regeln
   greifen nicht. Die Cockpit-Wurzel (<FluentStack Class="mo-cockpit">) füllt den höhen-
   begrenzten #mo-page-content als Flex-Spalte; die Roster-<table> wird zum Scroll-Container
   (overflow-y:auto, überschreibt das globale table.fluent-data-grid{overflow:hidden} aus §17).
   Kopf (.mo-w-header), Aktions-Buttons und sticky Spaltenkopf bleiben oben stehen; nur die
   Datenzeilen scrollen — analog /employees.

   display:flex; flex-direction:column kommt aus FluentStacks Library-Klasse .stack-vertical
   (hier NICHT dupliziert — gleiche Annahme wie bei .mo-w-list > .mo-emp-stack).
   Doppel-Scrollbar-Fix identisch zu .mo-w-list: die selbst-scrollende Voll-Höhen-Liste füllt
   den padding-behafteten Wrapper via flex (min-height:0) statt height:100% → kein Overflow,
   keine zweite Scrollbar neben der Tabellen-Scrollbar. */
#mo-page-content:has(> .mo-cockpit) {
    display: flex;
    flex-direction: column;
}

.mo-cockpit {
    flex: 1 1 auto;
    min-height: 0;
}

.mo-cockpit table.fluent-data-grid[data-testid="roster-grid"] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;   /* wie .mo-w-list; Roster ist 8×1fr → passt in die Breite */
}

/* Sticky Spaltenkopf beim Roster-Scroll: die Header-ROW ist display:contents (boxlos) →
   position:sticky auf der Row (§17) wirkt NICHT. Daher die Header-ZELLEN sticky machen.
   Eigener Hintergrund nötig, da die Row-Fläche nicht rendert. */
.mo-cockpit table.fluent-data-grid[data-testid="roster-grid"] th.column-header {
    position: sticky;
    top: 0;
    z-index: 3;
    background-color: var(--mo-page);
}

/* Formulare (Edit, Tarif): ≤ 800px */
.mo-w-form {
    max-width: var(--modus-content-max-width-form, 800px);
    margin-inline: 0;
    padding-inline: var(--modus-content-padding-inline, clamp(16px, 3vw, 48px));
    box-sizing: border-box;
    width: 100%;
}

/* ── QW1: Inline-SVG-Icons (global, weil scoped b-xxx reicht nicht ins ChildContent-Slot) ──
   .mo-nav-icon liegt im Light-DOM ChildContent der FluentNavLink/FluentNavGroup-Komponente.
   Blazor scoped CSS erreicht es über [b-xxx] auf dem Host-Element nicht zuverlässig.
   Globale Regel ohne Scope-Attribut trifft es direkt. */
.mo-nav-icon {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    display: inline-block;
    vertical-align: middle;
    margin-right: 8px;
    margin-bottom: 1px;
    color: currentColor;
}

.mo-nav-icon--sub {
    width: 16px;
    height: 16px;
    margin-right: 6px;
}

/* Section-Header-Struktur (L1 — jetzt vorbereitet, aber noch NICHT sichtbar).
   Kommt sichtbar mit Modul 2. Wird hier als display:none-Klasse angelegt. */
.mo-nav-section-header {
    display: none; /* INTENTIONAL: erst ab Modul 2 anzeigen */
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--mo-muted-2);
    padding: 12px 16px 4px;
    pointer-events: none;
    user-select: none;
}

/* ==========================================================================
   14. Nav-Item-Styles — QW1–QW7 (GLOBAL, da FluentNavMenu 4.14.2 in Blazor WASM
       als reines HTML mit eigenen Scope-Attributen rendert; Blazor CSS Isolation
       von MainLayout.razor.css erreicht die inneren Elemente nicht).
   DOM-Struktur:
     div.mo-sidebar.fluent-nav-menu
       div.fluent-nav-item                              (NavLink-Wrapper)
         a.fluent-nav-link[.active]                     (NavLink)
           div.positioning-region
             div.content-region
               span.fluent-nav-icon                     (placeholder, leer lassen)
               div.fluent-nav-text                      (Label + unser SVG-Icon)
       div.fluent-nav-item.fluent-nav-group[.expanded]  (NavGroup-Wrapper)
         div.fluent-nav-link.notactive                  (Group-Header-Div)
           div.positioning-region
             div.content-region > div.fluent-nav-text   (Group-Titel + SVG-Icon)
             svg[class*="expand"]                       (Chevron)
         div.fluent-nav-menu                            (Sub-Items)
           div.fluent-nav-item > a.fluent-nav-link       (Sub-NavLink)
   ========================================================================== */

/* ── QW5: Zeilenhöhe Top-Level NavLink ── */
.fluent-nav-link {
    min-height: 44px;
    display: flex !important;
    align-items: center;
    box-sizing: border-box;
}

/* ── QW6: Top-Level-NavLink-Text: 14px/600, --mo-muted ── */
.fluent-nav-link > .positioning-region > .content-region > .fluent-nav-text,
.fluent-nav-link > .positioning-region .fluent-nav-text {
    color: var(--mo-muted);
    font-size: 14px;
    font-weight: 600;
}

/* ── QW3: Hover-Tint + Transition + border-radius ──
   Nur auf a.fluent-nav-link (echte Links), nicht auf Group-Header-Divs. */
a.fluent-nav-link:hover {
    background-color: var(--mo-green-tint-hover) !important;
    border-radius: var(--mo-radius-md) !important;
    margin-inline: 8px !important;
    /* margin-inline schrumpft die volle-Spalten-Breite des Links NICHT (FAST stretcht ihn) →
       Pill ragt 6px raus = horizontale Scrollbar in der Sidebar. max-width klemmt ihn auf
       Spalte minus beide Margins, border-box rechnet Border/Padding ein. */
    box-sizing: border-box !important;
    max-width: calc(100% - 16px) !important;
    transition: background var(--mo-motion-fast);
}

/* ── QW2: Aktiv-Markierung (Voll-Modus) ──
   EINZIGER Marker ist FASTs nativer Akzent-Balken (.positioning-region::before, schlanke
   grüne Linie links) + fetter Text (QW2-Text) — konsistent mit dem activeIndicator der
   Detail-Tabs. KEIN Fill und KEIN Custom-border-left (beides entfernt), damit nichts
   „drumherum" gebaut ist. Der native ::before rendert von selbst; wir blenden ihn NICHT
   mehr aus. Kein Layout-Prop hier (margin/max-width/radius waren nur für die alte Pille) →
   aktives Item bleibt bündig mit inaktiven.
   Rail-Modus: dort ist der native ::before per ~1686 ausgeblendet (überlagert sonst das
   zentrierte Icon) → für das aktive Item wird er rail-scoped wieder eingeblendet und links
   an gleicher Höhe wie hier gesetzt (s. Rail-Sektion „Rail-Aktiv-Balken"). */

a.fluent-nav-link.active .fluent-nav-text,
a.fluent-nav-link[aria-current] .fluent-nav-text {
    color: var(--mo-ink) !important;
    font-weight: 600 !important;
}

/* ── B4: Kein Doppelbox/Halo auf Nav-Link (Aktiv UND Hover) ──
   FAST setzt --neutral-fill-stealth-* auf der inneren .positioning-region / .content-region
   (Light + Dark) → zweite Fläche (off-white #FAFAFA) unter der grünen Tint-Pille auf dem
   `a`-Host. Beim Hover überdeckte sie sonst den grünen Hover-Tint = Halo/off-white statt grün.
   Lösung: innere Regions transparent machen — für aktiv UND hover (Light + Dark).
   §11 Dark-Stealth-Pins (globale --neutral-fill-stealth-* Overrides) bleiben unberührt. */
a.fluent-nav-link.active .positioning-region,
a.fluent-nav-link[aria-current] .positioning-region,
a.fluent-nav-link:hover .positioning-region,
a.fluent-nav-link.active .content-region,
a.fluent-nav-link[aria-current] .content-region,
a.fluent-nav-link:hover .content-region {
    background: transparent !important;
}

/* QW2 (Fortsetzung): FASTs nativer .positioning-region::before-Akzent bleibt im Voll-Modus
   sichtbar — er IST der Aktiv-Marker. (Frühere Voll-Modus-Unterdrückung entfernt.) Im Rail
   wird er weiterhin bei ~1686 ausgeblendet, weil er dort das zentrierte Icon überlagert. */

/* ── QW7: Keyboard-Focus-Ring auf Nav-Link ── */
a.fluent-nav-link:focus-visible {
    outline: 2px solid var(--mo-focus-ring) !important;
    outline-offset: -2px !important;
    border-radius: var(--mo-radius-md) !important;
}

/* ── QW5: Sub-Items in NavGroup: Zeilenhöhe 38px + Einrückung 24px ── */
.fluent-nav-group .fluent-nav-item > a.fluent-nav-link {
    min-height: 38px;
    padding-left: 24px;
}

/* ── QW6: Sub-Item-Text: 13px/400, --mo-ink-3 ── */
.fluent-nav-group .fluent-nav-item > a.fluent-nav-link .fluent-nav-text {
    font-size: 13px !important;
    font-weight: 400 !important;
    color: var(--mo-ink-3) !important;
}

/* ── QW6: Gruppen-Titel (div.fluent-nav-link.notactive = Group-Header-Div):
   14px/600/mixed-case/--mo-muted — konsistent zu Top-Level-NavLink-Labels.
   text-transform: uppercase entfernt (war Ursache für STAMMDATEN-Großschrift-Bug). ── */
.fluent-nav-group > .fluent-nav-link .fluent-nav-text {
    font-size: 14px !important;
    font-weight: 600 !important;
    color: var(--mo-muted) !important;
}

/* ── QW4: Chevron der Gruppe → rechts (margin-left: auto), Rotation bei expanded ── */
.fluent-nav-group > .fluent-nav-link {
    display: flex;
    align-items: center;
    cursor: pointer;
    min-height: 44px;
}

.fluent-nav-group > .fluent-nav-link .content-region {
    display: flex;
    align-items: center;
    flex: 1;
}

/* Der Expand-Pfeil (SVG-Chevron, rendert als letztes Kind in content-region) */
.fluent-nav-group > .fluent-nav-link svg:not(.mo-nav-icon),
.fluent-nav-group > .fluent-nav-link .fluent-expand-collapse-glyph {
    margin-left: auto;
    transition: transform 200ms ease;
    flex-shrink: 0;
}

.fluent-nav-group.expanded > .fluent-nav-link svg:not(.mo-nav-icon),
.fluent-nav-group.expanded > .fluent-nav-link .fluent-expand-collapse-glyph {
    transform: rotate(90deg);
}

/* ==========================================================================
   15. F-1 Accent-Fix — ::part-Override für Submit-Button + Aktiv-Switch
       LIVE-DIAGNOSE (DevTools @ 1920×1080): Submit-Button + Aktiv-Switch (ON)
       rendern MS-Blau (#036ac4) trotz :root-Override (§11).

       URSACHE: FAST setzt die accent-Tokens per-Element via DesignToken-JS
       (setValueFor → CSSOM setProperty auf dem Host), wodurch `--accent-fill-rest`
       IM SCOPE DER KOMPONENTE auf FAST-Blau #036ac4 zurückfällt — NICHT auf den
       :root-Wert #5A8A00. getComputedStyle(button)['--accent-fill-rest'] = #036ac4.
       Ein ::part-Override, der `var(--accent-fill-rest)` referenziert, liest daher
       im Part-Scope wieder das FAST-Blau — `!important` gewinnt die Kaskade, aber
       die Variable hat den falschen Wert.

       FIX: Im ::part-Override NICHT die FAST-gehijackten --accent-*-Tokens
       referenzieren, sondern die FAST-UNVERWALTETEN Modus-Tokens
       --mo-green-interactive (#5A8A00 Light / #A6D63D Dark) + --mo-on-green-i
       (#FFFFFF Light / #13230A Dark). Diese resolven im Komponenten-Scope korrekt
       (verifiziert: getComputedStyle(button)['--mo-green'] = #9CCC3C, unhijacked).
       Light/Dark erben automatisch über die --mo-*-Dark-Overrides (§ Dark-Block).
       ::part() penetriert den Shadow-DOM direkt (kein ::deep — natives Part-Targeting).
   ========================================================================== */

/* Accent-Button (inkl. Submit) — .control-Background + Border + Textfarbe grün.
   --mo-green-interactive (FAST-unverwaltet) statt --accent-fill-rest (FAST-gehijackt). */
fluent-button[appearance="accent"]::part(control) {
    background: var(--mo-green-interactive) !important;
    border-color: var(--mo-green-interactive) !important;
    color: var(--mo-on-green-i) !important;
}

/* Aktiv-Switch im ON-Zustand — Track grün. aria-checked ist die zuverlässigste
   FAST-Reflektion; current-checked + .checked als Sicherheitsnetz.
   WICHTIG: current-checked WERT-spezifisch matchen (="true"). FAST reflektiert
   current-checked IMMER als Attribut — auch im OFF-Zustand als current-checked="false".
   Der reine Präsenz-Selektor [current-checked] matchte damit BEIDE Zustände und
   färbte den OFF-Track fälschlich grün (deaktiviert sah aus wie aktiv). Mit ="true"
   greift Grün nur bei aktiv; der OFF-Track fällt auf den neutralen FAST-Basis-Track
   (--neutral-fill-input-alt-rest) zurück. */
fluent-switch[aria-checked="true"]::part(switch),
fluent-switch[current-checked="true"]::part(switch),
fluent-switch.checked::part(switch) {
    background: var(--mo-green-interactive) !important;
    border-color: transparent !important;
}

/* ==========================================================================
   15b. Input-System — fluent-number-field / fluent-text-field / fluent-select
        Behebt weiße Inputs im Dark-Mode (Roster-Grid + alle Dialoge/Formulare).
        Root-Cause: FAST leitet --neutral-fill-input-* algorithmisch aus
        --base-layer-luminance ab und liefert in Dark fast-weiße Werte.
        §11 pinnt --neutral-fill-input-* bereits, aber ::part(control) liest
        den FAST-Wert im Komponenten-Scope. Direktes Überschreiben via --mo-*
        (FAST-unverwaltet) ist zuverlässiger und theme-aware ohne separaten
        Dark-Block — --mo-surface/--mo-ink/--mo-border cascaden via §3.
        WICHTIG: outline nicht setzen → Focus-Ring (::part(control):focus-visible)
        bleibt FAST-verwaltet (grün via §11 --accent-stroke-control-*).
   ========================================================================== */

fluent-number-field::part(control),
fluent-text-field::part(control),
fluent-select::part(control) {
    background-color: var(--mo-surface) !important;
    color: var(--mo-ink) !important;
    border-color: var(--mo-border) !important;
}

/* fluent-select („outline") paintet seine Fläche ZUSÄTZLICH per background-image-Gradient
   (--neutral-fill-rest = #3d3d3d grau im Dark) ÜBER der background-color → grauer Kasten,
   der nicht mit der Karte/Dem Dialog verschmilzt. Der background-color-Override (oben) allein
   reicht NICHT, weil der Gradient darüber liegt (live verifiziert: bgImage = linear-gradient
   #3d3d3d). Gradient entfernen → die flache --mo-surface wird sichtbar (Light + Dark). */
fluent-select::part(control) {
    background-image: none !important;
}

/* Dark: Light-Logik gespiegelt → Feld = Karte = Dialog sind EIN Ton (--mo-surface #1B1E22,
   wie im Light alles Weiß ist). Die Trennung macht ein KLAR SICHTBARER Feld-Rahmen
   (#3E4654 — Dark-Pendant zum Light-Feldrahmen #D1D5DB), nicht eine Ton-Stufe.
   control + controls auf den Flächen-Ton → uniform; der Rahmen liegt auf dem control
   (Feld-Box). Inputs OHNE Karte (Roster-Grid) bleiben unverändert (§15b). */
body[data-theme="dark"] fluent-card fluent-number-field::part(control),
body[data-theme="dark"] fluent-card fluent-number-field::part(controls),
body[data-theme="dark"] fluent-card fluent-text-field::part(control),
body[data-theme="dark"] fluent-card fluent-select::part(control),
body[data-theme="system-dark"] fluent-card fluent-number-field::part(control),
body[data-theme="system-dark"] fluent-card fluent-number-field::part(controls),
body[data-theme="system-dark"] fluent-card fluent-text-field::part(control),
body[data-theme="system-dark"] fluent-card fluent-select::part(control) {
    background-color: var(--mo-surface) !important;
}

/* Sichtbarer Feld-Rahmen (nur control = Feld-Box, nicht controls) — definiert die Struktur. */
body[data-theme="dark"] fluent-card fluent-number-field::part(control),
body[data-theme="dark"] fluent-card fluent-text-field::part(control),
body[data-theme="dark"] fluent-card fluent-select::part(control),
body[data-theme="system-dark"] fluent-card fluent-number-field::part(control),
body[data-theme="system-dark"] fluent-card fluent-text-field::part(control),
body[data-theme="system-dark"] fluent-card fluent-select::part(control) {
    border-color: #3E4654 !important;
}

/* Zusätzlich den FAST-Token --neutral-fill-input-* selbst auf den Karten-Ton pinnen.
   Er ist im Dark grau (#3d3d3d, live gemessen) und färbt interne Feld-Box-Flächen, die
   ::part(control)/(controls) nicht erreichen → das „Grau um das Feld". So wird die ganze
   Feld-Box uniform mit der Karte. */
body[data-theme="dark"] fluent-card fluent-number-field,
body[data-theme="dark"] fluent-card fluent-text-field,
body[data-theme="dark"] fluent-card fluent-select,
body[data-theme="system-dark"] fluent-card fluent-number-field,
body[data-theme="system-dark"] fluent-card fluent-text-field,
body[data-theme="system-dark"] fluent-card fluent-select {
    --neutral-fill-input-rest: #1B1E22;
    --neutral-fill-input-hover: #1B1E22;
    --neutral-fill-input-active: #1B1E22;
    --neutral-fill-input-focus: #1B1E22;
    --neutral-fill-input-alt-rest: #1B1E22;
    --neutral-fill-input-alt-hover: #1B1E22;
    --neutral-fill-input-alt-active: #1B1E22;
    --neutral-fill-input-alt-focus: #1B1E22;
}

/* ==========================================================================
   15c. Surface-System — fluent-card (GLOBAL, alle Seiten)
        Root-Cause (Live-DOM verifiziert): FAST setzt --fill-color PER ELEMENT
        auf den fluent-card-Host (DesignToken.setValueFor), wodurch der §11-Dark-Pin
        (--fill-color: #1B1E22) im Card-Scope auf #FFFFFF zurückfällt → weiße Card
        auf dunklem Page-Grund (Monatsblatt, Personen-Detail-Saldo-Cards).
        Gleiche Klasse Bug wie Accent-Button §15 / Inputs §15b.
        FIX: Card-Hintergrund direkt auf das FAST-unverwaltete --mo-surface +
        --mo-hairline-Border setzen (theme-aware via §3). Eine Fläche, dezente
        Hairline-Trennung — konsistent mit Dialog-Cards (§16).
        Light bleibt korrekt (--mo-surface = #FFFFFF). ::part(control) deckt den
        Shadow-DOM-Hintergrundkasten ab, der Host die äußere Fläche/Border. */
fluent-card,
fluent-card::part(control) {
    background-color: var(--mo-surface) !important;
    border-color: var(--mo-hairline) !important;
    color: var(--mo-ink);
}

/* (Frühere Dark-Karten-Elevation auf #262B33 ENTFERNT — Light-Logik gespiegelt:
   Karte = Dialog = Feld sind jetzt EIN Ton (--mo-surface #1B1E22, via Basis-Regel oben),
   die Trennung machen sichtbare Rahmen (Feld #3E4654 §15b-dark, Karte --mo-hairline),
   genau wie im Light Feld/Karte/Dialog ein Weißton sind und Rahmen trennen.) */

/* ==========================================================================
   15d. Surface-System — fluent-accordion (GLOBAL)
        Root-Cause (Live-DOM verifiziert): FAST rendert fluent-accordion-item-Header
        (#3D3D3D) + Region/Inhalt (#2D2D2D) mit eigenen Neutral-Fills, die NICHT zur
        --mo-surface passen → grauer Kasten, der aus der Fläche heraussticht
        (z. B. das „Vollständiges Monatsblatt"-Accordion im Detail-Dialog).
        Gleiche Token-Instanz-Logik wie §15b (Inputs) / §15c (Cards).
        FIX: Accordion-Flächen auf --mo-surface, Hairline-Trennung. App-weit, theme-aware.
   ========================================================================== */
fluent-accordion,
fluent-accordion-item,
fluent-accordion-item::part(button),
fluent-accordion-item::part(heading),
fluent-accordion-item::part(region) {
    background: var(--mo-surface) !important;
    color: var(--mo-ink);
}

fluent-accordion-item {
    border-bottom: 1px solid var(--mo-hairline);
}

fluent-accordion-item::part(icon) {
    background: transparent !important;
    fill: var(--mo-muted);
}

/* ==========================================================================
   15e. Surface-System — fluent-select / fluent-option Flyout (GLOBAL)
        Root-Cause (Live-DOM verifiziert): das geöffnete Select-Flyout rendert mit
        FAST-Default-Grau (Listbox #333333, Optionen #272727, ausgewählt #383838),
        nicht zur --mo-surface passend → leicht abweichender Ton ggü. Dialog/Seite.
        FIX: Flyout-Fläche auf --mo-surface (Hairline + bestehender Schatten geben die
        Popup-Trennung), Optionen surface, Hover/Auswahl auf die Interaktions-Tokens
        (konsistent mit Roster/Nav). App-weit, theme-aware. */
fluent-select::part(listbox),
fluent-combobox::part(listbox),
fluent-listbox {
    background: var(--mo-surface) !important;
    border-color: var(--mo-hairline) !important;
}

fluent-option {
    background: var(--mo-surface) !important;
    color: var(--mo-ink);
}

fluent-option:hover {
    background: var(--mo-green-tint-hover) !important;
}

fluent-option[aria-selected="true"],
fluent-option.selected {
    background: var(--mo-green-tint-active) !important;
    color: var(--mo-ink) !important;
}

/* ==========================================================================
   16. Dialog (global) — #2b Scroll + z-index + #2c Dark-Surface
       Strang B — 2026-06-22

       DOM-Analyse (bundle.scp.css-Grep + Blazor WASM devserver @ localhost:9876):
       - fluent-dialog = Web-Component (beide Render-Pfade: IDialogService + inline @ref)
       - ::part(control) = Shadow-DOM-Teil mit dem weißen Hintergrundkasten
       - .fluent-dialog-header/.fluent-dialog-body/.fluent-dialog-footer = Light-DOM-Klassen
         im Slot des Shadow-Parts; greifen ohne ::part() via normaler Kaskade.
       - Standard-Modal: body liegt in CSS-Grid-Zeile (1fr), hat KEIN overflow-y: auto →
         scrollt nicht trotz 90vh-Höhe. Nur Panel-Dialoge (.right/.left) erhalten das
         overflow in der scoped Bundle-CSS — daher muss modus-theme.css es global ergänzen.
       - z-index: Scoped-Bundle setzt keinen z-index auf fluent-dialog. Das Overlay/Host
         rendert via FluentDialogProvider in einem <div> am body-Ende; fluent-dialog selbst
         und sein ::part(control) erhalten kein explizites z-index → Dialog kann unter
         sticky Header (z-index: 100, header.mo-topbar) verschwinden.
       - Best-effort-Abdeckung (kein Live-DevTools-Check möglich vom Agent-Kontext):
         Selektoren decken beide Render-Pfade und beide shadow/light-DOM-Flächen ab.
   ========================================================================== */

/* --- Dialog-Header-Focus-Ring entfernen ---
   Der Dialog-Header (Titel-DIV) wird beim Öffnen programmatisch fokussiert (Screenreader-
   Ansage) → grüner Focus-Ring (outline 2px #5A8A00) oben im Header. Da es kein vom Nutzer
   angesteuertes interaktives Element ist, blenden wir den sichtbaren Ring NUR dort aus.
   Buttons/Inputs/Nav/Close behalten ihren Focus-Ring (kein globaler Eingriff). */
.fluent-dialog-header > div:focus,
.fluent-dialog-header > div:focus-visible,
fluent-dialog .fluent-dialog-header > div:focus,
fluent-dialog .fluent-dialog-header > div:focus-visible {
    outline: none !important;
}

/* --- #2b Body-Scroll (Standard-Modal, 90vh Detail-Dialog) ---
     Im scoped Bundle fehlt overflow-y:auto für Standard-Modals (nur Panel .right/.left).
     min-height:0 verhindert flex/grid-Shrink-Problem in der 1fr-Grid-Zeile.
     Drei Selektor-Varianten: direkt auf Klasse, qualifiziert mit fluent-dialog,
     und der scoped-Äquivalent ohne Scope-Attribut (greift global). */
.fluent-dialog-body {
    overflow-y: auto !important;
    flex: 1 1 auto;
    min-height: 0 !important;
}

fluent-dialog .fluent-dialog-body {
    overflow-y: auto !important;
    min-height: 0 !important;
}

/* --- #2b z-index — Dialog-Host/Overlay ≥ 1000 ---
     Sichert, dass fluent-dialog (beide Render-Pfade) über dem sticky Roster-Header
     (z-index: 100, Strang C) und über header.mo-topbar (z-index: 100) liegt.
     [part="overlay"] = das halbtransparente Backdrop-Element des Web-Components. */
fluent-dialog {
    z-index: 1000 !important;
}

/* Overlay/Backdrop muss UNTER dem Dialog-Inhalt (::part(control), z-index:1) liegen,
   sonst fängt das bildschirmfüllende Overlay alle Klicks (→ Dialog schließt sich) und
   Scrolls (→ kein Scroll) ab. Es bleibt trotzdem im Stacking-Context des Hosts (z-index:1000
   am fluent-dialog), also weit über dem sticky Header (100). Darum hier z-index:0. */
fluent-dialog::part(overlay) {
    z-index: 0 !important;
}

.fluent-dialog-main {
    z-index: 1000 !important;
}

/* --- #2c Dark-Mode Dialog-Surface ---
     Mappt die Modal-Fläche (::part(control) = Shadow-DOM-Hintergrund + light-DOM-Slots)
     auf --mo-surface (#1B1E22) im Dark-Mode. Light-Mode UNVERÄNDERT (kein Selektor).
     Beide Render-Pfade werden abgedeckt:
       IDialogService-verwaltet (fluent-dialog als Web-Component, PayrollDetailDialog/Edit)
       Inline @ref (FluentDialog-Komponente, AboutDialog/YearEndRollover)
     In Fluent UI v4.14.2 setzt body[data-theme] den Wert "dark" oder "light" — ob
     "system-dark" als literal gesetzt wird ist unsicher (Review-Finding), daher
     zusätzlich @media (prefers-color-scheme: dark) Fallback (gescoped auf Nicht-Light). */

/* Explicit dark-theme toggle */
body[data-theme="dark"] fluent-dialog::part(control),
body[data-theme="system-dark"] fluent-dialog::part(control),
body[data-theme="dark"] .fluent-dialog-main,
body[data-theme="system-dark"] .fluent-dialog-main {
    background-color: var(--mo-surface) !important;
    color: var(--mo-ink);
}

body[data-theme="dark"] fluent-dialog .fluent-dialog-header,
body[data-theme="system-dark"] fluent-dialog .fluent-dialog-header,
body[data-theme="dark"] .fluent-dialog-header,
body[data-theme="system-dark"] .fluent-dialog-header {
    background-color: var(--mo-surface) !important;
    color: var(--mo-ink);
}

body[data-theme="dark"] fluent-dialog .fluent-dialog-body,
body[data-theme="system-dark"] fluent-dialog .fluent-dialog-body,
body[data-theme="dark"] .fluent-dialog-body,
body[data-theme="system-dark"] .fluent-dialog-body {
    background-color: var(--mo-surface) !important;
    color: var(--mo-ink);
}

body[data-theme="dark"] fluent-dialog .fluent-dialog-footer,
body[data-theme="system-dark"] fluent-dialog .fluent-dialog-footer,
body[data-theme="dark"] .fluent-dialog-footer,
body[data-theme="system-dark"] .fluent-dialog-footer {
    background-color: var(--mo-surface) !important;
    color: var(--mo-ink);
}

/* system-dark OS-Fallback: greift wenn kein expliziter data-theme gesetzt
   (user hat kein Toggle-Klick gemacht) oder data-theme="system-dark" nicht literal gesetzt.
   Gescoped auf body:not([data-theme="light"]) — verhindert Überschreiben des expliziten
   Light-Toggles. */
@media (prefers-color-scheme: dark) {
    body:not([data-theme="light"]):not([data-theme="dark"]) fluent-dialog::part(control) {
        background-color: var(--mo-surface) !important;
        color: var(--mo-ink);
    }

    body:not([data-theme="light"]):not([data-theme="dark"]) fluent-dialog .fluent-dialog-header,
    body:not([data-theme="light"]):not([data-theme="dark"]) .fluent-dialog-header {
        background-color: var(--mo-surface) !important;
        color: var(--mo-ink);
    }

    body:not([data-theme="light"]):not([data-theme="dark"]) fluent-dialog .fluent-dialog-body,
    body:not([data-theme="light"]):not([data-theme="dark"]) .fluent-dialog-body {
        background-color: var(--mo-surface) !important;
        color: var(--mo-ink);
    }

    body:not([data-theme="light"]):not([data-theme="dark"]) fluent-dialog .fluent-dialog-footer,
    body:not([data-theme="light"]):not([data-theme="dark"]) .fluent-dialog-footer {
        background-color: var(--mo-surface) !important;
        color: var(--mo-ink);
    }
}

/* --- C5: Dialog-interne FluentCards — eine Surface, Hairline-Trennung (Light + Dark) ---
     FluentCards im Dialog erhalten dieselbe Fläche wie der Dialog-Body (--mo-surface),
     sodass keine zweite elevierte Fläche entsteht. Trennung via Hairline statt Card-Schatten.
     Scope: nur innerhalb fluent-dialog → normale FluentCards auf anderen Seiten unberührt.
     Both light and dark covered via token-cascade (--mo-surface/--mo-hairline wechseln per
     body[data-theme] — kein separater Dark-Block nötig). */
fluent-dialog fluent-card,
fluent-dialog .fluent-card {
    background: var(--mo-surface) !important;
    box-shadow: none !important;
    border: 1px solid var(--mo-hairline) !important;
}

/* ==========================================================================
   16b. Dialog-Formulare — Eingabefelder vereinheitlichen (Live-DOM verifiziert)
        Root-Causes (FluentUI v4 4.14.2, im Anlegen-/Bearbeiten-Dialog gemessen):
        a) fluent-select rendert als display:inline-flex und ignoriert die volle
           Grid-Item-Breite → es war 8px breiter (250px) als die inline-block
           fluent-text-field/-number-field (242px) → rechte Kante ragte raus,
           Spalte wirkte asymmetrisch. Fix: width:100% + min-width:0 + border-box
           erzwingt identische Feldbreite (alle 242px, rechtsbündig).
        b) ::part(control)-corner-radius differierte (Textfelder 0px „eckig",
           Selects 4px „rund"). Fix: einheitlich --mo-radius-sm.
        c) fluent-switch-Label („Aktiv") erbte color:#FFFFFF → weiß auf weiß =
           unsichtbar im Light-Mode (im Dark zufällig sichtbar). Fix: --mo-ink.
        Scope: alle Dialog-Bodies (Konsistenz app-weit, betrifft nur Felder IM
        Dialog; Roster-Grid-Inputs liegen außerhalb .fluent-dialog-body).
   ========================================================================== */
.fluent-dialog-body fluent-text-field,
.fluent-dialog-body fluent-number-field,
.fluent-dialog-body fluent-select {
    width: 100% !important;
    min-width: 0 !important;
    box-sizing: border-box !important;
    /* Host-Radius rundet den Valid-/Focus-OUTLINE. Root-Cause (Live-DOM): FAST
       zeichnet den grünen Valid-Rahmen der Text-/Number-Felder als OUTLINE auf
       dem HOST (border-radius war 0 → eckiger Rahmen), während fluent-select den
       Rahmen auf ::part(control) (radius 4px) trägt → rund. Host-Radius
       vereinheitlicht beide. (::part(control)/(root) unten ergänzen die Box selbst.) */
    border-radius: var(--mo-radius-sm, 4px) !important;
}

.fluent-dialog-body fluent-text-field::part(control),
.fluent-dialog-body fluent-number-field::part(control),
.fluent-dialog-body fluent-text-field::part(root),
.fluent-dialog-body fluent-number-field::part(root),
.fluent-dialog-body fluent-select::part(control) {
    border-radius: var(--mo-radius-sm, 4px) !important;
    box-sizing: border-box !important;
}

.fluent-dialog-body fluent-switch::part(label) {
    color: var(--mo-ink) !important;
}

/* „Aktiv"-Switch als reguläres Feld (Markup: <div.mo-switch-field> mit
   <label.fluent-input-label> + bare FluentSwitch, siehe EmployeeEditDialog.razor).
   Vorher: FluentSwitch mit inline-Label saß oben in der Zelle (auf Label-Höhe) →
   wirkte „aufgesetzt", nicht in der Eingabezeile. Jetzt: Label oben wie die übrigen
   Felder, Toggle in die 32px-Input-Zeile zentriert → bündig mit dem Nachbar-Input. */
.fluent-dialog-body .mo-switch-field {
    /* „Aktiv" als vollbreite Zeile ganz unten im Dialog, Label links neben dem Toggle,
       die Gruppe horizontal in der gesamten Dialogbreite zentriert. */
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
}

/* in der Inline-Variante kein Label-Unterabstand (fluent-input-label bringt margin-bottom mit) */
.fluent-dialog-body .mo-switch-field .fluent-input-label {
    margin-bottom: 0;
}

.fluent-dialog-body .mo-switch-field fluent-switch {
    min-height: 32px;
    display: inline-flex;
    align-items: center;
}

/* leeres internes FAST-Label entfernen — Beschriftung kommt vom <label.fluent-input-label> */
.fluent-dialog-body .mo-switch-field fluent-switch::part(label) {
    display: none;
}

/* Select-/Combobox-Flyout darf den Dialog-Body verlassen (nicht clippen).
   Root-Cause (Live-DOM): .fluent-dialog-body hat overflow:auto. Das absolut
   positionierte Listbox-Popup öffnet bei mittiger Dialog-Lage nach oben und
   wurde an der Body-Oberkante abgeschnitten → obere Gruppen (I–IV) unerreichbar,
   wirkte wie „nicht scrollbar". Auch der grüne Validator-Focus-Ring wurde an
   der linken Body-Kante beschnitten. overflow:visible behebt beides.
   GESCOPED via :has() auf den Mitarbeiter-Dialog (eindeutiger Submit-Button),
   damit lange Dialoge (z. B. Monatsblatt-Detail) ihren internen Scroll behalten.
   overflow-y/-x als Longhand (Shorthand wurde von spezifischerer FAST-Regel
   geschlagen — live verifiziert). */
.fluent-dialog-body:has(#employee-edit-dialog-submit) {
    overflow-x: visible !important;
    overflow-y: visible !important;
}

/* ==========================================================================
   17. Roster-Grid (Cockpit) — global, NICHT scoped (Strang C, 2026-06-22)

       Grund (DOM-verifiziert, FluentUI v4 4.14.2): FluentDataGrid rendert sein
       <table class="fluent-data-grid"> in einem EIGENEN CSS-Isolation-Scope.
       Cockpits ::deep-Scope-Attribut (b-coctab...) landet NICHT auf einem
       Vorfahren der Grid-Zeilen — daher greifen scoped ::deep-Regeln nicht.
       Hier global gekeyt auf table.fluent-data-grid (nur das Roster,
       NICHT die Mitarbeiterliste). Reales DOM:
         table.fluent-data-grid > tbody > tr.fluent-data-grid-row
         Header-<tr>: KEIN aria-rowindex, enthält <th class="column-header">
         Daten-<tr>:  MIT aria-rowindex, enthält <td role="gridcell">
       EIN Interaktions-Farbsystem (Review §2): Hover/Aktiv/Focus = --mo-*-Tokens,
       konsistent mit Nav. Markierte Zeile (.mo-row--active) = im Detail-Dialog
       geöffnet; grüner inset-shadow = Brückenmuster zur Nav-border-left.
   ========================================================================== */

table.fluent-data-grid {
    width: 100%;
    background-color: var(--mo-surface);
    border: 1px solid var(--mo-hairline);
    border-radius: var(--mo-radius-md);
    overflow: hidden;
}

/* Header-Zeile: sticky, z-index 100 (unter Dialog 1000). Header-<tr> = kein aria-rowindex. */
table.fluent-data-grid tr.fluent-data-grid-row:not([aria-rowindex]) {
    position: sticky;
    top: 0;
    background-color: var(--mo-page) !important;
    z-index: 100;
    border-bottom: 2px solid var(--mo-border);
}

table.fluent-data-grid th.column-header {
    color: var(--mo-muted);
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

table.fluent-data-grid th.column-header svg,
table.fluent-data-grid th.column-header [class*="sort"] {
    color: var(--mo-green-interactive);
    fill: var(--mo-green-interactive);
}

/* Auftraggeber-Wunsch: ALLE Header mittig (konsistent, NICHT an die Spalten-Ausrichtung
   gekoppelt — das „links/rechts/mittig gemischt" stoerte). FluentDataGrid setzt am Wrapper-
   <div> inline justify-content (flex-start/center/flex-end) pro Column.Align → mit !important
   auf center ueberschreiben; .col-title zentrieren. */
table.fluent-data-grid th.column-header > div { justify-content: center !important; }
table.fluent-data-grid th.column-header .col-title { text-align: center !important; }

/* Datenzeilen */
table.fluent-data-grid tr.fluent-data-grid-row[aria-rowindex] {
    transition: background-color var(--mo-motion-fast);
    /* B2: Kante-zu-Kante Zeilen-Trenner auf der Row (statt Cell-border-bottom → keine Doppellinie) */
    border-bottom: 1px solid var(--mo-hairline);
}

/* Zebra-Striping (Datenzeilen) */
table.fluent-data-grid tr.fluent-data-grid-row[aria-rowindex]:nth-of-type(odd) {
    background-color: var(--mo-surface);
}

table.fluent-data-grid tr.fluent-data-grid-row[aria-rowindex]:nth-of-type(even) {
    background-color: var(--mo-surface-2);
}

/* Hover-Zeile (Review-Token --mo-green-tint-hover) */
table.fluent-data-grid tr.fluent-data-grid-row[aria-rowindex]:hover {
    background-color: var(--mo-green-tint-hover) !important;
}

/* Aktiv-Zeile = Detail-Dialog offen (Review §2 — markierte Zeile).
   NACH Zebra + Hover → !important schlägt Zebra; inset-shadow-Kante immer sichtbar. */
table.fluent-data-grid tr.fluent-data-grid-row.mo-row--active,
table.fluent-data-grid tr.fluent-data-grid-row[aria-selected="true"] {
    background-color: var(--mo-green-tint-active) !important;
    box-shadow: inset 3px 0 0 var(--mo-green);
}

/* Focus-Ring (Tab-Navigation) */
table.fluent-data-grid tr.fluent-data-grid-row[aria-rowindex]:focus-within {
    outline: 2px solid var(--mo-focus-ring);
    outline-offset: -2px;
}

/* Datenzellen */
table.fluent-data-grid td[role="gridcell"] {
    color: var(--mo-ink);
    /* Zeilen-Trenner liegt auf der ZELLE: der Row-Border (oben, 1341) rendert NICHT, weil die
       <tr> display:contents ist (kein Box). Damit die Linie durchgehend ist (keine Luecken),
       muss die Zelle ihre Grid-Spur fuellen → justify-self:stretch. Die Spalten-Ausrichtung
       des Inhalts kommt aus text-align (pro Column.Align), nicht aus dem Schrumpfen der Zelle.
       Farbe = --mo-hairline statt FAST-Default-Grau (#3D3D3D). */
    border-bottom: 1px solid var(--mo-hairline) !important;
    justify-self: stretch !important;
}

/* Tarif-Tabelle ist eine rohe <table> (kein FluentDataGrid) → Zebra + Hover separat,
   damit sie zum Roster/Liste-Grid passt. Karten-Fläche/Rahmen/Header kommen bereits aus
   der generischen [data-testid$="-grid"]-Regel bzw. den Inline-Header-Styles. */
/* (Tarif nutzt jetzt FluentDataGrid und wird von den generischen Grid-Regeln oben
   mitgestylt - keine Sonderregel mehr noetig.) */

/* Tablet: touch-freundlichere Zeilenhöhe */
@media (min-width: 768px) and (max-width: 1199px) {
    table.fluent-data-grid tr.fluent-data-grid-row[aria-rowindex] {
        height: 44px;
    }
}

/* ==========================================================================
   18. FluentMessageBar — Box-Modell-Überlauf
       Root-Cause (live verifiziert, Jahresabschluss-Seite): FAST rendert die
       MessageBar mit box-sizing:content-box + width:100% (→ Container-Breite) PLUS
       Padding 2×12px + Border 2×1px obendrauf → 26px breiter als der Container
       (z. B. .mo-w-form 800px → MessageBar 826px) → horizontale Scrollbar.
       Fix: border-box, damit width:100% Padding+Border einschließt → passt exakt.
       Gilt global für alle MessageBars (Rollover-Hinweis u. a.). */
.fluent-messagebar {
    box-sizing: border-box;
    max-width: 100%;
}

/* ==========================================================================
   19. A11y-Utilities
   ========================================================================== */

/* ==========================================================================
   20. Rail-Collapsed — persistenter 56px-Icon-Rail via .mo-rail-collapsed
       Wird durch _railCollapsed C#-State gesetzt (MainLayout.razor @code B2).
       Gilt GLOBAL (wie §14 Nav-Item-Styles) weil FluentNavMenu 4.14.2 eigene
       Scope-Attribute setzt — Blazor scoped CSS von MainLayout.razor.css
       erreicht die inneren Elemente nicht.

       Verhältnis zur Tablet-Rail (MainLayout.razor.css @media 768–1199):
       - Tablet-Media-Query: erzwingt Rail UNTERHALB 1200px (immer).
       - .mo-rail-collapsed-Klasse: gilt AB 1200px (oder zusammen mit Tablet-Rail
         — additive Regeln, kein Konflikt). Der User-Toggle ist persistent und
         unabhängig vom Viewport. Beide Rail-Zustandsquellen nutzen dieselben
         Selektoren, da .mo-rail-collapsed auf .mo-sidebar sitzt.
   ========================================================================== */

/* ── Sidebar-Breite auf 56px klemmen ── */
.mo-sidebar.mo-rail-collapsed {
    width: 56px !important;
    min-width: 56px !important;
    overflow: hidden !important;
    transition: width 180ms ease !important;
}

/* fluent-nav-menu-Host spiegelt dieselbe Breite (wie Tablet-Media-Query) */
.mo-sidebar.mo-rail-collapsed .fluent-nav-menu,
.mo-rail-collapsed.fluent-nav-menu {
    width: 56px !important;
    min-width: 56px !important;
    overflow: hidden !important;
}

/* ── Breiten-Transition auch im Nicht-Collapsed-Zustand (smooth expand) ── */
.mo-sidebar {
    transition: width 180ms ease;
}

/* ── Nav-Links im Rail: nur Icon, Label per opacity ausgeblendet (A11y-Name bleibt) ── */
.mo-sidebar.mo-rail-collapsed .fluent-nav-link,
.mo-rail-collapsed.fluent-nav-menu .fluent-nav-link {
    overflow: hidden;
    white-space: nowrap;
    min-height: 44px;
    justify-content: center;
    margin-inline: 0 !important;
    border-radius: 0 !important;
}

/* ── Rail-Icon WIRKLICH zentrieren ──
   justify-content auf dem <a> reicht nicht: das Icon steckt in .positioning-region/
   .content-region, und der AKTIVE Link erbt padding-left/border-left/max-width (§14)
   → Icon wandert nach rechts aus der 56px-Rail (overflow:hidden) und ist „leer"
   (oberstes = aktives Lohnlauf, unterstes = Jahresabschluss). Padding/Border/max-width
   neutralisieren + die inneren FAST-Regionen zentrieren. */
.mo-sidebar.mo-rail-collapsed .fluent-nav-link,
.mo-sidebar.mo-rail-collapsed .fluent-nav-link.active {
    padding-left: 0 !important;
    padding-right: 0 !important;
    border-left-width: 0 !important;
    max-width: 100% !important;
}
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .positioning-region,
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .content-region {
    justify-content: center !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    width: 100% !important;
}

/* ── Rail-Icon-Farbe: im Rail ist das Icon der EINZIGE Inhalt → klar sichtbar (--mo-ink).
   Das matte --mo-muted (#8B929C) ist im Dark zu schwach; der Stammdaten-Anchor erbte
   color:inherit → schwarz (im Dark unsichtbar). Aktiv-Item bleibt durch den nativen
   Akzent-Balken (::before, rail-scoped, s. „Rail-Aktiv-Balken") markiert. */
.mo-sidebar.mo-rail-collapsed .mo-nav-icon {
    color: var(--mo-ink) !important;
}

/* ── Rail-Aktiv-Balken (links, IDENTISCH zum ausgeklappten Zustand) ──
   Auch im eingeklappten Rail derselbe schlanke vertikale Balken wie im Voll-Modus, an der
   linken Kante. WICHTIG: exakt DIESELBE vertikale Position wie ausgeklappt übernehmen —
   FASTs Default ist top:-0.5px (oben ausgerichtet), NICHT auf Icon-Mitte zentriert. Ein
   Zentrieren (top:50%) ließ den Balken ggü. ausgeklappt ~9px tiefer sitzen („links unten").
   Daher hier top:-0.5px / transform:none wie im Voll-Modus. FASTs ::before ist im Rail per
   ~1686 ausgeblendet → für das AKTIVE Item wieder einblenden (left:0 hält ihn an der Kante,
   nicht über dem zentrierten Icon). */
.mo-sidebar.mo-rail-collapsed a.fluent-nav-link.active .positioning-region::before,
.mo-sidebar.mo-rail-collapsed a.fluent-nav-link[aria-current] .positioning-region::before {
    display: block !important;
    position: absolute !important;
    left: 0 !important;
    right: auto !important;
    top: -0.5px !important;
    bottom: auto !important;
    transform: none !important;
    width: 3px !important;
    height: 16px !important;
}

/* Leeren FAST-Icon-Slot (.fluent-nav-icon, ungenutzt da Icon im ChildContent) ausblenden,
   sonst nimmt er 20px ein → schiebt das echte Icon aus der Mitte. Rest-Margins null. */
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .fluent-nav-icon {
    display: none !important;
}
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .content-region,
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .mo-nav-icon,
.mo-sidebar.mo-rail-collapsed .mo-stammdaten-anchor .mo-nav-icon {
    /* margin-right:8px (§14 Label-Abstand) auch beim Stammdaten-Anker nullen, sonst zählt
       das Icon+Margin als Block → Icon ~4px links der Mitte (war center 26 statt 30). */
    margin: 0 !important;
}
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .mo-nav-icon {
    display: block !important;
}

/* FAST-Aktiv-Akzent (.positioning-region::before, 3px×16px grüner Balken, position:absolute)
   im Rail generell ausblenden: durch die Icon-Zentrierung landet seine Static-Position mittig
   → liegt quer über dem Icon. Für das AKTIVE Item wird er weiter oben („Rail-Aktiv-Balken")
   rail-scoped wieder eingeblendet und links positioniert. */
.mo-sidebar.mo-rail-collapsed .fluent-nav-link .positioning-region::before {
    display: none !important;
}

/* Label-TEXT ausblenden, aber das Icon-SVG sichtbar + zentriert behalten.
   WICHTIG: Der Lead legt das Icon ins ChildContent → FAST rendert es MIT in
   .fluent-nav-text (zusammen mit dem Label-Text). Das frühere opacity:0/width:0
   versteckte daher AUCH das Icon (= leere oberste/unterste Rail-Icons, ragten bei x:49
   aus der Rail). Fix: font-size:0 entfernt nur den Textknoten; das 20px-SVG (feste
   Attribut-Größe) bleibt, und .fluent-nav-text wird zur zentrierten Icon-Hülle.
   display:none wäre falsch (Accessible Name bleibt via Tooltip/aria erhalten). */
.mo-sidebar.mo-rail-collapsed .fluent-nav-text,
.mo-rail-collapsed.fluent-nav-menu .fluent-nav-text {
    font-size: 0 !important;
    opacity: 1 !important;
    width: 100% !important;
    margin: 0 !important;
    display: flex;
    justify-content: center;
    overflow: hidden;
}

/* ── Nav-Group-Header im Rail ausblenden (Icon bleibt via §14 .mo-nav-icon sichtbar) ── */
.mo-sidebar.mo-rail-collapsed .fluent-nav-group > div.fluent-nav-link,
.mo-rail-collapsed.fluent-nav-menu .fluent-nav-group > div.fluent-nav-link {
    display: none;
}

/* ── Toggle-Kopf im Rail: Toggle-Button zentrieren ── */
.mo-sidebar.mo-rail-collapsed .mo-sidebar-head {
    justify-content: center;
    padding: 8px 0 4px;
}

/* ── Smile im Rail zentrieren ── */
.mo-sidebar.mo-rail-collapsed .mo-sidebar-smile {
    padding: 4px 0 8px;
}

/* ── Reduced-motion: alle Rail-Transitions deaktivieren ── */
@media (prefers-reduced-motion: reduce) {
    .mo-sidebar,
    .mo-sidebar.mo-rail-collapsed,
    .mo-sidebar.mo-rail-collapsed .fluent-nav-text,
    .mo-rail-collapsed.fluent-nav-menu .fluent-nav-text {
        transition: none !important;
    }
}

/* ==========================================================================
   C2 — Stammdaten-Rail-Flyout-Popover
   Nur aktiv wenn _railCollapsed == true (Kondition im Markup; Anker bleibt im
   overflow:hidden-Rail-Container, Flyout escapet per position:fixed).

   Clipping-Lösung: Das Flyout (.mo-stammdaten-flyout) ist position:fixed.
   Der Rail-Container hat overflow:hidden — ein absolut-positioniertes Child
   würde geclippt. Fixed-Positionierung hebt das Element aus dem Stacking-
   Kontext der Sidebar heraus und rendert es relativ zum Viewport, also
   RECHTS der 56px-Rail ohne Clipping.
   ========================================================================== */

/* ── Anker-Wrapper: kein Clip, kein overflow:hidden (nur Stacking-Kontext) ── */
.mo-stammdaten-anchor-wrap {
    position: relative;
}

/* ── Anker-Button: visuell wie ein FluentNavLink im Rail (Icon zentriert, 44px min-height) ── */
.mo-stammdaten-anchor {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 44px;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--mo-ink); /* war inherit → schwarz/unsichtbar im Dark; Icon = currentColor */
    /* Pill-Hover analog zu den anderen Nav-Links */
    border-radius: 0;
}

.mo-stammdaten-anchor:hover,
.mo-stammdaten-anchor:focus-visible {
    background: var(--mo-green-tint-hover, rgba(90, 138, 0, 0.08));
    outline: none;
}

.mo-stammdaten-anchor:focus-visible {
    outline: 2px solid var(--accent-fill-rest, #5A8A00);
    outline-offset: -2px;
}

/* ── Flyout-Popover: position:fixed, rechts der 56px-Rail ── */
.mo-stammdaten-flyout {
    position: fixed;
    left: 56px;         /* unmittelbar rechts des 56px-Rails */
    z-index: 1000;
    min-width: 180px;
    background: var(--mo-surface, #fff);
    border: 1px solid var(--mo-hairline, rgba(0, 0, 0, 0.1));
    border-radius: var(--mo-radius-md, 6px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.08);
    padding: 4px 0;
    /* Öffnen-Animation (fade+slide) — reduced-motion deaktiviert sie unten */
    animation: mo-flyout-in 120ms ease-out;
}

@keyframes mo-flyout-in {
    from {
        opacity: 0;
        transform: translateX(-6px);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* ── Flyout-Header: nicht-interaktiver Gruppen-Name ── */
.mo-stammdaten-flyout-header {
    padding: 8px 16px 4px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--neutral-foreground-hint, #767676);
    pointer-events: none;
    user-select: none;
}

/* ── Flyout-Items: Links die wie Nav-Pill-Items aussehen ── */
.mo-stammdaten-flyout-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    text-decoration: none;
    color: inherit;
    font-size: 0.875rem;
    cursor: pointer;
    border-radius: 0;
    white-space: nowrap;
}

.mo-stammdaten-flyout-item:hover,
.mo-stammdaten-flyout-item:focus-visible {
    background: var(--mo-green-tint-hover, rgba(90, 138, 0, 0.08));
    outline: none;
}

.mo-stammdaten-flyout-item:focus-visible {
    outline: 2px solid var(--accent-fill-rest, #5A8A00);
    outline-offset: -2px;
}

/* ── Dark-Mode: Flyout-Oberfläche via vorhandene Tokens automatisch ── */
/* var(--mo-surface) + var(--mo-hairline) + var(--mo-green-tint-hover) passen
   sich automatisch an, wenn die Dark-Tokens gesetzt sind (FluentDesignTheme). */

/* ── Reduced-motion: Flyout-Animation deaktivieren ── */
@media (prefers-reduced-motion: reduce) {
    .mo-stammdaten-flyout {
        animation: none;
    }
}

/* Screen-reader-only — visually hidden, im A11y-Tree sichtbar (Accessible-Name-Quelle).
   Projekt-eigener Helper (Bootstrap .visually-hidden ist nicht geladen). */
.mo-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
