h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid var(--error-color);
}

.validation-message {
    color: var(--error-color);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4SiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* ---- Wiederverwendbare Seiten-Struktur (Fluent-Tokens) ----
   .admin-page ist der Standard-Seitenrahmen fuer Modul-/Verwaltungsseiten.
   Die eigentlichen Eintraege werden ueber Win11Row/Win11BarList dargestellt
   (Konzept/Fluent-UX-Konzept.md Abschnitt 10), nicht mehr ueber eigene
   Kachel-Komponenten. Farben ausschliesslich ueber Fluent-Tokens. */
/* Seiten setzen bewusst KEIN eigenes Padding - der Aussenabstand kommt
   ausschliesslich aus .app-content (app-shell.css). So beginnen Inhalte auf
   jeder Seite exakt an derselben Stelle wie auf der Startseite. */
.admin-page {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* .page-header bringt bereits seinen eigenen margin-bottom von 1.5rem mit
   (siehe .page-header weiter unten) - das darf sich innerhalb von
   .admin-page NICHT einfach zum Flex-gap (1rem) addieren, sonst waere der
   Abstand zum ersten Content-Element hier doppelt so gross wie bei
   PageHeader-Verwendung OHNE .admin-page-Wrapper (z.B. Module.razor).
   Stattdessen wird die Restmarge so gesetzt, dass Gap (1rem) + Restmarge
   (0.5rem) wieder exakt die 1.5rem ergeben, die PageHeader auch ausserhalb
   von .admin-page erzeugt - so ist der Abstand Ueberschrift-zu-Content auf
   JEDER Seite identisch, unabhaengig vom umschliessenden Wrapper. */
.admin-page > .page-header {
    margin-bottom: 0.5rem;
}

.admin-subline {
    color: var(--neutral-foreground-secondary);
    margin-top: -0.5rem;
    margin-bottom: 1.5rem;
}

/* ---- Seitenkopf: Breadcrumb (Win-11-Explorer) + Titel + Aktionen ----
   Wird ausschliesslich ueber die Komponente PageHeader.razor erzeugt, damit
   jede Seite denselben Kopf hat (kein seitenspezifischer Zurueck-Button). */
.page-header {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    /* Abstand zum nachfolgenden Content-Bereich - bewusst hier zentral am
       Seitenkopf selbst gesetzt (nicht ueber gap eines umschliessenden
       Wrapper-Divs), damit JEDE Seite denselben Windows-11-typischen
       Abstand (24px) zwischen Untertitel und Content bekommt, auch wenn
       PageHeader ohne .admin-page-Wrapper verwendet wird. */
    margin-bottom: 1.5rem;
}

.page-header-bar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
}

.page-title {
    margin: 0;
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--neutral-foreground-rest);
}

.page-subtitle {
    margin: 0.375rem 0 0;
    font-size: 0.8rem;
    color: var(--neutral-foreground-secondary);
}

/* Aktionsleiste im Seitenkopf (PageHeader.Actions) - fuer globale, seiten-
   weite Kopf-Aktionen (aktuell kaum genutzt). Liegende Content-Aktionen wie
   "Standort"/"Standorttyp" gehoeren NICHT hierher, sondern in eine eigene
   ContentToolbar UNTERHALB des PageHeader (siehe .content-toolbar,
   ContentToolbar.razor) - analog zu GitHub: Seitenkopf und Listen-Toolbar
   sind zwei getrennte Zeilen. Bricht bei wenig Platz um, OHNE die Buttons
   dabei zu strecken (bewusst kein flex:1 1 auto/width:100% - Buttons sollen
   beim Umbrechen ihre natuerliche Groesse behalten, nicht breiter werden). */
.page-header-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* Content-Toolbar (ContentToolbar.razor) - eigene Zeile UNTER dem PageHeader
   fuer Listen-/Seiten-Aktionen (z.B. "Standort"/"Standorttyp" auf
   Standorte.razor). Liegt bewusst direkt auf dem Seiten-Content, ohne
   umschliessendes SurfaceCard/Win11Table-Element (anders als z.B. die
   "Generieren"-Toolbar von Win11Table, die bewusst Teil des Tabellenrahmens
   bleibt - das ist NICHT das Muster fuer normale Seiten-Aktionen). Gleiches
   Umbruchverhalten wie .page-header-actions: bei wenig Platz bricht die
   Zeile um, die Buttons behalten dabei ihre natuerliche Groesse. Bewusst
   OHNE eigenen margin-bottom: der Abstand zum nachfolgenden Content kommt
   ausschliesslich aus dem Flex-gap (1rem) von .admin-page, sonst wuerde
   sich Gap + eigener Margin zu einem doppelt so grossen Abstand addieren. */
.content-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* Schiebt einen einzelnen ContentToolbar-Button ganz nach rechts (z.B.
   "Alle Versionen zuruecksetzen" auf Versionen.razor), waehrend die
   uebrigen Buttons/die SelectionActionBar links beieinander bleiben.
   Nur fuer vereinzelte, seltene Aktionen gedacht - nicht der Normalfall
   fuer generische Listen-Toolbars. */
.content-toolbar-push-right {
    margin-left: auto;
}

/* Hinweis: Das fruehere zwei-/dreispaltige Grid fuer Win11-Zeilen-
   Uebersichten (.win11-two-col/.win11-three-col) wurde durch die
   wiederverwendbare Komponente Win11ColumnGroup (siehe
   Components/Win11ColumnGroup.razor(.css)) abgeloest - CSS-Grid statt
   Flexbox, damit einzelne Win11BarList-Bloecke gezielt per Span-Parameter
   ueber mehrere Spalten spannen koennen. Seiten schreiben seitdem
   <Win11ColumnGroup MaxColumns="2"|"3"> statt eine CSS-Klasse zu kennen. */

/* ---- Sektions-Ueberschriften unterhalb des Seitentitels (.page-title) ----
   Fuer inhaltliche Unterteilungen INNERHALB einer Seite/Surface (z.B. auf
   Profil.razor "Persoenliche Einstellungen", "Geschaeftsdaten"). Bewusst
   ueber eine eigene Klasse statt ueber den Tag-Namen (h2/h3) selektiert:
   die Optik haengt NIE am Heading-Level, nur das semantisch korrekte Tag
   variiert je nach Verschachtelungstiefe (siehe SurfaceHeader.HeadingLevel).
   Aktuell identisch zur Groesse von .styleguide-entry-text h3 (Doku-Text im
   Style Guide) - falls .section-title spaeter eine eigene Groesse braucht,
   hier anpassen, ohne den Style-Guide-Doku-Text zu beruehren. */
.section-title {
    margin: 0 0 0.35rem 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--neutral-foreground-rest);
}

/* Abstand zwischen mehreren direkt untereinander liegenden Win11BarList-
   Bloecken auf Modul-Uebersichtsseiten (z.B. Verkauf.razor, Stammdaten.razor,
   Personal.razor). Diese Bloecke werden bewusst NICHT mehr mit einer eigenen
   Zwischenueberschrift (ehemals .pos-group-title) gruppiert, sondern liegen
   direkt nebeneinander im DOM und erhalten nur noch Abstand zueinander.
   Bewusst GLOBAL statt in einer seitenspezifischen *.razor.css: die Regel
   wird auf mehreren Modul-Uebersichtsseiten benoetigt, scoped CSS (Blazor
   CSS-Isolation) haette sie aber nur auf der Seite wirksam gemacht, in der
   sie urspruenglich definiert wurde (siehe SurfaceCard.razor.css
   .surface-card-footer-btn fuer dasselbe Muster/denselben Fehlversuch). */
.detail-card-slot > .win11-bar-list + .win11-bar-list {
    margin-top: 1rem;
}

/* ---- Globale Formularfelder ----
   Optik 1:1 wie .app-sidebar-search und .login-input, damit Eingabefelder in
   der gesamten App identisch aussehen. Niemals seitenspezifisch nachbauen.
   Abstaende laufen bewusst ueber gap (nicht ueber margin-top auf .form-label):
   margin-top-Regeln wie ":first-of-type" greifen je ELTERNELEMENT, nicht je
   Card - bei gemischter Verschachtelung (manche Felder in .form-field, andere
   direkt in .form-grid) entstanden dadurch je nach Feld unterschiedliche
   Abstaende. Mit gap ist jedes Feld ein gleichwertiger .form-field-Block. */
.form-grid {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 32rem;
}

.form-field {
    display: flex;
    flex-direction: column;
}

/* ---- Generisches 1/3-2/3-Split-Layout fuer Seiten mit einem schmalen
   Nebenbereich (z.B. Logo) neben einer breiteren Formularspalte. Faellt auf
   schmalen Bildschirmen auf eine Spalte zusammen. Bewusst global, damit
   kuenftige aehnliche Seiten dasselbe Muster nutzen statt eigene Grids zu
   erfinden (siehe Firma.razor als Referenz). */
.page-split-grid {
    display: grid;
    grid-template-columns: 1fr 2fr;
    align-items: start;
    gap: 1rem;
}

.page-split-grid-side {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

@media (max-width: 720px) {
    .page-split-grid {
        grid-template-columns: 1fr;
    }
}

/* Checkbox als eigenstaendiges Feld innerhalb eines .form-grid: bekommt
   denselben vertikalen Abstand zu den Nachbarfeldern wie diese sich
   untereinander (siehe .form-grid gap), damit sie sich nicht "zu nah" am
   vorherigen Feld anfuehlt. Kein .form-label/.form-input-Wrapper noetig -
   FluentCheckbox bringt Kontrollkaestchen + Beschriftung bereits mit. */
.form-checkbox {
    margin-top: 6px;
}

.form-label {
    display: block;
    margin-bottom: 4px;
    font-size: 0.85rem;
    color: var(--neutral-foreground-rest);
}

.form-input {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 10px;
    /* Gleicher Eckenradius wie FluentButton (Fluent-Standard-Control-Radius).
       Bewusst FEST 4px statt var(--control-corner-radius, ...): Fluent setzt
       dieses Token global als LEERE Custom Property, wodurch var()-Fallbacks
       nie greifen und der Radius komplett verschwindet. */
    border-radius: 4px;
    /* Ruhezustand: reine, neutrale Flaeche (--neutral-layer-1) - im
       Hellmodus dadurch weiss und bleibt dort bewusst bei --neutral-layer-1.
       Im Dunkelmodus dagegen einen sichtbar HELLEREN Layer verwenden (siehe
       @media-Override unten), da reines --neutral-layer-1 im Dark-Theme zu
       wenig Kontrast zur umgebenden Flaeche (z.B. Card-Body) bietet. */
    background: var(--input-background);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    backdrop-filter: blur(20px) saturate(140%);
    border: 1px solid var(--input-stroke);
    transition: border-color 0.12s ease-in-out, background 0.12s ease-in-out, box-shadow 0.12s ease-in-out;
}

/* KEIN Hover-Effekt: Eingabefelder sind keine klickbaren Aktionselemente wie
   Buttons/Icon-Buttons - nur der Fokus-Zustand (siehe .form-input:focus-within
   unten) gibt Feedback. */

/* :not(.form-input--readonly) hier ebenfalls noetig: ein readonly-Input laesst
   sich zwar nicht bearbeiten, aber trotzdem anklicken/fokussieren (Browser-
   Standardverhalten) - ohne diese Ausnahme bekam ein gesperrtes Feld beim
   Anklicken faelschlich dieselbe Akzentfarbe/Fokus-Optik wie ein editierbares.
   Feldflaeche bleibt im Fokus bewusst neutral (keine Akzentfarbe im Inhalt) -
   nur der Rahmen/die Unterlinie ist akzentfarben. */
.form-input:focus-within:not(.form-input--readonly) {
    border-color: var(--input-stroke);
    box-shadow: inset 0 -2px 0 0 var(--accent-fill-rest);
}

.form-input--readonly {
    opacity: 0.7;
}

/* Browser-Autofill/Autocomplete-Auswahl (z. B. gespeicherter Vorname/Telefon
   aus dem Dropdown) faerbt das Feld sonst mit einem eigenen hellen
   Hintergrund - identischer Fix wie bei .app-input-field. */
.form-input-field:-webkit-autofill,
.form-input-field:-webkit-autofill:hover,
.form-input-field:-webkit-autofill:focus,
.form-input-field:-webkit-autofill:active {
    -webkit-text-fill-color: var(--neutral-foreground-rest);
    -webkit-box-shadow: 0 0 0 1000px transparent inset;
    box-shadow: 0 0 0 1000px transparent inset;
    caret-color: var(--neutral-foreground-rest);
    transition: background-color 9999s ease-in-out 0s;
}

/* Schloss-Icon in nicht editierbaren Feldern (Konzept 3o-1): signalisiert,
   dass es sich weiterhin um ein Eingabefeld handelt, dessen Bearbeitung nur
   aktuell (rechteabhaengig) gesperrt ist - kein rein informativer Text. */
.form-input--readonly .form-input-lock {
    flex: none;
    color: var(--neutral-foreground-secondary);
}

/* ============================================================================
   FUNDAMENT: Content-Layer-Modell (verbindlich fuer ALLE Content-Flaechen)
   ============================================================================
   Ausgangsproblem: Content-Flaechen (Cards, Accordions, Panels) verhielten
   sich in Light und Dark grundsaetzlich unterschiedlich. Ursache ist KEIN
   fehlerhaftes CSS, sondern die Art, wie Fluent Flaechen berechnet:

   Fluent leitet --neutral-layer-* aus einer Luminanz-Rampe ab. In Dark wird
   eine hoehere Ebene HELLER, in Light wird sie DUNKLER. Eine Regel wie
   "nimm --neutral-layer-2" bedeutet deshalb je Theme das GEGENTEIL in der
   Kontrastrichtung. Genau daran scheiterten die bisherigen Einzel-Fixes: sie
   wurden jeweils in einem Theme "passend" gemacht und kippten im anderen.

   Konsequenz - das Fundament arbeitet ab hier NICHT mehr mit festen
   Layer-Nummern, sondern mit RELATIVEN, richtungsneutralen Groessen:

     --surface-elevate  Flaechenanhebung gegenueber dem Untergrund. Wird ueber
                        color-mix mit --neutral-foreground-rest gebildet, also
                        automatisch in BEIDEN Themes in die jeweils richtige
                        Kontrastrichtung (Dark: heller, Light: dunkler).
     --surface-stroke   Einheitliche Trennlinie/Rahmen fuer alle Surfaces.
     --surface-radius   Einheitlicher Radius aller Content-Flaechen.

   Warum color-mix statt Fluent-Token: --neutral-layer-* und
   --neutral-stroke-* sind ECHTE Fluent-Design-Tokens. Das JS-Tokensystem
   schreibt sie zur Laufzeit als INLINE-STYLE auf die Elemente. Inline gewinnt
   in der Kaskade immer gegen externes CSS - deshalb "griffen Ueberschreibungen
   scheinbar nicht". Die drei Variablen hier sind dagegen EIGENE Variablen,
   die Fluent nicht kennt und daher nie inline ueberschreibt. Sie sind der
   einzige zuverlaessige Hebel und damit die verbindliche Basis.

   Regel fuer neue UI: Content-Flaechen IMMER ueber diese drei Variablen
   bauen, niemals direkt auf --neutral-layer-* oder Hex-Werte. */
/* THEME-TOKEN-SYSTEM (verbindlich)
   Aufbau in genau zwei Ebenen:
   1) :root  = theme-NEUTRALE Tokens. Alles, was in Hell UND Dunkel identisch
      berechnet werden kann, weil es relativ zu Fluent-Tokens definiert ist.
   2) @media (prefers-color-scheme: light/dark) = die EINZIGEN beiden Stellen
      im gesamten Stylesheet, an denen theme-abhaengige Werte gesetzt werden.
   Regel fuer neue UI: niemals Hex-/rgba-Werte im Regelwerk verwenden und
   niemals einen weiteren prefers-color-scheme-Block anlegen - stattdessen
   hier ein Token ergaenzen und ueberall referenzieren. */
:root {
    --surface-elevate: color-mix(in srgb, var(--neutral-foreground-rest) 6%, var(--neutral-layer-1));
    --surface-stroke: color-mix(in srgb, var(--neutral-foreground-rest) 18%, transparent);
    --surface-radius: 6px;
    /* Rahmenfarbe von Eingabefeldern im Ruhe-/Fokuszustand - eine Stufe
       kraeftiger als --surface-stroke, damit Felder als Eingabeflaeche lesbar
       bleiben. Theme-neutral, da relativ zum Vordergrund berechnet. */
    --input-stroke: color-mix(in srgb, var(--neutral-foreground-rest) 22%, transparent);
    /* Elevation: EINE Schattenfarbe, zwei Abstufungen (Card vs. schwebende
       Flaeche). Ersetzt die frueher verstreuten rgba(0,0,0,...)-Werte. */
    --shadow-color: color-mix(in srgb, black 6%, transparent);
    --shadow-card: 0 1px 2px var(--shadow-color);
    --shadow-floating: 0 4px 16px var(--shadow-color);
    /* Gegenstueck zu --surface-elevate: der App-Rahmen (Shell/Header/Sidebar/
       Content) liegt eine Stufe HINTER --neutral-layer-1 zurueck (dezent
       Richtung Mittelgrau gemischt), damit Content-Cards (--surface-elevate)
       sich sichtbar davon abheben - analog zur Windows-11-Einstellungsseite
       (Fensterhintergrund dezent abgesetzt, Karten heben sich ab).
       Bewusst NICHT ueber --neutral-foreground-rest gemischt (wie zuvor):
       dessen Farbe kehrt sich je Theme um (Dark: hell, Light: dunkel),
       wodurch der Shell-Hintergrund im Dark-Theme faelschlich HELLER statt
       dunkler als --neutral-layer-1 wurde (der gemeldete Fehler - der
       Login-Seitenhintergrund war im Dunkeldesign heller als die Card).
       Stattdessen fest Richtung Schwarz gemischt - das dunkelt in Light UND
       Dark gleichermassen ab. */
    --app-shell-background: color-mix(in srgb, black 8%, var(--neutral-layer-1));
    /* Einheitliche Semantikfarben fuer Validierung. Erfolg bewusst als eigenes
       Token statt Hex-Wert an jeder Stelle; Rot bleibt der abgestimmte, etwas
       waermere Ton (kein grelles Windows-Standardrot). Beide werden im
       Dark-Block unten aufgehellt, damit sie auf dunklem Grund lesbar sind. */
    --error-color: #bc2f32;
    --success-color: #2e9e44;
    /* Presence-/Verfuegbarkeitsgruen der Shell (Sidebar-Profil). Windows-11-
       Statusgruen statt des grellen Fluent-Neongruens. Eigenes Token, weil es
       NICHT die Validierungs-Semantik von --success-color ist. */
    --presence-available: #6ccb5a;
    /* Trennlinien der Sidebar-Gliederung: dezent akzentgetoent, folgt
       automatisch der System-Akzentfarbe. Im Hellmodus kraeftiger (siehe
       Light-Block), da helle Flaechen weniger Kontrast bieten. */
    --sidebar-divider: color-mix(in srgb, var(--accent-fill-rest) 35%, transparent);
    /* Abdunkelnde Ebene hinter modalen/aufgeklappten Flaechen (mobile
       Sidebar-Overlay, Dialoge). */
    --scrim-color: color-mix(in srgb, black 35%, transparent);
    /* Schatten der aufgeklappten mobilen Sidebar - deutlich staerker als
       --shadow-floating, da sie ueber dem Content schwebt. */
    --shadow-overlay: 0 10px 30px color-mix(in srgb, black 20%, transparent);
    /* Einheitlicher Hover-/Aktiv-Ton fuer interaktive Icon-/Nav-Elemente der
       App-Shell (Header-Icons, Zurueck/Vor-Navigation, Hamburger-Menue,
       Hauptnavigation, Bearbeiten-Button im Profilbereich, ...). Bewusst
       NEUTRAL (Kontrast zum jeweiligen Theme-Hintergrund) statt akzentfarben.
       EINE zentrale Variable statt denselben color-mix()-Ausdruck an jeder
       einzelnen Stelle zu duplizieren - passt sich automatisch an Hell/Dunkel
       an. Neue Elementgruppen mit Icon-Hover sollen ausschliesslich diese
       Variable referenzieren, keinen eigenen color-mix()-Wert definieren. */
         --shell-icon-hover: color-mix(in srgb, var(--neutral-foreground-rest) 10%, transparent);
    }

/* ---- Theme-abhaengige Tokens: HELL ----------------------------------------
   Eingabefelder nutzen im Hellmodus reines --neutral-layer-1. */
@media (prefers-color-scheme: light) {
    :root {
        --input-background: var(--neutral-layer-1);
        --sidebar-divider: color-mix(in srgb, var(--accent-fill-rest) 45%, transparent);
    }
}

/* ---- Theme-abhaengige Tokens: DUNKEL --------------------------------------
   Eingabefelder brauchen im Dunkelmodus einen sichtbar helleren Grund, sonst
   verschwinden sie im Card-Hintergrund. Fehler-/Erfolgsfarbe werden
   aufgehellt, weil das dunkle Rot/Gruen auf dunklem Grund sonst absaeuft -
   genau der gemeldete "Rot stimmt im Dark Mode nicht"-Fall. */
@media (prefers-color-scheme: dark) {
    :root {
        --input-background: color-mix(in srgb, white 16%, var(--neutral-layer-1));
        --error-color: color-mix(in srgb, white 34%, #bc2f32);
        --success-color: color-mix(in srgb, white 26%, #2e9e44);
    }
}

/* ---- Status-Badge "Inaktiv/Deaktiviert" ------------------------------------
   FluentBadge mit Appearance.Neutral hat im Standard einen transparenten/
   kaum sichtbaren Hintergrund. Inaktive Status sollen stattdessen in BEIDEN
   Themes klar als Rot erkennbar sein - dieselbe --error-color wie im
   Login-Formular (dort bereits fuer Dark automatisch aufgehellt). */
.status-badge-inactive::part(control) {
    background-color: var(--error-color);
    color: white;
}

/* ---- Kopfbereich JEDER Card/Panel/Dialog/Login-Flaeche (VERBINDLICHER,
   einziger Header-Ton der gesamten App) --------------------------------------
   EIN zentrales Token statt denselben color-mix()-Ausdruck an jeder Stelle zu
   duplizieren (Projektregel, siehe copilot-instructions.md). Bisher stand an
   drei Stellen (.surface-card-header, .fluent-section-header,
   .win11-table-toolbar-framed) exakt derselbe Wert einzeln kopiert - jede
   Kontrastanpassung musste dadurch an mehreren Stellen wiederholt werden.
   Fest gegen SCHWARZ gemischt (nicht gegen --neutral-foreground-rest): Letzterer
   flippt je Theme (Dark: hell), wodurch der Header im Dunkelmodus faelschlich
   HELLER statt dunkler als der Content wuerde. Ein fester Schwarzanteil dunkelt
   in Hell UND Dunkel gleichermassen ab - garantiert also in BEIDEN Themes einen
   Kopfbereich, der dunkler als der Content ist (siehe Nutzerregel).
   WICHTIG (Bugfix): der vorherige Wert mischte gegen "transparent" statt gegen
   eine feste Flaeche - dadurch schimmerte bei jedem Verwender die jeweils
   dahinterliegende Flaeche durch (z.B. bei Win11Table.razor.css ist
   .win11-table-toolbar-framed KEIN Kind von .surface-card, sondern liegt
   direkt auf dem Seitenhintergrund). Ergebnis: derselbe Token sah je nach
   Einsatzort unterschiedlich dunkel aus (Tabellen-Header zu dunkel).
   Jetzt fest gegen dieselbe Basis wie --surface-elevate (--neutral-layer-1)
   gemischt (undurchsichtig) - dadurch sieht der Header ÜBERALL exakt
   gleich aus, unabhaengig davon, was optisch dahinterliegt.
   Der Footer bekommt bewusst KEIN eigenes Token: er soll wie der Content
   aussehen (keine eigene Hintergrundfarbe), nur eine Trennlinie grenzt ihn ab. */
:root {
    --surface-header: color-mix(in srgb, black 10%, var(--neutral-layer-1));
}

/* ---- Surface-Card (Fluent) - gemeinsame Referenzflaeche fuer ALLE Surfaces
   (Formular-Card, Dialog, Panel), NICHT nur das Profil-Formular (daher der
   generische Name statt "form-card" - fruehere Bezeichnung fuehrte zu
   Verwirrung, weil sie projektweit fuer Dialoge/Panels zweckentfremdet wurde).
   Bleibt eine echte FluentCard (kein Custom-Dialog-Nachbau). Der Header hat
   bewusst KEINEN eigenen Hintergrund (nutzt die Card-Flaeche durch) - nur
   eine Trennlinie grenzt ihn optisch vom Body ab. */
.surface-card {
    /* Referenz-Card fuer Formulare (Konzept 3o-1): richtet sich nach der
       Breite von .form-grid (32rem) aus, statt einer eigenen, staerker
       abweichenden Breite. width: fit-content ginge hier NICHT zusammen mit
       einem eigenen Container-Kontext auf .surface-card-body (Zirkelbezug: der
       Container blendet die Kindgroesse aus, wodurch die Card auf ein
       Minimum schrumpft) - deshalb ein fester max-width-Rahmen, innerhalb
       dessen .form-row per flex-wrap selbststaendig umbricht. */
    width: 100%;
    max-width: 34rem;
    /* Siehe .app-confirm-dialog (app-shell.css): FluentCard fuellt als
       Content-Surface sonst die volle Hoehe ihres Containers aus. */
    height: auto !important;
    /* Hinweis: Accent-Buttons INNERHALB einer Card berechnen ihren Ton bei
       Fluent adaptiv zur (helleren) Card-Flaeche. Das laeuft im JS-basierten
       DesignToken-System und laesst sich per CSS NICHT korrigieren (im
       Styleguide Abschnitt 4 nachgemessen). Die App-weite Vereinheitlichung
       uebernimmt applyUniformAccent() in app-shell.js. */
    transition: box-shadow 0.1s ease-in-out;
}

/* Breiten-Variante von .surface-card fuer Inhalte, die NICHT in die 34rem-
   Formularbreite passen (z.B. eine Card mit FluentDataGrid mit mehreren
   Spalten). Behaelt alle anderen surface-card-Fixes (--fill-color,
   --neutral-stroke-layer-rest-Kontrast) bei, hebt nur die max-width auf.
   Verwendung: Class="surface-card surface-card-wide fluent-card-minimal-style
   fluent-card-flush" (surface-card-wide NACH surface-card, damit die
   Kaskade greift). */
.surface-card.surface-card-wide {
    max-width: none;
}


   Shadow) NUR, wenn die Klasse "fluent-card-minimal-style" gesetzt ist (siehe
   FluentCard.razor.rz.scp.css: .fluent-card-minimal-style { background:
   var(--fill-color); border: ... var(--neutral-stroke-layer-rest); box-shadow:
   var(--elevation-shadow-card-rest); }). Ohne diese Klasse besteht das
   Shadow-DOM nur aus einem nackten <slot> - kein ::part(content) vorhanden,
   ein Overwrite darauf greift also nie. surface-card setzt
   deshalb "fluent-card-minimal-style" (siehe Profil.razor)
   und nutzt den nativen Mechanismus, indem nur --fill-color auf den
   gemeinsamen Referenz-Ton (--neutral-layer-2) gesetzt wird. Border/Shadow kommen
   dadurch automatisch von Fluent - das ist die gemeinsame Referenzflaeche fuer
   ALLE Content-Cards. */
.surface-card.fluent-card-minimal-style {
    --fill-color: var(--surface-elevate);
}

.surface-card.fluent-card-minimal-style {
    padding: 0;
}

/* Der native --neutral-stroke-layer-rest-Border ist in BEIDEN Themes zu
   schwach, um die Card zuverlaessig vom Content-Hintergrund abzuheben -
   besonders wenn im Content viele helle (Light) bzw. sehr dunkle/schwarze
   (Dark) Flaechen liegen. Fix: staerkerer, themeneutraler Kontrast-Token
   --neutral-stroke-strong-rest statt einer Akzentfarb-Beimischung - dadurch
   wird die Card sichtbarer abgegrenzt, OHNE dass sie dabei (wie bei einer
   Akzent-Tönung) dunkler/farbiger als vorgesehen wirkt. Gleiches Muster wie
   beim nativen FluentAccordion (Heading/Region-Kontrast).
   WICHTIG (root cause, per NuGet-Package-Inspektion verifiziert):
   --neutral-stroke-layer-rest ist ein ECHTER Fluent-Design-Token. Das
   JS-basierte DesignToken-System von Fluent UI berechnet solche Tokens zur
   Laufzeit und schreibt sie als INLINE-STYLE direkt auf das jeweilige
   Element (sichtbar im gerenderten HTML, z.B. style="--neutral-stroke-
   layer-rest: #efefef; ..."). Ein Inline-Style gewinnt in der CSS-Kaskade
   IMMER gegen eine externe Stylesheet-Regel, unabhaengig von deren
   Selektor-Spezifitaet - ausser die externe Regel nutzt !important. Genau
   deshalb griff weder ein direktes border-color-Override noch ein simples
   Ueberschreiben der Variable ohne !important (beides schon ausprobiert).
   --fill-color dagegen funktioniert OHNE !important, weil das KEIN
   Fluent-Design-Token ist, sondern eine von FluentCard selbst erfundene,
   rein CSS-interne Variable, die nie per JS inline gesetzt wird. Gleiches
   grundsaetzliches Problem wie bei den Accent-Buttons in Cards (siehe
   Kommentar oben zu applyUniformAccent in app-shell.js). */
.surface-card.fluent-card-minimal-style {
    --neutral-stroke-layer-rest: var(--surface-stroke) !important;
}

/* Initialen-Avatar
   z.B. FluentPersona in der Sidebar oder als zugewiesener Bearbeiter):
   Fluent faerbt die Initialen-Zelle standardmaessig per Inline-Style mit
   einer aus dem Namen gehashten Zufallsfarbe. Das widerspricht unserem
   einheitlichen Akzentfarb-Schema (analog zu Buttons/Icons) - daher app-weit
   fuer JEDE FluentPersona auf die System-/App-Akzentfarbe ueberschrieben.
   !important noetig, da Inline-Styles sonst jede externe Regel schlagen. */
.fluent-persona .fluent-presence-badge > div {
    background-color: var(--accent-fill-rest) !important;
    /* Kontrastfarbe der Initialen: --foreground-on-accent-rest ist der von
       Fluent themabhaengig (hell/dunkel) berechnete Text-/Icon-Ton FUER
       Inhalte AUF einer Akzentflaeche (z.B. Button-Text auf Accent-Button).
       --accent-foreground-rest waere hier falsch, das ist fuer Akzentfarbtext
       AUF neutralem Hintergrund gedacht und ergab in einigen Themes zu wenig
       Kontrast auf der Akzentflaeche selbst. */
    color: var(--foreground-on-accent-rest) !important;
    border-radius: 50%;
}

/* Der native <fluent-dialog>-Host (IDialogService/FluentDialogProvider)
   rendert sein ::part(control) selbst mit eigenem Hintergrund/Border/Shadow.
   Da unsere zentrierten Dialog-Inhalte (ConfirmDialog/FormDialog-basierte
   Dialoge) IMMER eine eigene .surface-card-Flaeche mitbringen, entsteht sonst
   eine sichtbare "Karte in der Karte". Der Dialog-Host selbst dient dort nur
   noch als reiner Positionierungs-/Overlay-Container - die eigentliche Optik
   kommt ausschliesslich von .surface-card.
   Rechte/linke Slide-Over-Panels (z.B. QuickActionsPanel) nutzen NICHT mehr
   IDialogService.ShowPanelAsync/<fluent-dialog>, sondern die eigene
   SlidePanel-Komponente (siehe Components/SlidePanel.razor) - daher gibt es
   hier keinen Sonderfall fuer class~="right"/"left" mehr. */
fluent-dialog::part(control) {
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
}

/* ---- Fluent-Surface-Bausteine (Konzept/Fluent-UX-Konzept.md, Abschnitt 2) --
   Ersatz fuer die frueheren Eigenbau-Komponenten SurfaceHeader/SurfaceFooter/
   WinCard. Die Struktur entsteht ab jetzt direkt aus <FluentCard> +
   <FluentStack> + <FluentDivider>; diese Klassen liefern NUR die im Konzept
   vorgeschriebenen Abstandswerte, damit dafuer keine Inline-Styles noetig sind.

   .fluent-card-flush  = <FluentCard Style="padding: 0; overflow: hidden;">
   .fluent-section     = eine Zeile/Sektion innerhalb der randlosen Card
   .fluent-divider-inset = <FluentDivider Style="margin: 0 16px;"> */
.fluent-card-flush {
    /* !important zwingend noetig: Fluents eigenes Bundle-CSS setzt das
       Padding direkt ueber einen Element-Selektor mit Scope-Attribut
       (fluent-card[b-xxxx] { padding: calc(var(--design-unit) * 5px); }),
       Spezifitaet (0,1,1). Eine reine Klassenregel (0,1,0) wie diese hier
       wuerde dagegen IMMER verlieren, unabhaengig von der Reihenfolge der
       Stylesheets - das war der Grund, warum bisherige Content-Cards
       (im Gegensatz zu Login.razor, das stattdessen ein Inline-Style nutzt)
       trotz dieser Klasse sichtbares inneres Padding behalten haben. */
    padding: 0 !important;
    overflow: hidden;
    /* Divider innerhalb der Card brauchen denselben Kontrast-Fix wie zuvor in
       .surface-header - der globale Token reicht auf Card-Flaechen nicht aus. */
    --neutral-stroke-divider-rest: var(--surface-stroke);
}

.fluent-section {
    padding: 12px 16px;
}

/* Kopfbereich-Sektion einer Card/eines Flyouts (Windows-11-Muster: der
   Header hebt sich leicht vom Content darunter ab). Fest gegen black gemischt
   (nicht gegen --neutral-foreground-rest): Letzterer flippt je Theme, wodurch
   der Header im Dunkelmodus faelschlich heller statt dunkler wurde. Ein fester
   Schwarzanteil dunkelt in Hell UND Dunkel gleichermassen ab - identisches
   Muster wie .surface-card-header und --app-shell-background.
   Trennlinie zum Content: DURCHGEZOGEN (volle Breite, ::after ohne Inset) -
   identisch zu .surface-card-header, damit Kopfbereiche app-weit einheitlich
   wirken. Ersetzt den vorherigen vollbreiten FluentDivider auf der Login-Seite. */
.fluent-section-header {
    position: relative;
    padding: 16px 24px;
    background-color: var(--surface-header);
}

.fluent-section-header::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 1px;
    background-color: var(--surface-stroke);
}

.fluent-divider-inset {
    margin: 0 16px;
}

/* Titelzeile einer Fluent-Surface: nur Typografie, das Layout kommt aus
   FluentStack (Icon + Titel). */
.fluent-section-title {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1;
    color: var(--neutral-foreground-rest);
}

/* Sekundaere Stealth-Buttons MIT Text (z.B. "Abbrechen" in Dialog-Footern,
   "Feld hinzufuegen" im Tabellen-Kopfbereich) brauchen - anders als reine
   Icon-Only-Buttons (IconActionButton, die bewusst mit dem Untergrund
   verschmelzen, siehe IconActionButton.razor.css) - IMMER einen sichtbar
   erkennbaren Rand im Ruhezustand, unabhaengig davon, auf welcher Flaeche
   (Card, Header, Dialog) sie liegen und unabhaengig vom Hell/Dunkel-Theme.
   Frueher gab es hierfuer eine tote Regel auf einer nirgends verwendeten
   Klasse (.fluent-actions) - dadurch war der Rand mal sichtbar, mal nicht,
   und der Hover-Effekt inkonsistent. Jetzt EINE globale, Theme-unabhaengige
   Regel fuer ALLE Text-Stealth-Buttons der App (Fluent-Tokens statt
   hartkodierter Farben), damit Ruhezustand UND Hover ueberall konsistent
   funktionieren. :not(.icon-action-button-blend):not(.icon-action-button-filled)
   grenzt die reinen Icon-Only-Buttons (IconActionButton, beide Varianten) aus -
   Variant.Filled bringt in IconActionButton.razor.css bereits seine eigene,
   dauerhaft deckende Akzentflaeche mit und darf hier nicht durch den
   transparenten 10%-Hover ueberschrieben werden; #dialog_close ist der native,
   von FluentDialog selbst gerenderte Schliessen-Button (kein IconActionButton,
   daher separat ausgeschlossen und weiter unten eigens gestylt). */
fluent-button[appearance="stealth"]:not(.icon-action-button-blend):not(.icon-action-button-filled):not(#dialog_close)::part(control) {
    border: 1px solid var(--neutral-stroke-rest);
}

fluent-button[appearance="stealth"]:not(.icon-action-button-blend):not(.icon-action-button-filled):not(#dialog_close):hover::part(control) {
    border-color: var(--accent-fill-rest);
    background-color: color-mix(in srgb, var(--accent-fill-rest) 10%, transparent);
}

/* Nativer Dialog-Schliessen-Button (fluent-dialog, IDialogService): soll wie
   ein normaler Appearance.Accent-Button aussehen (Akzent-Hintergrund, Icon in
   Kontrastfarbe zur Akzentflaeche, gleicher Hover-Effekt wie jeder andere
   Accent-Button) statt wie ein transparenter Icon-Only-Button. Fluent rendert
   ihn selbst mit appearance="stealth" (kein Override moeglich), daher wird
   die Accent-Optik hier manuell nachgebaut statt appearance="accent" zu
   erzwingen. accent-fill-hover/-active kommen aus demselben Fluent-Token-Satz
   wie bei echten Accent-Buttons, dadurch identisches Hover-/Active-Verhalten. */
/* Nativer Dialog-Schliessen-Button (fluent-dialog, IDialogService): wird
   ausgeblendet, da ConfirmDialog/FormDialog jetzt einen eigenen Schliessen-
   Button im Kopfbereich mitbringen (SurfaceCard.OnClose, IconActionButton,
   siehe SurfaceCard.razor/.css .surface-card-close) - analog zum SlidePanel-
   Header. Der native, aussen ueber der Karte schwebende Button wuerde sonst
   doppelt angezeigt. display:none statt Entfernen von ShowDismiss=true je
   Aufrufer, damit KEINE der ca. 10 Aufrufer-Seiten angepasst werden muss. */
fluent-dialog #dialog_close {
    display: none;
}

/* Formularzeile fuer nebeneinanderliegende Felder (z.B. Vorname/Nachname).
   min-width auf .form-field ist HIER bewusst gesetzt (nicht 0): erst dadurch
   bricht die Zeile bei zu wenig Platz (z.B. Smartphone im Hochformat) auf
   mehrere Zeilen um, statt die Felder bis zur Unlesbarkeit zusammenzudruecken.
   Genau das ist global gewuenscht: Hochformat -> Felder untereinander,
   Querformat/Desktop mit genug Breite -> Felder bleiben nebeneinander.
   12rem ist bewusst absolut (nicht %) UND deckt sich mit der bereits in
   DetailCardGrid.razor.css dokumentierten Erwartung (minmax(0, 1fr) je
   Spalte, kommentiert mit "je min-width: 12rem") - die Grid-Spalte gibt
   .form-row damit schon Spielraum zum Umbrechen, diese Regel liefert dazu
   den fehlenden Gegenpart auf .form-field selbst. Der eigentliche Fehler
   der frueheren min-width:0-Regel war nicht die Mindestbreite an sich,
   sondern dass es KEINE gab, wodurch Felder nie umgebrochen sind. */
.form-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.form-row > .form-field {
    flex: 1 1 12rem;
    min-width: 12rem;
}

/* ---- Generisches 6-Spalten-Formular-Grid (Ersatz/Ergaenzung zu .form-row
   fuer Karten mit mehreren, UNTERSCHIEDLICH breiten Feldern pro Zeile, z.B.
   PLZ/Stadt/Land oder Strasse/Hausnummer). .form-row behandelt jedes Feld
   gleich breit (flex: 1 1 12rem) - das passt nicht, wenn ein Feld wie "Land"
   bewusst schmaler bleiben soll als "Strasse". Bewusst global in app.css
   (nicht seitenspezifisch), damit jede Karte im Projekt (Profil, Firma,
   Standorte, Rechtstraeger usw.) dasselbe Muster nutzen kann.

   6 statt 3 logische Spalten (angelehnt an Konzept/responsives_adress_
   formular.html) erlauben feinere Breitenverhaeltnisse pro Feld (z.B.
   Strasse 4/6 + Hausnummer 2/6, PLZ 2/6 + Stadt 4/6), statt nur grobe
   Drittel-Schritte.

   Nutzung: <div class="form-grid-6col"> als Ersatz fuer eine Reihe
   .form-row-Bloecke, darin jedes Feld als .form-field (nimmt Standard-Breite,
   2 von 6 Einheiten) oder .form-field-span-1/-2/-3/-4/-5/-6 fuer gezielt
   schmalere/breitere Felder. Faellt per @container (analog
   DetailCardGrid.razor.css) auf 1 gestapelte Spalte zurueck, damit es auch in
   der schmaleren 2/3-Spalte (DetailCardGridLayout.TwoThirdsOneThird), bei
   geoeffnetem Sidebar-Rail und auf Mobile funktioniert.
   BEWUSST NUR EIN BREAKPOINT (kein Zwischenschritt mit 2/3 sichtbaren
   Spalten): 6 ist nur durch 1, 2, 3 und 6 ganzzahlig teilbar - eine 3- oder
   4-Spalten-Zwischenstufe kann einen span-3+span-3-Feldpaar (z.B. Geburtsdatum
   + Geschlecht) mitten im Paar umbrechen lassen, da 3+3=6 nur bei voller
   6-Spalten-Aufloesung wieder exakt aufgeht. Daher: unterhalb des Breakpoints
   stapelt JEDES Feld auf volle Breite, ab dem Breakpoint gilt sofort die
   volle 6-Spalten-Aufloesung mit 1:1 passenden Spans.
   WICHTIG: reagiert bewusst auf den "form-card"-Container (siehe
   SurfaceCard.razor.css .surface-card-body), NICHT auf "app-content" - die
   Karte selbst kann schmaler sein als der gesamte Content-Bereich (z.B. in
   einer 2/3-1/3-Spalte oder bei geoeffnetem Sidebar-Rail), und genau darauf
   muss das Grid reagieren. */
.form-grid-6col {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px 12px;
}

.form-grid-6col > .form-field,
.form-grid-6col > .form-field-span-1,
.form-grid-6col > .form-field-span-2,
.form-grid-6col > .form-field-span-3,
.form-grid-6col > .form-field-span-4,
.form-grid-6col > .form-field-span-5,
.form-grid-6col > .form-field-span-6 {
    grid-column: 1 / -1;
}

/* Ab 400px: 2 sichtbare Spalten, NUR fuer ungespannte Felder (.form-field /
   .form-field-span-1/-2) sicher, da diese je 1 von 2 Spalten belegen und sich
   nicht gegenseitig zerreissen koennen. Felder mit Span 3-6 bleiben hier
   bewusst auf voller Breite (kein 2-Spalten-Mapping fuer sie), da sich
   ungleiche/groessere Spans (z.B. 3+3 bei Geburtsdatum+Geschlecht) bei nur 2
   Spalten nicht mehr sauber nebeneinander abbilden liessen - siehe
   Begruendung beim 640px-Breakpoint unten. Damit eignet sich diese Stufe nur
   fuer Karten mit ausschliesslich gleich breiten Feldern (z.B. Geschaeftsdaten
   in Profil.razor), nicht fuer Karten mit asymmetrischen Spans. */
@container form-card (min-width: 400px) {
    .form-grid-6col {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .form-grid-6col > .form-field,
    .form-grid-6col > .form-field-span-1,
    .form-grid-6col > .form-field-span-2 {
        grid-column: span 1;
    }
}

/* Ab 640px: volle 6-Spalten-Aufloesung wie im Mockup. Kein Zwischenschritt
   davor (siehe Begruendung oben), damit Feldpaare wie Geburtsdatum/Geschlecht
   (je span-3) nicht durch eine krumme Zwischenspaltenzahl auseinandergerissen
   werden. */
@container form-card (min-width: 640px) {
    .form-grid-6col {
        grid-template-columns: repeat(6, minmax(0, 1fr));
    }

    .form-grid-6col > .form-field,
    .form-grid-6col > .form-field-span-2 {
        grid-column: span 2;
    }

    .form-grid-6col > .form-field-span-1 {
        grid-column: span 1;
    }

    .form-grid-6col > .form-field-span-3 {
        grid-column: span 3;
    }

    .form-grid-6col > .form-field-span-4 {
        grid-column: span 4;
    }

    .form-grid-6col > .form-field-span-5 {
        grid-column: span 5;
    }

    .form-grid-6col > .form-field-span-6 {
        grid-column: span 6;
    }
}

/* ---- Haupt/Seite-Formularmuster (main+side) fuer Karten mit einer kleinen
   "Nebengruppe" (z.B. Geburtsdatum+Geschlecht), die je nach verfuegbarer
   Kartenbreite entweder OBEN (schmale Karte, z.B. Sidebar-Rail geoeffnet)
   oder als SCHMALE 3. SPALTE NEBEN dem Hauptinhalt (breite Karte, Rail
   geschlossen) steht - waehrend der Hauptinhalt selbst asymmetrische Zeilen
   enthaelt (z.B. Strasse deutlich breiter als Hausnummer, PLZ schmaler als
   Stadt). Ein starres Spalten-Raster (wie .form-grid-6col) kann das nicht
   abbilden, weil sich ungleiche Verhaeltnisse (z.B. 3:1 und 1:2) nicht in
   ganzzahligen Rastereinheiten UND gleichzeitig mit einer wandernden
   Nebenspalte kombinieren lassen. Daher hier bewusst zwei Techniken kombiniert:
   1) grid-template-areas fuer die Haupt/Seite-Anordnung (wandert zwischen
      "oben" und "seitliche Spalte").
   2) Flex-Verhaeltnisse (.form-field-flex-1/-2/-3) fuer die Zeilen INNERHALB
      von .form-grid-main-side-main - diese funktionieren bei JEDER
      tatsaechlichen Breite des Hauptbereichs korrekt (kein Rasterbruch),
      da sie relativ zueinander (3 Anteile zu 1 Anteil usw.) berechnet werden.
   Generisch/wiederverwendbar fuer jede Karte mit aehnlichem Bedarf (nicht nur
   Profil/Personendaten). Reagiert wie ueblich auf den "form-card"-Container. */
.form-grid-main-side {
    display: grid;
    grid-template-areas: "side" "main";
    grid-template-columns: 1fr;
    gap: 16px 12px;
}

.form-grid-main-side-main {
    grid-area: main;
    display: flex;
    flex-direction: column;
    gap: 10px 12px;
}

.form-grid-main-side-side {
    grid-area: side;
    display: flex;
    /* Nebenfelder (z.B. Geburtsdatum+Geschlecht) bleiben IMMER nebeneinander
       (row), egal ob die Seitenspalte gerade OBEN (schmale Karte, Rail
       offen) oder RECHTS (breite Karte, Rail zu) steht - flex-wrap +
       min-width je Kind (siehe Regel unten) sorgt dafuer, dass erst bei
       wirklich zu wenig Platz (z.B. Smartphone-Breite) umgebrochen wird,
       statt die Felder dauerhaft column zu stapeln. */
    flex-direction: row;
    flex-wrap: wrap;
    gap: 10px 12px;
}

/* Jedes Feld in der Seitenspalte bekommt dieselbe Mindestbreite wie ein
   normales .form-field (siehe .form-row > .form-field), damit Geburtsdatum
   und Geschlecht bei jeder Kartenbreite so frueh/spaet umbrechen wie
   vergleichbare Feldpaare auf anderen Seiten (z.B. Firma-Kontaktdaten). */
.form-grid-main-side-side > * {
    flex: 1 1 12rem;
    min-width: 12rem;
}

@container form-card (min-width: 640px) {
    .form-grid-main-side {
        grid-template-areas: "main side";
        grid-template-columns: 2fr 1fr;
        align-items: start;
    }
}

/* Zeile innerhalb von .form-grid-main-side-main (oder generell jeder Karte)
   fuer 2 Felder mit bewusst UNGLEICHEM Breitenverhaeltnis, z.B. Strasse
   (form-field-flex-3) + Hausnummer (form-field-flex-1), oder PLZ
   (form-field-flex-1) + Stadt (form-field-flex-2). Funktioniert bei jeder
   Containerbreite korrekt, da die Verhaeltnisse relativ (nicht rasterbasiert)
   berechnet werden.
   min-width JE FELD ist bewusst gesetzt (nicht 0): ohne Mindestbreite kann
   z.B. "Hausnummer" bei wenig Platz (schmale Karte, geoeffnetes Sidebar-Rail)
   beliebig schmal zusammengequetscht werden, wodurch das Floating-Label
   abgeschnitten wirkt. Die Werte sind bewusst klein gehalten (kleinere
   Mindestbreite fuer die "kleine" Seite eines Paars wie Hausnummer/PLZ,
   etwas groessere fuer die "grosse" Seite wie Strasse/Stadt), damit die Zeile
   erst dann umbricht (flex-wrap: wrap), wenn wirklich zu wenig Platz da ist -
   z.B. auf Smartphone-Breite faellt jedes Feld dann auf eine eigene Zeile
   (volle Breite), statt unleserlich schmal zu bleiben. */
.form-field-row {
    display: flex;
    gap: 10px 12px;
    flex-wrap: wrap;
}

.form-field-row > .form-field-flex-1 {
    flex: 1 1 6rem;
    min-width: 6rem;
}

.form-field-row > .form-field-flex-2 {
    flex: 2 1 8rem;
    min-width: 8rem;
}

.form-field-row > .form-field-flex-3 {
    flex: 3 1 8rem;
    min-width: 8rem;
}

.form-input-field {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    font-size: 0.875rem;
    font-family: inherit;
    color: var(--neutral-foreground-rest);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.form-input-field::placeholder {
    color: var(--neutral-foreground-hint);
}

/* ---- Beschreibung\u002BFormular-Muster fuer Karten im 2/3-Hauptbereich einer
   DetailCardGrid(Layout=TwoThirdsOneThird), z.B. Profil.razor/Firma.razor.
   Hintergrund: Diese Karten sind bei geoeffnetem Sidebar-Rail schmal genug,
   dass ihr bestehendes inneres Feld-Grid (form-grid-6col/form-grid-main-side
   usw.) die volle Kartenbreite sinnvoll ausfuellt. Bei GESCHLOSSENEM Rail
   waechst die 2/3-Spalte aber deutlich, waehrend die Formularfelder bewusst
   NICHT beliebig breiter werden sollen (laengere Eingabefelder wirken
   unleserlich) - es entstuende ein leerer, unschoener Bereich rechts/links
   neben dem Formular.
   Loesung: ein optionaler Beschreibungstext VOR den Feldern fuellt diesen
   Platz sinnvoll:
     SCHMALE Karte (Rail offen)  -\u003E Beschreibung OBEN, Felder darunter
                                    (volle Breite, wie bisher).
     BREITE Karte (Rail zu)     -\u003E Beschreibung LINKS in eigener Spalte,
                                    Felder bleiben rechts in ihrer bisherigen
                                    (schmalen) Breite - der sonst leere Rest
                                    der Karte wird durch die Beschreibung
                                    gefuellt statt zu stretchen.
   Reagiert wie .form-grid-main-side auf den form-card Container-Query-
   Kontext (SurfaceCard.razor.css), NICHT auf die Fensterbreite: entscheidend
   ist die tatsaechliche Breite DIESER Karte, nicht des Viewports.
   Generisch/wiederverwendbar fuer JEDE Karte mit diesem Bedarf - die
   Formularfelder selbst (form-grid-with-description-fields Inhalt) bleiben
   unveraendert die bestehenden Feld-Grid-Klassen. */
.form-grid-with-description {
    display: grid;
    grid-template-areas: "description" "fields";
    grid-template-columns: 1fr;
    gap: 16px 24px;
}

/* Etwas Luft oben/unten, damit der Text nicht direkt am Kartenrand bzw. am
   ersten/letzten Formularfeld "klebt". Bei breiter Karte (Rail zu, Text
   steht links neben den Feldern) zusaetzlich ein groesserer padding-top, da
   das erste Eingabefeld durch sein Floating-Label selbst etwas visuellen
   Abstand nach oben hat - ohne diesen Ausgleich wirkt der Beschreibungstext
   sonst hoeher angesetzt als das erste Feld. */
.form-grid-with-description-description {
    grid-area: description;
    padding-top: 4px;
    padding-bottom: 4px;
}

@container form-card (min-width: 680px) {
    .form-grid-with-description-description {
        /* Exakt derselbe FESTE Wert wie .app-input-floating margin-top
           (20px, siehe app.css) - dort ist der Abstand ein fixer
           Label-Reserveplatz, kein flexibler/responsiver Wert. Damit die
           Beschreibung optisch auf gleicher Hoehe wie die tatsaechliche
           Eingabebox (nicht das Label) beginnt, muss padding-top exakt
           diesen Fixwert uebernehmen statt eines eigenen, kleineren Werts. */
        padding-top: 20px;
    }
}

/* Eigener, GLEICHNAMIGER Container-Query-Kontext (container-name: form-card):
   verschachtelte Feld-Grids (form-grid-6col/form-grid-main-side) fragen per
   "@container form-card (min-width: ...)" ab - ohne diesen eigenen Kontext
   wuerden sie auf die Breite der GESAMTEN Karte reagieren (die bei
   geschlossenem Sidebar-Rail deutlich breiter als 26rem werden kann) und
   faelschlich in ihre breitere Mehrspalten-Auflösung wechseln, obwohl die
   Feldspalte selbst durch minmax(0, 26rem) gedeckelt bleibt. Mit diesem
   inneren Kontext gilt fuer verschachtelte Container-Queries automatisch die
   naechste (dieser) Container-Grenze statt der aeusseren Karte - die Felder
   bleiben dadurch IMMER in der schmalen, "Rail offen"-Anordnung, unabhaengig
   von der tatsaechlichen Kartenbreite. */
.form-grid-with-description-fields {
    grid-area: fields;
    min-width: 0;
    container-type: inline-size;
    container-name: form-card;
}

@container form-card (min-width: 680px) {
    .form-grid-with-description {
        grid-template-areas: "description fields";
        /* Beschreibungsspalte nimmt den Restplatz (1fr), die Feldspalte
           behaelt eine feste, mit der schmalen (Rail offen) Kartenbreite
           vergleichbare Maximalbreite, damit Eingabefelder nicht unleserlich
           breit werden. */
        grid-template-columns: 1fr minmax(0, 26rem);
        align-items: start;
    }
}

.form-hint {
    margin-top: 4px;
    font-size: 0.75rem;
    color: var(--neutral-foreground-secondary);
}

.form-actions {
    display: flex;
    gap: 0.5rem;
    /* Etwas weniger als der normale Feld-gap (16px) plus dem Platz, den ein
       .form-hint (Feld-Hinweistext) einnehmen wuerde - der Button-Bereich
       hat selbst keinen Hinweistext mehr, soll aber auch nicht direkt am
       letzten Feld "kleben". */
    margin-top: 0.5rem;
}

/* ---- Einheitliches Windows-11-Eingabefeld
   1:1 dieselbe Optik wie .login-input / .app-sidebar-search: eigenes <input>
   statt FluentTextField/FluentSearch. Grund: Fluent-2-Web-Components stylen
   sich ueber Shadow-DOM-::part()-Selektoren, die je nach Komponente/Version
   unterschiedlich benannt sind und sich als instabil erwiesen haben. Ein
   normales <input> mit Fluent-Design-Tokens (--accent-fill-rest,
   --neutral-foreground-rest ...) ist robuster, folgt automatisch Dark/Light
   und der System-Akzentfarbe und bleibt zentral an EINER Stelle wartbar.
   Verwendung: <div class="app-input"><input class="app-input-field" .../></div> */
.app-input {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 10px;
    border-radius: 4px;
    /* Ruhezustand: Feldflaeche kommt aus dem zentralen Theme-Token
       --input-background (Light: --neutral-layer-1, Dark: aufgehellt), analog
       zu .form-input. Kein eigener @media-Block mehr. */
    background: var(--input-background);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    backdrop-filter: blur(20px) saturate(140%);
    border: 1px solid var(--input-stroke);
    transition: border-color 0.12s ease-in-out, background 0.12s ease-in-out, box-shadow 0.12s ease-in-out;
}
/* KEIN Hover-Effekt
   Buttons/Icon-Buttons - nur der Fokus-Zustand (siehe :focus-within unten)
   gibt Feedback. Gilt app-weit, auch fuer .app-input-floating (Login,
   Style Guide). */
.app-input:focus-within {
    border-color: var(--input-stroke);
    box-shadow: inset 0 -2px 0 0 var(--accent-fill-rest);
}
.app-input-field {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    font-size: 0.875rem;
    color: var(--neutral-foreground-rest);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Bearbeiten-Sperre visuell eindeutig (EditableSurfaceCard setzt is-locked /
   is-editing auf die Card, siehe EditableSurfaceCard.razor). BEWUSST NICHT
   ueber :disabled allein geloest: der Kontrast war zu subtil und von der
   :disabled-Spezifitaet abhaengig. Der echte Zustands-Klassenschalter
   garantiert ein klar sichtbares Signal - der TEXT bleibt dabei immer im
   normalen Kontrast (bewusste Entscheidung), nur das FELD selbst wird
   ausgegraut:
     GESPERRT   -> Feld matt (transparenter Hintergrund, schwacher Rahmen,
                   gedimmtes Label),
     BEARBEITEN -> Feld voll aktiv (hellerer Feldhintergrund, kraeftiger
                   Rahmen), damit der Benutzer die Entsperrung sofort sieht.
   Gilt fuer JEDE EditableSurfaceCard app-weit (generisch wiederverwendbar). */
.editable-surface-card.is-locked .app-input {
    background: transparent;
    border-color: color-mix(in srgb, var(--input-stroke) 45%, transparent);
}
.editable-surface-card.is-locked .app-input-label {
    color: color-mix(in srgb, var(--neutral-foreground-hint) 60%, transparent);
}
.editable-surface-card.is-editing .app-input {
    background: var(--input-background);
    border-color: var(--input-stroke);
}
/* Spezifischer als die beiden Regeln oben (3 statt 2 Klassen-Selektoren):
   ein Feld, das zusaetzlich AppInputFloating.Locked="true" gesetzt hat (z.B.
   E-Mail in Profil.razor, immer nur ueber "Sicherheit" aenderbar), soll auch
   im Bearbeiten-Modus der Karte (.is-editing) matt/gesperrt bleiben statt
   durch die generische .is-editing .app-input-Regel faelschlich wieder aktiv
   (heller Hintergrund/kraeftiger Rahmen) zu wirken - unabhaengig vom
   Kartenzustand bleibt ein einzeln gesperrtes Feld immer gesperrt. */
.editable-surface-card.is-editing .app-input.is-locked {
    background: transparent;
    border-color: color-mix(in srgb, var(--input-stroke) 45%, transparent);
}
.editable-surface-card.is-editing .app-input.is-locked .app-input-label {
    color: color-mix(in srgb, var(--neutral-foreground-hint) 60%, transparent);
}
/* Generische Variante derselben Sperr-Optik fuer AppInputFloating.Locked
   (siehe Kommentar dort): gilt UNABHAENGIG vom EditableSurfaceCard-Kontext,
   z.B. in einem normalen FormDialog wie EditUserDialog.razor, wo ein Feld
   (aktuell: E-Mail) grundsaetzlich nicht auf dieser Seite editierbar ist,
   sondern nur ueber den Menuepunkt "Sicherheit". Zusaetzlich zur gedimmten
   Optik ein Schloss-Icon rechts im Feld, das eindeutig signalisiert: hier
   fehlt keine fehlende Funktion, sondern ist ein bewusst gesperrtes Feld. */
.app-input.is-locked {
    background: transparent;
    border-color: color-mix(in srgb, var(--input-stroke) 45%, transparent);
}
.app-input.is-locked .app-input-label {
    color: color-mix(in srgb, var(--neutral-foreground-hint) 60%, transparent);
}
.app-input.is-locked .app-input-field {
    /* Platz fuer das Schloss-Icon reservieren, damit langer Text nicht
       darunter verschwindet. */
    padding-right: 22px;
}
.app-input-lock-icon {
    position: absolute;
    right: 9px;
    top: 50%;
    transform: translateY(-50%);
    color: color-mix(in srgb, var(--neutral-foreground-hint) 70%, transparent);
    pointer-events: none;
}
/* Nicht-Formularfelder (z.B. Login, Sidebar-Suche): weiterhin normal lesbar,
   Browser-Standard-Ausgrauen bei :disabled unterbinden. */
.app-input-field:disabled {
    opacity: 1;
    color: var(--neutral-foreground-rest);
    -webkit-text-fill-color: var(--neutral-foreground-rest);
}
.app-input-field::placeholder {
    color: var(--neutral-foreground-hint);
}
/* Natives Browser-Icon (Edge/Chromium) zum Passwort-Einblenden/Loeschen
   ausblenden - Felder mit eigenem Augen-Button (z. B. Login, Profil) nutzen
   ausschliesslich diesen in Akzentfarbe statt des doppelten nativen Icons. */
.app-input-field::-ms-reveal,
.app-input-field::-ms-clear {
    display: none;
}
/* Augen-Button (Passwort anzeigen/verbergen, siehe AppInputFloating.
   ShowPasswordToggle): solange das Feld gesperrt/deaktiviert ist, soll er
   dieselbe gedimmte Optik wie das restliche Feld zeigen statt weiterhin in
   Akzentfarbe zu leuchten - erst nach "Bearbeiten" (Feld aktiv) erscheint
   er wieder in Akzentfarbe. Gilt app-weit (Login.razor, Sicherheit.razor,
   jede weitere Verwendung von AppInputFloating). */
.login-input-icon-btn:disabled {
    cursor: default;
}
.login-input-icon-btn:disabled svg {
    fill: color-mix(in srgb, var(--neutral-foreground-hint) 60%, transparent) !important;
}
.app-input-field::-webkit-credentials-auto-fill-button,
.app-input-field::-webkit-strong-password-auto-fill-button {
    display: none !important;
    visibility: hidden;
    pointer-events: none;
    position: absolute;
    right: 0;
}
/* Browser-Autofill/Autocomplete-Auswahl (z. B. gespeicherter Benutzername aus
   dem Dropdown) faerbt das Feld sonst mit einem eigenen hellen Hintergrund -
   wird hier per langem inset-Schatten in der Feldfarbe uebermalt, analog zum
   bisherigen Fix in login.css fuer .login-input-field. */
.app-input-field:-webkit-autofill,
.app-input-field:-webkit-autofill:hover,
.app-input-field:-webkit-autofill:focus,
.app-input-field:-webkit-autofill:active {
    -webkit-text-fill-color: var(--neutral-foreground-rest);
    -webkit-box-shadow: 0 0 0 1000px transparent inset;
    box-shadow: 0 0 0 1000px transparent inset;
    caret-color: var(--neutral-foreground-rest);
    transition: background-color 9999s ease-in-out 0s;
}
/* Natives Kalender-Icon bei type="date"-Feldern wird ausgeblendet - die
   Komponente AppDateInputFloating.razor zeigt stattdessen ein eigenes
   FluentIcon in echter Akzentfarbe (analog zum Augen-Icon im Passwortfeld,
   siehe login.css .login-input-icon-btn). Weiterhin volle Feldbreite
   klickbar lassen, damit das Feld insgesamt den Picker oeffnen kann. */
.app-date-input-floating .app-input-field::-webkit-calendar-picker-indicator {
    opacity: 0;
    position: absolute;
    right: 0;
    width: 32px;
    height: 100%;
    cursor: pointer;
}
.app-date-input-floating .app-input-field {
    padding-right: 26px;
}
.app-date-input-icon-btn {
    position: absolute;
    right: 9px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    padding: 0;
    cursor: pointer;
    color: var(--accent-fill-rest);
}
.app-date-input-icon-btn:disabled {
    cursor: default;
    color: color-mix(in srgb, var(--neutral-foreground-hint) 60%, transparent);
}

/* Visuell verstecktes Eingabeelement (z.B. natives <InputFile> fuer den
   Logo-Upload in Firma.razor, das ueber einen sichtbaren Button ausgeloest
   wird). BEWUSST global (nicht scoped): von Kindkomponenten wie <InputFile>
   gerendertes Markup traegt das scoped-CSS-Attribut der Seite nicht, daher
   wuerde eine Regel in Firma.razor.css nicht greifen. Nicht display:none,
   damit das Element klickbar/fokussierbar im DOM bleibt. */
.visually-hidden-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---- Floating-Label-Variante von .app-input (Google-/Material-Stil) ----
   Reines CSS, KEIN JavaScript. Funktioniert ueber zwei native CSS-Mechanismen:
   1. :placeholder-shown erkennt, ob das Feld leer ist (dafuer MUSS das Input
      ein - und sei es leeres - placeholder-Attribut haben, sonst greift die
      Pseudo-Klasse nicht).
   2. Die Geschwister-Kombinatoren (~) verschieben das <label>, das im Markup
      NACH dem <input> stehen muss (reine CSS-Beschraenkung: es gibt keinen
      "vorherigen Geschwister"-Selektor). Optisch steht das Label trotzdem
      VOR dem Text, weil es per position:absolute ueber dem Input liegt.
   Zustaende:
     - leer + kein Fokus  -> Label liegt UEBER dem Eingabetext (wirkt wie
       Placeholder).
     - Fokus ODER Wert vorhanden -> Label wandert VOLLSTAENDIG aus dem Rahmen
       heraus, oberhalb der Box (kein "Linie durchtrennen"-Trick mehr noetig -
       im Feld selbst war schlicht zu wenig Platz). Kein Hintergrund/Ueberlapp
       mit dem Rahmen mehr noetig.
   Abstand: .app-input-floating reserviert ueber margin-top FEST den Platz
   fuer das ausgeflogene Label, unabhaengig vom Zustand - dadurch bleibt der
   Abstand zum vorherigen Element (z.B. .form-label eines anderen Feldes,
   oder der Kopfzeile) IMMER gleich und springt beim Fokussieren nicht.
   Rahmen: die dickere Akzentlinie unten bei Fokus kommt weiterhin (wie bei
   .app-input) ueber :focus-within per box-shadow - der duenne Rahmen ringsum
   bleibt dabei unveraendert bestehen.
   Validierung: Klassen .is-valid / .is-invalid auf .app-input-floating
   faerben Rahmen, Label UND Bottom-Akzentlinie um (gruen/rot). */
.app-input-floating {
    position: relative;
    /* Gleiche Hoehe wie .app-input/.form-input (34px) - Eingabefelder sind
       app-weit einheitlich, die Floating-Variante bildet da keine Ausnahme. */
    height: 34px;
    /* Reservierter Fest-Abstand nach oben fuer das ausgeflogene Label -
       IMMER vorhanden, damit sich beim Fokussieren/Ausfuellen nichts
       verschiebt (kein Layout-Sprung). */
    margin-top: 20px;
}
.app-input-floating .app-input-field {
    height: 100%;
}
.app-input-floating .app-input-label {
    position: absolute;
    left: 9px;
    /* Rechter Rand analog zu left, damit lange Labels (z.B. "Neues Passwort
       bestaetigen *") auf schmalen Feldern (Login-Card auf Smartphone-Breite,
       AppInputFloating in schmalen Dialogen) nicht umbrechen, sondern wie das
       restliche App-generische Verhalten (siehe .app-input-field, .win11-*
       Zellen) sauber mit Ellipsis abgeschnitten werden. */
    right: 9px;
    /* Ruhezustand: mittig im Feld, wirkt wie ein Placeholder. */
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.875rem;
    line-height: 1;
    color: var(--neutral-foreground-hint);
    pointer-events: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: top 0.15s ease-in-out, font-size 0.15s ease-in-out, color 0.12s ease-in-out;
}
/* Wert vorhanden ODER Fokus -> Label komplett oberhalb der Box, im
   reservierten margin-top-Bereich. */
.app-input-floating .app-input-field:focus ~ .app-input-label,
.app-input-floating .app-input-field:not(:placeholder-shown) ~ .app-input-label {
    top: -18px;
    transform: none;
    font-size: 0.75rem;
    color: var(--neutral-foreground-secondary);
}
.app-input-floating .app-input-field:focus ~ .app-input-label {
    color: var(--accent-fill-rest);
}
/* Fokus-Rahmen + dicke Akzent-Unterlinie bleiben erhalten - NUR der
   Akzent-Hover-Hintergrund im Ruhezustand des Feldes entfaellt (siehe
   .app-input-floating weiter oben, dort kein :hover mehr definiert). */
.app-input-floating:focus-within {
    border-color: var(--input-stroke);
    box-shadow: inset 0 -2px 0 0 var(--accent-fill-rest);
}
/* Validierungszustaende: Rahmen + Label in Gruen/Rot, unabhaengig vom Fokus.
   Die Label-Regeln muessen HIER auch den fokussierten Fall
   (.app-input-field:focus ~ .app-input-label) explizit mit abdecken, sonst
   gewinnt die weiter oben stehende, hoeher spezifische Fokus-Regel (setzt die
   Akzentfarbe) und ueberschreibt Gruen/Rot, sobald das Feld fokussiert ist. */
.app-input-floating.is-valid {
    border-color: var(--input-stroke);
    box-shadow: inset 0 -2px 0 0 var(--success-color);
}
.app-input-floating.is-valid .app-input-label,
.app-input-floating.is-valid .app-input-field:focus ~ .app-input-label {
    color: var(--success-color);
}
.app-input-floating.is-invalid {
    border-color: var(--input-stroke);
    box-shadow: inset 0 -2px 0 0 var(--error-color);
}
.app-input-floating.is-invalid .app-input-label,
.app-input-floating.is-invalid .app-input-field:focus ~ .app-input-label {
    color: var(--error-color);
}

/* Hinweistext unter einem .app-input-floating-Feld (z.B. Fehlermeldung bei
   is-invalid, oder ein neutraler Hilfetext). Analog zu .form-hint, aber mit
   eigener Klasse, damit die Farbe je nach Validierungszustand des
   umgebenden Wrappers automatisch mitfaerbt (kein zusaetzliches JS/Binding
   fuer die Textfarbe noetig). */
.app-input-hint {
    display: block;
    margin-top: 2px;
    font-size: 0.75rem;
    color: var(--neutral-foreground-secondary);
}
.app-input-floating.is-invalid + .app-input-hint {
    color: var(--error-color);
}
.app-input-floating.is-valid + .app-input-hint {
    color: var(--success-color);
}

/* ---- Floating-Label-Select (AppSelectFloating.razor) ----
   Baut auf .app-input-floating auf (siehe oben), ersetzt aber das <input>
   durch einen <button> + ein eigenes <div>-Dropdown (siehe Begruendung im
   Kommentarkopf von AppSelectFloating.razor: weder natives <select> noch
   FluentSelect liessen sich exakt im App-Stil gestalten). Ein <button> hat
   nie einen "leeren" Placeholder-Zustand, daher steht das Label hier - wie
   beim vorherigen <select>-Versuch - IMMER oben, analog zum ausgefuellten
   Zustand eines Textfeldes. */
.app-select-floating .app-input-label {
    top: -18px;
    transform: none;
    font-size: 0.75rem;
    color: var(--neutral-foreground-secondary);
}
.app-select-floating.is-open .app-input-label,
.app-select-field:focus ~ .app-input-label {
    color: var(--accent-fill-rest);
}
/* Der Button uebernimmt Optik/Groesse von .app-input-field, braucht aber
   eigene Zuruecksetzung (kein Browser-Button-Standardrahmen/-Hintergrund)
   und ein flex-Layout fuer Wert-Text + Chevron-Icon. */
.app-select-field {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    box-sizing: border-box;
    background: transparent;
    border: none;
    outline: none;
    cursor: pointer;
    text-align: left;
    font: inherit;
}
.app-select-field:disabled {
    cursor: default;
    opacity: 1;
    color: var(--neutral-foreground-rest);
}
.app-select-value {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.app-select-chevron {
    flex: none;
    color: var(--neutral-foreground-hint);
    transition: transform 0.12s ease-in-out;
}
.app-select-floating.is-open .app-select-chevron {
    transform: rotate(180deg);
}
/* Stacking-Fix: .app-select-listbox hat position:absolute + z-index, aber
   das wirkt nur INNERHALB des Stacking-Contexts von .app-select-floating.
   Nachfolgende .app-input-floating-Geschwister bilden durch backdrop-filter
   (siehe .app-input) einen EIGENEN Stacking-Context mit z-index:auto und
   werden dadurch trotzdem in DOM-Reihenfolge ueber das Dropdown gemalt.
   Beim Oeffnen bekommt daher der GESAMTE Wrapper einen eigenen, hoeheren
   z-index, damit er inklusive Listbox ueber alle folgenden Felder liegt. */
.app-select-floating.is-open {
    position: relative;
    z-index: 10;
}
/* Eigenes Dropdown-Popup: liegt im normalen Dokumentfluss (position:
   absolute relativ zu .app-input-floating, das schon position:relative
   traegt) statt in einem Browser-/Shadow-DOM-Popup - dadurch greift jedes
   normale CSS (Padding, Breite, Hover) zuverlaessig, exakt wie bei jeder
   anderen Card/Liste der App. Gleiche Popup-Ebene wie fluent-menu/
   fluent-listbox (siehe dort), damit sich Custom- und Fluent-Popups optisch
   nicht unterscheiden. */
.app-select-listbox {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 4px);
    z-index: 100;
    max-height: 240px;
    overflow-y: auto;
    background: color-mix(in srgb, var(--neutral-foreground-rest) 12%, var(--neutral-layer-1));
    border: 1px solid var(--surface-stroke);
    border-radius: 4px;
    box-shadow: 0 8px 28px color-mix(in srgb, black 24%, transparent);
    padding: 4px;
}
/* Reicht der Platz unterhalb des Feldes nicht (z.B. letzte Zeile eines
   Formulars), oeffnet das Dropdown stattdessen nach oben - siehe
   shouldOpenUpward() in AppSelectFloating.razor.js. */
.app-select-listbox.opens-upward {
    top: auto;
    bottom: calc(100% + 4px);
}
.app-select-option {
    padding: 6px 10px;
    border-radius: 4px;
    font-size: 0.875rem;
    color: var(--neutral-foreground-rest);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.app-select-option:hover {
    background: var(--neutral-fill-stealth-hover, color-mix(in srgb, var(--neutral-foreground-rest) 8%, transparent));
}
.app-select-option.is-selected {
    color: var(--accent-fill-rest);
    font-weight: 600;
}

/* ---- Mehrfachauswahl-Variante (AppMultiSelectFloating.razor) ----
   Baut vollstaendig auf den app-select-*-Klassen oben auf (identisches
   Feld-/Popup-Aussehen), ergaenzt pro Option nur ein Checkbox-Icon links
   vom Text. Anders als bei AppSelectFloating bleibt is-selected hier NICHT
   fett/farbig (das wuerde bei vielen ausgewaehlten Zeilen unruhig wirken) -
   der Auswahlzustand wird stattdessen ausschliesslich ueber das
   Checkbox-Icon kommuniziert. */
.app-multi-select-option {
    display: flex;
    align-items: center;
    gap: 8px;
}
.app-multi-select-option.is-selected {
    color: var(--neutral-foreground-rest);
    font-weight: 400;
}
.app-multi-select-checkbox {
    flex: none;
    color: var(--neutral-foreground-hint);
}
.app-multi-select-option.is-selected .app-multi-select-checkbox {
    color: var(--accent-fill-rest);
}

/* ---- Inline-Zeile: Icon/Label + .app-input-floating in einer Reihe ----
   Wiederverwendbares Muster fuer Faelle, in denen ein Icon+Titel (z.B.
   "Neues Datenmodell") direkt neben EINEM Floating-Label-Feld steht, ohne
   Card/Row-Rahmen (z.B. Datenmodelle.razor). .app-input-floating reserviert
   bewusst margin-top:20px fuer das ausgeflogene Label (siehe oben) - das
   verschiebt das Feld gegenueber einem normalen Icon/Label-Paar sichtbar
   nach unten. Statt das je Seite einzeln zu kompensieren, hebt dieser
   Container-Klasse das Feld zentral wieder auf die gemeinsame Grundlinie:
   align-items:center gleicht das Reserve-margin optisch aus, sodass Icon,
   Titel-Text und Eingabefeld immer auf einer Achse stehen - unabhaengig
   davon, ob das Feld gerade leer/fokussiert ist oder nicht. */
.app-inline-label-field {
    display: flex;
    align-items: center;
    gap: 12px;
}
.app-inline-label-field > .app-input-floating {
    margin-top: 0;
}

/* ---- Popup-Ebene (Menues/Listboxen) ----
   Zweite Referenzebene ueber den Content-Flaechen: ein Popup schwebt und muss
   sich deshalb staerker absetzen als eine Card. Die frueher hier stehende,
   auskommentierte Fassung arbeitete mit --neutral-layer-3 und hatte damit
   exakt das Theme-Problem, das dieses Fundament beseitigt (feste Layer-Nummer
   = im Light dunkler, im Dark heller). Ersetzt durch dieselbe relative
   Berechnung wie --surface-elevate, nur mit hoeherem Anteil - dadurch ist der
   Abstand zur Card-Ebene in beiden Themes gleich gross.
   fluent-dialog ist hier bewusst NICHT enthalten: dessen ::part(control) wird
   weiter oben absichtlich transparent gesetzt, weil Dialog-Inhalte ihre
   eigene .surface-card-Flaeche mitbringen. */
fluent-menu,
fluent-listbox {
    background: color-mix(in srgb, var(--neutral-foreground-rest) 12%, var(--neutral-layer-1)) !important;
}

/* ---- Accordion (Content-Bereich) auf Fundament-Basis ----
   Das Accordion war der Ausloeser der Theme-Analyse: es sah in Light und Dark
   grundsaetzlich unterschiedlich aus. Grund war NICHT fehlerhaftes CSS,
   sondern dass es ueberhaupt keine eigene Regel hatte und damit voll auf
   Fluent-Defaults lief. Fluent gibt der Kopfzeile je Theme eine andere
   Eigenflaeche und eine Trennlinie mit theme-abhaengiger Staerke - im Dark
   deutlich sichtbar, im Light nahezu unsichtbar.

   Fix nach Fundament-Regel: die Kopfzeile bekommt eine EIGENE, klar vom
   Inhalt abgesetzte Flaeche, der Inhaltsbereich bleibt bewusst transparent
   (er liegt direkt auf dem Content-Untergrund). Dadurch ist der Absatz
   Kopf/Inhalt in BEIDEN Themes identisch stark, weil beide Werte relativ zum
   Vordergrund berechnet werden.

   WICHTIG zur Shadow-DOM-Struktur (haeufige Fehlerquelle): part="button" ist
   NICHT die Kopfzeile, sondern nur ein Kind von part="heading". Neben dem
   Button liegen als Geschwister part="start", part="end" und part="icon"
   (Chevron). Eine Flaeche auf ::part(button) faerbt daher nur die Textzeile
   und laesst Chevron und Slot-Bereiche unbedeckt. Die Flaeche gehoert
   deshalb auf ::part(heading); der Button wird transparent gehalten, damit
   seine Fluent-Eigenflaeche die Heading-Flaeche nicht ueberdeckt.

   Die Kopfzeile nutzt eine eigene, staerkere Anhebung als --surface-elevate:
   Sie liegt hier auf dem Content-Grund (nicht in einer Card) und muss sich
   daher deutlicher absetzen, sonst wirkt sie wie der Content-Bereich.

   Rahmen ergaenzt (--surface-stroke), damit die Flaeche denselben Kontrakt
   wie alle anderen Content-Ebenen (Card, Demo im Style Guide) erfuellt: jede
   angehobene Flaeche hat Flaeche + Rahmen + Radius, nie nur Flaeche allein.
   Vorher wich das Heading davon ab (nur Flaeche, kein Rahmen) - im Style
   Guide, der den Rahmen von Anfang an zeigte, war das nicht sichtbar. */
fluent-accordion-item::part(heading) {
    background: color-mix(in srgb, var(--neutral-foreground-rest) 12%, var(--neutral-layer-1));
    border: 1px solid var(--surface-stroke);
    border-radius: var(--surface-radius);
}

/* Button/Chevron ohne Eigenflaeche, damit die Heading-Flaeche durchscheint
   und die gesamte Kopfzeile einheitlich aussieht. */
fluent-accordion-item::part(button),
fluent-accordion-item::part(icon) {
    background: transparent;
}

/* Der Host selbst bleibt bewusst ohne Eigenflaeche. Ohne diese Regel gibt
   Fluent dem fluent-accordion-item eine eigene Flaeche - der Inhaltsbereich
   war dann zwar korrekt transparent, sass aber trotzdem sichtbar auf einer
   angehobenen Ebene statt auf dem Content-Grund. Genau dieser Widerspruch
   ("als transparent beschriftet, sieht aber angehoben aus") liess sich am
   Host mit rgb(51,51,51) im Dark nachmessen. Nur mit dieser Regel stimmt die
   Aussage "Inhalt liegt auf dem Content-Grund" tatsaechlich. */
fluent-accordion-item,
fluent-accordion {
    background: transparent;
}

/* Der Inhaltsbereich bleibt bewusst ohne eigene Flaeche: nur so bleibt der
   Kontrastabstand zur Kopfzeile in beiden Themes exakt derselbe. Der Rahmen
   nutzt bewusst dieselbe Fundament-Variable wie das Heading (--surface-stroke),
   damit Rahmen und Trennlinien app-weit dieselbe Staerke haben - eine eigene,
   kraeftigere Intensitaet (frueher 30% statt 18%) wirkte optisch wie ein
   dickerer Rahmen, obwohl beide technisch 1px breit sind. Einheitliche
   Staerke hat hier Vorrang vor zusaetzlichem Eigenkontrast. */
fluent-accordion-item::part(region) {
    background: transparent;
    border: 1px solid var(--surface-stroke);
    border-top: none;
    border-radius: 0 0 var(--surface-radius) var(--surface-radius);
}

.content-stack {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-width: 1000px;
}

/* ---- Backdrop-Filter-Bug bei Layout-Aenderungen (Resize/Rail) ----
   Siehe suppressBackdropFilterBriefly in app-shell.js: waehrend eines
   Fenster-Resizes oder der Rail-Breiten-Transition wird diese Klasse kurz
   auf <html> gesetzt. !important noetig, um JEDES backdrop-filter (Inputs,
   Sidebar, Header) zuverlaessig zu uebersteuern, unabhaengig von Spezifitaet. */
.disable-backdrop-filter,
.disable-backdrop-filter * {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
}
