/* =====================================================================
   components.css — Wiederverwendbare UI-Komponenten
   ---------------------------------------------------------------------
   Die Standard-Bausteine, die bisher in ~37 Page-<style>-Bloecken nahezu
   identisch dupliziert waren: Buttons, Cards, Tabellen, Formulare, Pills,
   Toasts. Hier EINMAL, token-basiert (tokens.css) — damit sie in Light +
   Dark automatisch korrekt aussehen.

   Lade-Reihenfolge: tokens.css -> theme.css -> components.css -> Page-
   Inline-<style>. Solange eine Page ihren eigenen :root/Komponenten-Block
   inline mitbringt, gewinnt dieser (spaetere Quell-Reihenfolge). Die
   Migration entfernt die Inline-Duplikate Seite fuer Seite — danach greift
   automatisch diese Datei.

   WICHTIG: Hier stehen nur GENERISCHE, seiten-uebergreifende Bausteine.
   Seitenspezifisches CSS bleibt in der jeweiligen Seite.
   ===================================================================== */

/* ---- Reset / Grundlayout ---- */
.cmp-scope * { box-sizing: border-box; }

/* ---- Nur fuer die Sprachausgabe ----
   Text, der vorgelesen, aber nicht gezeigt werden soll: Ansagen zu einer
   Aenderung, die man sieht (ein Chip kommt dazu), aber nicht hoert.
   NICHT `display:none` und nicht `visibility:hidden` — beides nimmt den
   Text auch aus dem Baum der Sprachausgabe. */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ---- Links (global, token-basiert) ---- */
/* Ohne diese Regel nutzen ungestylte <a> die Browser-Defaults
   (Blau/Lila) — im Dark-Mode schlecht lesbar. .btn/.nav-* u. a.
   setzen ihre eigene Farbe und gewinnen per hoeherer Spezifitaet. */
a { color: var(--theme-link); }
a:visited { color: var(--theme-link); }
a:hover { color: var(--theme-link-hover); }

/* ---- Globaler Tastatur-Fokus (WCAG 2.4.7) ----
   Sichtbarer, themebewusster Fokus-Ring auf ALLEN interaktiven Elementen.
   Vorher fielen die meisten Controls im Dark-Mode auf die nahezu schwarze
   UA-Default-Outline zurueck (kaum sichtbar). :focus-visible -> nur bei
   Tastatur-/Programm-Fokus, nicht bei Maus-Klick. :where() haelt die
   Spezifitaet bei 0, damit Komponenten (z. B. .form-field, .dispo-select)
   mit eigener :focus-visible-Regel ueberschreiben koennen. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--c-primary);
    outline-offset: 2px;
}

/* ---- EM-Chips: Touch-Drag (em-dnd.js) ---- */
/* Auf Touch-Geraeten startet ein langer Druck den Drag. Auswahl + iOS-
   Callout auf den Chips abschalten, damit dabei kein Text markiert und kein
   Kontextmenue geoeffnet wird. */
.em-chip { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
/* Der „Ghost" folgt dem Finger; pointer-events:none, damit elementFromPoint
   die Drop-Zone DARUNTER findet (nicht den Ghost selbst). */
.em-drag-ghost {
    position: fixed; z-index: var(--z-critical); pointer-events: none;
    transform: translate(-50%, -50%); opacity: 0.9;
    box-shadow: 0 6px 20px rgba(0,0,0,0.35);
}

/* ---- Buttons ---- */
.btn {
    text-decoration: none;
    padding: 6px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--theme-card-hover);
    color: var(--c-fg);
    font-size: var(--fs-13);
    cursor: pointer;
    font-family: inherit;
}
/* Als <a> behalten Buttons ihre neutrale Textfarbe — die globale
   a:visited/a:hover-Regel (0,1,1) wuerde sie sonst blau faerben (.btn allein
   ist nur 0,1,0). Bewusst VOR .primary/.danger platziert: die Modifier haben
   dieselbe Spezifitaet (0,2,0) und gewinnen damit per Quell-Reihenfolge,
   behalten also ihre eigene Farbe (#fff bzw. --c-error) auch im :visited-/
   :hover-Zustand. .btn faerbt beim Hover nur den Hintergrund. */
.btn:link, .btn:visited, .btn:hover { color: var(--c-fg); }
.btn.primary {
    background: var(--c-identity);
    color: #fff;
    border-color: var(--c-identity);
}
.btn.primary:link, .btn.primary:visited, .btn.primary:hover { color: #fff; }
.btn.primary:hover { background: var(--c-identity-strong); border-color: var(--c-identity-strong); }
.btn.danger {
    background: var(--theme-toast-err-bg);
    color: var(--c-error);
    border-color: var(--theme-toast-err-border);
}
/* Groessen-Modifier — reine Padding-/Schriftgroessen-Varianten, kombinierbar
   mit .primary/.danger (die nur Farbe setzen). .sm fuer kompakte Aktionsleisten
   (Bestand: vielfach inline als .btn.small), .lg fuer Formular-Primaeraktionen
   (Bestand: 9x18/10x20 in setup-wizard, branding, etb-reset, edit-Seiten). */
.btn.sm, .btn.small { padding: 4px 10px; font-size: var(--fs-12); }
.btn.lg             { padding: 9px 18px; font-size: var(--fs-base); }

/* Sekundaer-Link-Button (Topbar/Toolbar) — Bestand aus geocode-admin und
   hydrantenplan. Bewusst eigenstaendig neben .btn (anderes Padding, helleres
   Grau als Hintergrund). */
.btn-link {
    font: inherit;
    text-decoration: none;
    padding: 6px 11px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--c-btn-soft-bg);
    color: var(--c-fg);
    font-size: var(--fs-13);
    cursor: pointer;
}
.btn-link:hover { background: var(--c-btn-soft-hover); }
/* Wie .btn: neutrale Textfarbe als Link halten (Hover faerbt nur den
   Hintergrund, nicht den Text). */
.btn-link:link, .btn-link:visited, .btn-link:hover { color: var(--c-fg); }

/* ---- Toasts / Statusmeldungen ---- */
.toast {
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-13);
    margin-bottom: 14px;
}
.toast.ok {
    background: var(--theme-toast-ok-bg);
    color: var(--theme-toast-ok-fg);
    border: 1px solid var(--theme-toast-ok-border);
}
.toast.err {
    background: var(--theme-toast-err-bg);
    color: var(--theme-toast-err-fg);
    border: 1px solid var(--theme-toast-err-border);
}
.toast.warn {
    background: var(--theme-toast-warn-bg);
    color: var(--theme-toast-warn-fg);
    border: 1px solid var(--theme-toast-warn-border);
}

/* Schwebender Feedback-Toast — fixed, unten zentriert; per JS mit
   .is-visible ein-/ausgeblendet (einsatzmittel, geocode-admin).
   NICHT mit dem Inline-Banner .toast oben kombinieren. */
.toast-float {
    position: fixed;
    bottom: 18px;
    left: 50%;
    transform: translateX(-50%) translateY(20px);
    background: var(--c-toast-float-bg);
    color: #fff;
    padding: 10px 16px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-13);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s, transform 0.18s;
    z-index: var(--z-toast);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}
.toast-float.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}
.toast-float.is-error   { background: var(--c-error); }
.toast-float.is-success { background: var(--c-success); }

/* ---- Lade-Spinner + Status-Banner ---- */
@keyframes spin { to { transform: rotate(360deg); } }
.spinner {
    display: inline-block;
    width: 13px;
    height: 13px;
    border: 2px solid rgba(0, 0, 0, 0.18); /* neutraler Ring, beide Themes */
    border-top-color: var(--c-primary);
    border-radius: 50%;
    animation: spin 0.85s linear infinite;
}

/* Status-/Stand-Anzeige ueber Listen ("Lade…" / "Stand: 12:00"). Das
   Layout (margin/flex) bleibt Sache der Seite. */
.status-banner { font-size: var(--fs-13); color: var(--c-muted); }
.status-banner.is-error { color: var(--c-error); font-weight: 600; }

/* ---- Cards ---- */
.card {
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: 10px;
    padding: 16px 18px;
    margin-bottom: 16px;
    box-shadow: var(--theme-shadow);
}
.card h2 { margin: 0 0 12px; font-size: 15px; }

/* ---- Formulare ---- */
.form-grid {
    display: grid;
    /* Label-Spaltenbreite ueber Variable: einzelne Seiten setzen nur noch
       --form-label-col (statt grid-template-columns DIREKT zu ueberschreiben),
       sonst gewinnt ihr spaeter geladenes Inline-<style> gegen den mobilen
       1-Spalten-Reflow unten (gleiche Spezifitaet, spaetere Quelle). */
    grid-template-columns: var(--form-label-col, 160px) 1fr;
    gap: 10px 14px;
    align-items: center;
}

/* === Einheitlicher Dropdown-Stil =======================================
   Alle <select> bekommen den Look des Disponent-Dropdowns (Token-basiert;
   die Dark-Farben setzt theme.css global). Ausgenommen die farbig
   hinterlegten Status-Selects (.status-select). So sehen Kommentar-Ziel-,
   Bulk- und Alarm-Dropdowns konsistent aus wie die Disponent-Zuweisung. */
select:not(.status-select):not(.sp-status-select) {
    font: inherit; font-size: var(--fs-13);
    padding: 5px 28px 5px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--theme-input-bg); color: var(--c-fg);
    cursor: pointer;
}

/* === Filter-Chip (Standard, wie Lagekarte) =============================
   Farbiger Punkt + kleines Label; inaktive Chips gedimmt. Checkbox visuell
   versteckt, aber tastatur-fokussierbar (:focus-within). Standard fuer ALLE
   Filter dieser Art (Lagekarte, Einsatz-Filter ...). Dark-Overrides: theme.css. */
.status-filter-group { display: flex; flex-wrap: wrap; gap: 4px; }
.status-pill {
    display: inline-flex; align-items: center; gap: 6px;
    background: var(--c-card); border: 1px solid var(--c-border);
    border-radius: 14px; padding: 4px 10px;
    font-size: var(--fs-12); cursor: pointer; user-select: none;
    transition: opacity 0.12s, background 0.12s, border-color 0.12s, box-shadow 0.12s;
}
.status-pill input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); }
.status-pill .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--c-st-gray); flex-shrink: 0; }
.status-pill[data-color="green"]   .dot { background: var(--c-st-green); }
.status-pill[data-color="red"]     .dot { background: var(--c-st-red); }
.status-pill[data-color="red-alt"] .dot { background: var(--c-st-red-alt); }
.status-pill[data-color="orange"]  .dot { background: var(--c-st-orange); }
.status-pill[data-color="violet"]  .dot { background: var(--c-st-violet); }
.status-pill[data-color="gray"]    .dot { background: var(--c-st-gray); }
.status-pill:has(input:not(:checked)) { opacity: 0.5; }
/* Aktiver Filter-Chip: nicht NUR ueber Deckkraft (im Hell-Modus schwer
   ablesbar), sondern zusaetzlich ueber einen roten Ring — klare
   Selektions-Affordanz. Inset-Shadow statt 2px-Border = kein Layout-Sprung. */
.status-pill:has(input:checked) { border-color: var(--c-identity); box-shadow: inset 0 0 0 1px var(--c-identity); }
.status-pill:hover { background: var(--c-btn-soft-hover); }
.status-pill:focus-within { outline: 2px solid var(--c-primary); outline-offset: 1px; }

/* TEXTFELD-STYLING — ausdruecklich NICHT fuer Haken und Radios.
 *
 * `width: 100%`, Innenabstand, Rahmen und Hintergrund sind fuer Felder
 * gedacht, in die man schreibt. Auf einer Checkbox blaehen sie das native
 * Kaestchen auf: Der Browser skaliert es mit, und aus dem Haken wird ein
 * Klotz. Zusammen mit der Tippziel-Regel weiter unten stand auf der
 * Meldungsarten-Seite ein 44 Pixel grosser blauer Haken (Michael,
 * 30.08.2026).
 *
 * Ausgenommen bleibt hier nur das AUSSEHEN. Dass ein Haken auf dem Tablet
 * trotzdem gut zu treffen sein muss, loest sein Label — app-weit in #219. */
.form-grid input:not([type="checkbox"]):not([type="radio"]),
.form-grid textarea,
.form-grid select {
    font: inherit;
    font-size: var(--fs-base);
    padding: 7px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--theme-input-bg);
    color: var(--c-fg);
    width: 100%;
}

/* Haken und Radios im Formularraster: native Groesse, links ausgerichtet. */
.form-grid input[type="checkbox"],
.form-grid input[type="radio"] {
    width: auto;
    accent-color: var(--c-primary);
}
.form-grid textarea {
    min-height: 60px;
    font-family: ui-monospace, "Consolas", monospace;
    font-size: var(--fs-sm);
}
.form-grid label { font-size: var(--fs-13); color: var(--c-muted); }

/* .hint — der kleine erklaerende Nachsatz.
 *
 * Bis zum 28.08.2026 war er NUR innerhalb von `.form-grid` definiert.
 * Freistehend fiel er auf 14px Fliesstext zurueck — auf ein und derselben
 * Seite sah dieselbe Klasse dadurch zweimal anders aus, je nachdem ob sie
 * in einem Formularraster stand. Dieselbe Aufteilung wie bei `.lead-note`
 * weiter unten: die Erscheinung allgemein, der Abstand im Kontext. */
.hint {
    font-size: 11.5px;
    color: var(--c-muted);
    font-style: italic;
}
.form-grid .hint { margin-top: 2px; }
/* TIPPZIELE IM FORMULARRASTER (28.08.2026).
 *
 * Der mobile Block weiter unten hebt nur `.form-field`-Felder an —
 * `.form-grid` war nicht erfasst und blieb bei rund 33 px. Michael arbeitet
 * auf dem Tablet; dort ist das zu klein. 44 px ist das Mass, das die
 * Anwendung an ihren uebrigen Feldern schon benutzt.
 *
 * HAKEN UND RADIOS SIND AUSGENOMMEN (Michael, 30.08.2026: „der Aktiv-Knopf
 * ist aber gross geworden").
 *
 * Ein `min-height` auf einem Textfeld vergroessert die Trefferflaeche. Auf
 * einer Checkbox vergroessert es das KAESTCHEN — der Browser skaliert das
 * native Element mit. Auf der Meldungsarten-Seite stand deshalb ein
 * 44 Pixel grosser blauer Haken neben normalgrossen Feldern.
 *
 * Die Regel stand ausserdem auf oberster Ebene statt in der Touch-Media-
 * Query wie ihre Schwester `.form-field` weiter unten — sie traf also auch
 * jeden Schreibtisch-Bildschirm. Beides zusammen: eine Touch-Verbesserung,
 * die am Schreibtisch als Fehler ankam.
 *
 * Ein Haken braucht keine 44 Pixel Kaestchen, sondern eine 44 Pixel grosse
 * ANFASSFLAECHE — das ist Sache seines Labels und wird app-weit in #219
 * nachgezogen. */
.form-grid input:not([type="checkbox"]):not([type="radio"]),
.form-grid select,
.form-grid textarea { min-height: 44px; }
.form-grid textarea { min-height: 88px; }

.form-actions { margin-top: 14px; display: flex; gap: 8px; }
.row-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* ---- Tabellen ----
   Greift auf Seiten mit der Marker-Klasse .cmp-scope (am <body> oder einem
   Wrapper) fuer schlichte <table> sowie generell fuer .cmp-table. So bleibt
   das globale <table> der nicht-migrierten Seiten unberuehrt — nur wer sich
   per .cmp-scope opt-in anmeldet (migrierte Seiten) bekommt den Standard. */
.cmp-scope table,
.cmp-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: 10px;
    overflow: hidden;
    box-shadow: var(--theme-shadow);
    font-size: var(--fs-13);
}
.cmp-scope th,
.cmp-scope td,
.cmp-table th,
.cmp-table td {
    padding: 9px 12px;
    text-align: left;
    border-bottom: 1px solid var(--c-border-l);
    vertical-align: middle;
}
.cmp-scope th,
.cmp-table th {
    background: var(--theme-card-hover);
    color: var(--c-muted);
    font-size: var(--fs-12);
    text-transform: uppercase;
    letter-spacing: 0.4px;
}
.cmp-scope tbody tr:last-child td,
.cmp-table tbody tr:last-child td { border-bottom: 0; }

/* ---- Pills ---- */
.pill {
    display: inline-block;
    padding: 2px 9px;
    border-radius: var(--radius-lg);
    font-size: var(--fs-xs);
    font-weight: 600;
}
.pill-on  { background: #dff6e3; color: #1f6f3a; }
.pill-off { background: var(--theme-card-hover); color: var(--c-muted); }
/* Warnende Pille (31.08.2026) — fuer Zustaende, die nicht kaputt sind,
   aber Folgen haben: eine fehlende Ausrueckeordnung heisst, dass ein von
   Hand ausgeloester Alarm dort niemanden erreicht. Token statt Hex, damit
   der Dunkelmodus mitkommt (.pill-on daneben ist Bestand mit Hex und beim
   naechsten Design-Durchgang faellig). */
.pill-warn {
    background: var(--theme-toast-warn-bg);
    color: var(--theme-toast-warn-fg);
}
/* Admin-Rollen-Pills — zentrale Light+Dark-Defaults (token-basiert).
   Vorsorglich zentral: bislang nutzt nur users.php diese Klassen (inline,
   Light), die Dark-Werte lagen global in theme.css. Die Token-Regel macht
   beide Themes konsistent; Etappe 6 loest die theme.css-Duplikate auf. */
.pill-admin { background: var(--c-pill-admin-bg); color: var(--c-pill-admin-fg); }
.pill-lage  { background: var(--c-pill-lage-bg);  color: var(--c-pill-lage-fg); }

/* ---- Auswahl-Chips (Checkbox in Chip-Form, z. B. Trigger-Orte) ---- */
.ort-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: 14px;
    font-size: var(--fs-sm);
    cursor: pointer;
    user-select: none;
}
/* Checkbox visuell ausblenden — die Pille selbst ist der Toggle (wie
   .checkpill), damit die Orts-Auswahl als saubere Pille erscheint und mit
   den EM-Pool-Chips harmoniert. Tastatur-Fokus bleibt erhalten. */
.ort-chip input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); }
.ort-chip:focus-within { outline: 2px solid var(--c-primary); outline-offset: 1px; }
.ort-chip:has(input:checked) {
    background: var(--c-chip-on-bg);
    border-color: var(--c-primary);
    color: var(--c-fg);   /* Light: dunkler Text auf hellblau; Dark: heller Text auf dunkelblau */
}

/* ---- Aktions-Spalte (Tabellen) ---- */
.col-act { text-align: right; white-space: nowrap; }
.col-act .btn { padding: 4px 8px; font-size: var(--fs-12); }

/* ---- Mono-Aliasse / Codes ---- */
.alias,
.key-mono {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--c-muted);
}

/* ---- Leerer Zustand ---- */
.empty-state {
    padding: 28px;
    text-align: center;
    color: var(--c-muted);
    font-size: var(--fs-base);
    background: var(--c-card);
    border: 1px dashed var(--c-border);
    border-radius: 10px;
}
.empty-state a { color: var(--c-primary); }

/* Filter-Hinweis (z. B. Dispo-Default „nur meine Einsaetze", Etappe 1.6). */
.filter-hint {
    margin: 0 0 12px;
    padding: 8px 12px;
    background: var(--theme-card-hover);
    border: 1px solid var(--c-border);
    border-left: 3px solid var(--c-primary);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    color: var(--c-fg);
}
.filter-hint a { color: var(--c-primary); }

/* SP-Personalstaerke (#34): kompakte Aufschluesselung „N im Einsatz · M
   Reserve" neben der Gesamt-Pill. Farbe via currentColor + Transparenz —
   passt sich an helle Listen wie an den dunklen SP-Banner an (keine feste
   Farbe noetig). */
.personal-split-break {
    font-size: var(--fs-xs);
    font-weight: 600;
    opacity: 0.72;
}

/* =====================================================================
   Form-Field-Komponente (Etappe 0.5) — Label + Input + Inline-Fehler
   ---------------------------------------------------------------------
   Vertikales Feld mit Fehler-Slot. Zustaende: .has-error / aria-invalid.
   Der Fehlertext traegt role="alert" (Markup/JS) und wird von
   form-validate.js gesetzt — nur textContent/setAttribute, nie
   innerHTML (kein XSS ueber Server-Fehlertexte).
   ===================================================================== */
.form-field { display: flex; flex-direction: column; gap: var(--sp-xs); margin-bottom: var(--sp-md); }
.form-field > label { font-size: var(--fs-sm); color: var(--c-muted); font-weight: 500; }
.form-field .req { color: var(--c-error); margin-left: 2px; }   /* Pflichtfeld-Stern */
.form-field input,
.form-field textarea,
.form-field select {
    font: inherit;
    font-size: var(--fs-base);
    padding: 8px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--theme-input-bg);
    color: var(--c-fg);
    width: 100%;
}
.form-field input:focus-visible,
.form-field textarea:focus-visible,
.form-field select:focus-visible {
    outline: 2px solid var(--c-primary);
    outline-offset: 1px;
    border-color: var(--c-primary);
}
.form-field .field-error {
    font-size: var(--fs-xs);
    color: var(--c-error);
    display: none;
}
/* Fehlerzustand: rote Umrandung + Fehlertext sichtbar. Greift ueber die
   Klasse .has-error ODER aria-invalid am Feld. */
.form-field.has-error input,
.form-field.has-error textarea,
.form-field.has-error select,
.form-field input[aria-invalid="true"],
.form-field textarea[aria-invalid="true"],
.form-field select[aria-invalid="true"] {
    border-color: var(--c-error);
}
.form-field.has-error .field-error { display: block; }
/* Auch bei server-gerendertem aria-invalid (ohne .has-error) den Fehlertext
   zeigen — sonst roter Rahmen ohne Meldung. */
.form-field:has([aria-invalid="true"]) .field-error { display: block; }

/* Server-gerenderter Feldfehler AUSSERHALB eines .form-field-Slots.
   Die Verwaltungsseiten bauen ihre Formulare als .form-grid (Label-Spalte +
   Wert-Spalte), da gibt es den Fehler-Slot nicht. Der Text wird dort nur
   ausgegeben, wenn es wirklich einen Fehler gibt — deshalb keine
   display:none-Grundstellung, sondern nur die Auszeichnung.
   Zusammen mit aria-invalid + aria-describedby am Feld erfuellt das die
   Hausregel „Fehler gehoeren ans Feld" auch ohne JavaScript. */
.feld-fehler {
    margin: 6px 0 0;
    font-size: var(--fs-xs);
    color: var(--c-error);
    font-weight: 600;
}

/* ---- Einheitliches Text-Eingabefeld (Standard, #172-UX) ----
   Ein Feld-Look fuer die ganze App: dieselben Tokens/Groessen wie
   .form-field, aber als eigenstaendige Klasse fuer Dialoge, die kein
   .form-field-Grid nutzen (EM-Zuweisung, ueOert-Anlage). */
.etb-input {
    font: inherit;
    font-size: var(--fs-base);
    padding: 8px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--theme-input-bg);
    color: var(--c-fg);
    width: 100%;
}
.etb-input:focus-visible {
    outline: 2px solid var(--c-primary);
    outline-offset: 1px;
    border-color: var(--c-primary);
}

/* ---- Staerke-Eingabe A/B/C = S (Standard, #168) ----
   Drei kompakte Zahlenfelder + berechnete Gesamtsumme. Wird im
   EM-Zuweisungs-Dialog UND in der ueOert-Anlage identisch genutzt.
   Die Trenner „/" und „=" fluchten mit den EINGABEFELDERN (obere Reihe),
   nicht mit dem Feld+Beschriftung-Block — daher align-items:flex-start
   und feste Trenner-Hoehe gleich der Feldhoehe. */
.staerke-input { display: flex; align-items: flex-start; gap: 6px; }
.staerke-input .st-cell { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.staerke-input .st-num {
    width: 44px; height: 34px; text-align: center;
    font: inherit; font-size: var(--fs-base);
    padding: 4px 4px;
    border: 1px solid var(--c-border); border-radius: var(--radius-sm);
    background: var(--theme-input-bg); color: var(--c-fg);
    -moz-appearance: textfield;
}
.staerke-input .st-num:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; border-color: var(--c-primary); }
.staerke-input .st-sum {
    display: inline-flex; align-items: center; justify-content: center;
    width: 48px; height: 34px;
    font-size: var(--fs-base); font-weight: 700;
    border: 1px solid var(--c-border); border-radius: var(--radius-sm);
    background: var(--c-pill-muted-bg); color: var(--c-fg);
    text-decoration: underline double; text-underline-offset: 2px;
}
/* Trenner: gleiche Hoehe wie die Felder (34px), vertikal zentriert ->
   fluchtet mit der Feld-Reihe, nicht mit dem Feld+Cap-Block. */
.staerke-input .st-sep {
    height: 34px; display: inline-flex; align-items: center;
    color: var(--c-muted); font-weight: 600;
}
.staerke-input .st-cap { font-size: 10.5px; color: var(--c-muted); }

/* =====================================================================
   Design „Mischung" — wiederverwendbare Bausteine (Etappe 0.5.4)
   ---------------------------------------------------------------------
   Reine Bausteine; die flaechige Anwendung erfolgt in den Feature-
   Etappen (Liste/Filter in Etappe 1, SP-Kontext in Etappe 4, Etappe 6).
   ===================================================================== */

/* Listen-Zeilen-Statusleiste ueber data-status (Etappe 1): linke farbige
   Leiste auf der ersten Zelle, ohne Layout-Shift (box-shadow inset). Der
   Status-Text (Pill) bleibt der primaere Traeger — die Leiste doppelt nur. */
tbody tr[data-status] > td:first-child { box-shadow: inset 4px 0 0 0 var(--status-accent, transparent); }
/* Akzent = die (konfigurierbare, #164) Status-Vollton-Farbe = Kachel-bg-
   Token, damit Zeilenbalken, Pill-Grund und Kachel EINE Farbe zeigen. */
tbody tr[data-status="neu"]            { --status-accent: var(--c-kachel-neu-bg); }
tbody tr[data-status="dispo"]          { --status-accent: var(--c-kachel-dispo-bg); }
tbody tr[data-status="in_bearbeitung"] { --status-accent: var(--c-kachel-bearb-bg); }
tbody tr[data-status="erledigt"]       { --status-accent: var(--c-kachel-erledigt-bg); }
tbody tr[data-status="abgeschlossen"]  { --status-accent: var(--c-kachel-abgeschlossen-bg); }

/* ---- Toggle-Chip (Filter) ----
   An/Aus-Filter-Chip (Status-Filter in Etappe 1). Zustand ueber
   [aria-pressed="true"] ODER .is-active. Sichtbarer Fokusring. */
.toggle-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    min-height: 34px;
    border: 1px solid var(--c-border);
    border-radius: 16px;
    background: var(--c-card);
    color: var(--c-fg);
    font: inherit;
    font-size: var(--fs-sm);
    cursor: pointer;
    user-select: none;
}
.toggle-chip:hover { background: var(--c-btn-soft-hover); }
.toggle-chip[aria-pressed="true"],
.toggle-chip.is-active {
    background: var(--c-chip-on-bg);
    border-color: var(--c-primary);
    font-weight: 600;
}
.toggle-chip:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; }

/* ---- Icon-Basis (Inline-SVG via IconLibrary::render) ----
   Tabler-Style (Outline): erbt die Textfarbe ueber currentColor und
   skaliert mit der Schriftgroesse. */
.icon {
    width: 1.15em;
    height: 1.15em;
    display: inline-block;
    vertical-align: -0.15em;
    flex: none;
    fill: none;
    stroke: currentColor;
}

/* =====================================================================
   Mobile-Schliff (<= 760px) — zentrale, seiten-uebergreifende Regeln
   ---------------------------------------------------------------------
   Ergaenzt das Off-Canvas-Menue (MainNavSidebar). Formulare einspaltig,
   groessere Touch-Ziele, breite Admin-Datentabellen horizontal scrollbar.
   ===================================================================== */
/* 800 px, nicht 760 (#214 + UX-Befund 22.08.2026).
   Portrait-Tablets liegen bei 768/810/820/834 px — der alte Breakpoint
   verfehlte genau die Geraete, auf denen hier getestet wird. Bei 800 px
   schaltet auch MainNavSidebar auf die mobile Leiste um; dazwischen war die
   Leiste mobil und die Knoepfe am Desktop-Mass. */
@media (max-width: 800px) {
    .form-grid { grid-template-columns: 1fr; gap: 6px 0; }
    .form-grid label { padding-top: 0; }
    .row-pair { grid-template-columns: 1fr; }

    /* Touch-Mindestgroessen (Finger statt Maus; WCAG 2.5.x).
       `.btn.sm` ausdruecklich MIT: Die Variante ist fuer enge Tabellen
       gedacht, aber auf dem Tablet ist sie oft die Hauptaktion einer Zeile —
       und stand dort mit 24 px neben 48-px-Nachbarn. */
    .btn, .btn-link { min-height: 44px; }
    .btn.sm, .btn.small { min-height: 44px; padding: 8px 12px; }
    .ort-chip { min-height: 44px; }
    .toggle-chip { min-height: 44px; }
    .checkpill { min-height: 44px; }  /* #124: Status-Filter-Chips, analog .toggle-chip */
    .form-field input, .form-field textarea, .form-field select { min-height: 44px; }

    /* Breite Datentabellen (Admin-CRUD) horizontal scrollbar statt rechts
       abgeschnitten — sowohl explizite .cmp-table als auch die schlichten
       <table> der .cmp-scope-Seiten. sp-table ausgenommen: eigenes Karten-
       Layout, display:block bricht dort die Spalten (vgl. V4-1-Regression). */
    /* `:not([hidden])` ist kein Schoenheitsfehler-Schutz, sondern noetig:
       Diese Regel ist eine AUTOR-Regel mit `display` und schlaegt damit das
       `[hidden] { display: none }` des Browsers (UA-Ursprung), unabhaengig
       von der Spezifitaet. Ohne sie rendert jede mit `hidden` versteckte
       Tabelle einer .cmp-scope-Seite auf schmalen Geraeten trotzdem — auf
       der Atemschutz-Uebersicht stand die leere Kopfzeile unter dem
       Leerzustand. Die Tafel fing das mit einem eigenen
       `[hidden] { display: none !important }` ab; die Uebersicht laedt
       deren Stylesheet bewusst nicht (UX-Abnahme 09.09.2026, Blocker B1). */
    .cmp-table:not([hidden]),
    .cmp-scope table:not(.sp-table):not([hidden]) { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* === EM-Tap-Zuweisen (Touch-Alternative zum Drag) ====================== */
.em-tap-picker {
    position: fixed; inset: 0; z-index: var(--z-critical);
    background: rgba(0,0,0,0.45);
    display: flex; align-items: flex-end; justify-content: center;
}
.em-tap-sheet {
    width: 100%; max-width: 520px;
    background: var(--c-card); color: var(--c-fg);
    border-radius: 16px 16px 0 0;
    max-height: 72vh; display: flex; flex-direction: column;
    box-shadow: 0 -8px 30px rgba(0,0,0,0.28);
}
.em-tap-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 14px 16px; border-bottom: 1px solid var(--c-border-l);
}
.em-tap-head strong { font-size: 15px; font-weight: 600; }
.em-tap-x {
    flex-shrink: 0; width: 32px; height: 32px; border: 0; background: transparent;
    color: var(--c-muted); font-size: var(--fs-xl); line-height: 1; cursor: pointer; border-radius: 7px;
}
.em-tap-x:hover { background: var(--c-btn-soft-hover); color: var(--c-fg); }
.em-tap-list { overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.em-tap-target {
    text-align: left; padding: 12px 14px; min-height: 48px;
    border: 1px solid var(--c-border); border-radius: 10px;
    background: var(--c-card); color: var(--c-fg);
    font: inherit; font-size: var(--fs-base); cursor: pointer;
    transition: background 0.1s, border-color 0.1s;
}
.em-tap-target:hover { background: var(--c-btn-soft-hover); border-color: var(--c-primary); }
/* :active fuer spuerbares Tap-Feedback auf Touch (kein Hover dort). */
.em-tap-target:active { background: var(--c-btn-soft-hover); border-color: var(--c-primary); }
.em-tap-target:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; }
@media (min-width: 560px) {
    .em-tap-picker { align-items: center; }
    .em-tap-sheet { border-radius: 14px; }
}
/* Hinweis-Schnipsel nur auf Touch-Geraeten (kein Hover) einblenden — z. B.
   „… oder antippen" in den EM-Zuweis-Hinweisen. */
.touch-only { display: none; }
@media (hover: none) { .touch-only { display: inline; } }

/* === Modal-Schliessen-X (oben rechts) ===================================
   Geteiltes Schliessen-X fuer alle bespoke Modals (.sp-modal, add-einsatz-,
   sp-dispo-, pw-modal, sp-assign- usw.). Die Modal-Box muss position:relative
   sein. Wirkt wie „Abbrechen". */
/* 40x40 statt 30x30 (#214, 22.08.2026): Die 30 px erfuellten WCAG 2.5.8
   (24 px), aber nicht die Haus-Regel von 40. In der Vollbild-Lagekarte auf
   dem Tablet ist dieses X der Hauptausgang — dort trifft man es nur mit dem
   Fingernagel. Das SYMBOL bleibt 18 px, nur die Trefferflaeche waechst; die
   Optik aendert sich also kaum, der Rand um das X wird groesser. */
.modal-x {
    position: absolute; top: 8px; right: 8px;
    width: 40px; height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0; border: none; background: transparent; border-radius: 8px;
    color: var(--c-muted); cursor: pointer;
    transition: background 0.1s ease, color 0.1s ease;
}
.modal-x:hover { background: var(--c-chip-bg); color: var(--c-fg); }
.modal-x:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; }
.modal-x svg { width: 18px; height: 18px; }

/* === Karten-Schalter (#214) ============================================
   EIN Schalter zum Ein- und Ausblenden einer Karten-Ebene — Hydranten,
   DWD-Warnungen, Regenradar, Blitze, Vollbild. Vorher sprach dieselbe
   Handlung drei Sprachen: eine 40-px-Pille auf der Wetterseite, ein
   ~28-px-Kaestchen in der Einsatz-Lightbox und ein Textlink auf der
   Lagekarte. Der kleinste sass ausgerechnet dort, wo auf dem Tablet
   gearbeitet wird.

   NICHT GEDRUECKT = neutral, GEDRUECKT = VOLL gefuellt. Ein blosser
   Rahmenwechsel ist auf einem Tablet im Sonnenlicht nicht zu erkennen;
   `aria-pressed` traegt den Zustand zusaetzlich fuer die Sprachausgabe. */
.karten-chip {
    display: inline-flex; align-items: center; gap: 6px; min-height: 40px;
    padding: 8px 16px; border-radius: 999px;
    border: 1px solid var(--c-border); background: var(--c-card);
    color: var(--c-fg); font: inherit;
    font-size: var(--fs-13); font-weight: 600; cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.karten-chip:hover { background: var(--c-btn-soft-hover); }
.karten-chip svg { width: 16px; height: 16px; }
.karten-chip[aria-pressed="true"] {
    background: var(--c-identity); border-color: var(--c-identity);
    color: var(--c-identity-fg);
}
.karten-chip:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 2px; }
/* Waehrend die Ebene laedt: sichtbar, aber nicht gesperrt. */
.karten-chip.is-loading { opacity: 0.6; cursor: progress; }

/* === Standard-Stern fuer Admin-Kataloge (Wichtigkeit/Status/…) ==========
   Gold gefuellter Stern = aktueller Standard; in den uebrigen Zeilen ein
   grauer, klickbarer Stern, der den Standard setzt. Immer genau einer gold. */
/* Gleiche Box (display + padding!) wie .cat-star-btn, damit der gold
   gefuellte Standard-Stern exakt ueber den klickbaren Sternen der anderen
   Zeilen sitzt und nicht nach links versetzt erscheint. */
.cat-star { color: #f1c40f; font-size: 19px; line-height: 1; display: inline-block; padding: 2px 6px; }
.cat-star-btn {
    background: none; border: none; cursor: pointer;
    color: var(--c-border); font-size: 19px; line-height: 1;
    padding: 2px 6px; transition: color 0.12s ease, transform 0.1s ease;
}
.cat-star-btn:hover { color: #f1c40f; transform: scale(1.15); }
.cat-star-btn:focus-visible { color: #f1c40f; outline: 2px solid var(--c-primary); outline-offset: 1px; }
/* #41: aktiver Eil/Zeit-Marker (●) — Primary-Farbe statt des geerbten,
   blassen --c-border (das WCAG 1.4.11 verfehlt); bewusst NICHT gold, damit
   die Sondersignal-Zuordnung vom gold gefuellten Standard-Stern
   unterscheidbar bleibt. Trifft nur die Eil/Zeit-Buttons — der aktive
   Standard nutzt ein span.cat-star ohne .is-on. */
.cat-star-btn.is-on { color: var(--c-primary); font-weight: 700; }

/* === Live-Refresh-Umschalter (.live-refresh) ==========================
   Einheitlicher segmentierter Pillen-Umschalter fuer alle Seiten mit
   Auto-Refresh (Einsatz-Uebersicht, Dashboard). Kollisionsfreie Klassen-
   Namen — kein Overlap mit .pill/.live-btn der Lagekarte.
   Nur Tokens, kein hartkodiertes Hex-Farbwert.
   ==================================================================== */
.live-refresh {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.live-refresh-label {
    font-size: var(--fs-12);
    color: var(--c-muted);
    white-space: nowrap;
}
.live-refresh-group {
    display: inline-flex;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.live-refresh-btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 28px;
    padding: 5px 10px;
    font-size: var(--fs-sm);
    line-height: 1;
    border: 0;
    border-right: 1px solid var(--c-border);
    background: var(--c-card);
    color: var(--c-fg);
    cursor: pointer;
    font-family: inherit;
    transition: background 0.1s ease;
}
.live-refresh-btn:last-child { border-right: 0; }
.live-refresh-btn:hover { background: var(--theme-card-hover); }
.live-refresh-btn.is-active { background: var(--c-identity); color: #fff; }
.live-refresh-btn:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; z-index: 1; position: relative; }

/* Touch-Geraete: etwas groesseres Tippziel (min-height 36 px, analog .btn).
   Greift nur auf echten Touch-Geraeten (kein Maus-Hover moeglich). */
@media (hover: none) {
    .live-refresh-btn { padding: 8px 12px; min-height: 36px; }
}

/* ---- Abschnitts-Sperr-Dialog (#162, abschnitt-sperre.js) ----
   "Abschnitte noch in Arbeit" beim Erledigen/Abschliessen eines Einsatzes —
   blockierende Abschnitte direkt im Dialog erledigen. */
.absperre-overlay {
    position: fixed; inset: 0; z-index: var(--z-sheet);
    background: rgba(0, 0, 0, 0.45);
    display: flex; align-items: center; justify-content: center; padding: 16px;
}
.absperre-box {
    background: var(--c-card); border: 1px solid var(--c-border);
    border-radius: var(--radius-lg); padding: 16px 18px;
    width: min(520px, 100%); max-height: 80vh; overflow-y: auto;
}
.absperre-title { margin: 0 0 6px; font-size: var(--fs-md); }
.absperre-msg { font-size: var(--fs-13); color: var(--c-muted); margin: 0 0 10px; }
.absperre-row {
    display: flex; align-items: center; gap: 10px;
    padding: 7px 2px; border-bottom: 1px solid var(--c-border-l);
}
.absperre-row:last-child { border-bottom: 0; }
.absperre-nr { font-family: var(--font-mono); font-size: var(--fs-12); font-weight: 700; color: var(--c-muted); min-width: 46px; text-align: center; }
.absperre-name { flex: 1; min-width: 0; font-size: var(--fs-base); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.absperre-do { white-space: nowrap; flex-shrink: 0; min-height: 36px; }
.absperre-foot { display: flex; justify-content: flex-end; margin-top: 12px; }
/* Zeile mit Begruendung (Stufe 0 im Erledigen-Modal: warum eine Warnung
   hier nicht abschliessbar ist). Die Basis-Zeile kuerzt einzeilig mit
   Ellipse — der Grund braucht dagegen Umbruch, sonst wird genau die
   Information abgeschnitten, wegen der er dasteht. */
.absperre-row:has(.absperre-grund) { align-items: flex-start; }
.absperre-row:has(.absperre-grund) .absperre-name { white-space: normal; overflow: visible; text-overflow: clip; }
.absperre-grund { display: block; margin-top: 2px; font-size: var(--fs-12); color: var(--c-muted); }

/* ---- Warn-Sperre-Dialog (warn-sperre.js, Vorbild .absperre-* oben) ----
   "Bevoelkerungswarnung noch offen" beim Erledigen/Abschliessen eines
   Einsatzes/Schwerpunkts — abschlussbereite Warnungen direkt im Dialog
   abschliessen (Recht + Vier-Augen bleiben serverseitig gewahrt). */
.warnsperre-overlay {
    position: fixed; inset: 0; z-index: var(--z-sheet);
    background: rgba(0, 0, 0, 0.45);
    display: flex; align-items: center; justify-content: center; padding: 16px;
}
.warnsperre-box {
    background: var(--c-card); border: 1px solid var(--c-border);
    border-radius: var(--radius-lg); padding: 16px 18px;
    width: min(560px, 100%); max-height: 80vh; overflow-y: auto;
}
.warnsperre-title { margin: 0 0 6px; font-size: var(--fs-md); }
.warnsperre-msg { font-size: var(--fs-13); color: var(--c-muted); margin: 0 0 10px; }
.warnsperre-row { padding: 7px 2px; border-bottom: 1px solid var(--c-border-l); }
.warnsperre-row:last-child { border-bottom: 0; }
.warnsperre-line { display: flex; align-items: center; gap: 10px; }
.warnsperre-nr { font-family: var(--font-mono); font-size: var(--fs-12); font-weight: 700; color: var(--c-muted); min-width: 80px; }
.warnsperre-phase { flex: 1; min-width: 0; font-size: var(--fs-base); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.warnsperre-do { white-space: nowrap; flex-shrink: 0; min-height: 36px; }
.warnsperre-do[disabled] { opacity: 0.55; cursor: not-allowed; }
/* Begruendung eines deaktivierten Abschliessen-Knopfs (z. B. Vier-Augen) —
   role="alert" sitzt im HTML (warn-sperre.js), hier nur die Optik. */
.warnsperre-reason { margin: 4px 0 0; font-size: var(--fs-12); color: var(--c-error); line-height: 1.35; }
.warnsperre-foot { display: flex; justify-content: flex-end; margin-top: 12px; }

/* ============================================================
   Handlungsempfehlungen-Picker (he-picker.js, MoWaS #208 / v4.6)
   Editierbare Text-Liste + Katalog-Auswahl-Modal.
   ============================================================ */
.he-row { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.he-row .he-input { flex: 1; padding: 7px 10px; border: 1px solid var(--c-border); border-radius: var(--radius-md); background: var(--c-bg); color: var(--c-fg); font-family: inherit; }
/* Touch-Targets groesszuegig (Handschuh-Bedienung): ▲▼/× jeweils 40px. */
.he-row .he-del { flex: 0 0 auto; width: 40px; height: 40px; border: 1px solid var(--c-border); border-radius: var(--radius-md); background: var(--c-card); color: var(--c-muted); cursor: pointer; font-size: 18px; line-height: 1; }
.he-row .he-del:hover { color: var(--c-primary); border-color: var(--c-primary); }
.he-row .he-move { flex: 0 0 auto; width: 40px; height: 40px; border: 1px solid var(--c-border); border-radius: var(--radius-md); background: var(--c-card); color: var(--c-muted); cursor: pointer; font-size: 12px; line-height: 1; }
.he-row .he-move:hover { color: var(--c-primary); border-color: var(--c-primary); }
.he-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.he-modal { position: fixed; inset: 0; background: rgba(0, 0, 0, .45); display: flex; align-items: center; justify-content: center; z-index: var(--z-modal); padding: 16px; }
.he-modal[hidden] { display: none; }
/* position:relative — Ankerpunkt fuer ein optionales .modal-x (Schliessen-Kreuz,
   absolut positioniert; Muster: alle bespoke Modals, siehe dortiger Kommentar).
   he-modal selbst hat keins (schliesst nur ueber ESC/Backdrop/Fuss-Knopf), andere
   Aufrufer dieser Klassen (z. B. warnung-stammdaten.php) duerfen aber eins ergaenzen. */
.he-modal-box { position: relative; background: var(--c-card); color: var(--c-fg); border: 1px solid var(--c-border); border-radius: var(--radius-lg); width: 100%; max-width: 640px; max-height: 82vh; display: flex; flex-direction: column; box-shadow: var(--shadow-lg); }
.he-modal-head { display: flex; gap: 12px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding: 14px 16px; border-bottom: 1px solid var(--c-border); }
.he-modal-filter { font-size: var(--fs-13); color: var(--c-muted); display: flex; gap: 6px; align-items: center; }
.he-modal-filter select { padding: 6px 8px; border: 1px solid var(--c-border); border-radius: var(--radius-md); background: var(--c-bg); color: var(--c-fg); }
.he-modal-list { overflow: auto; padding: 8px 16px; }
.he-modal-list .he-pick { display: flex; gap: 8px; align-items: flex-start; padding: 5px 2px; font-size: var(--fs-13); line-height: 1.4; cursor: pointer; }
.he-modal-list .he-pick input:disabled + span { color: var(--c-muted); }
.he-modal-list .he-pick-note { color: var(--c-muted); font-size: var(--fs-12); font-style: italic; }
.he-modal-list .he-pick-sep { border-top: 1px dashed var(--c-border); margin: 6px 0; }
.he-modal-list .he-none { color: var(--c-muted); font-size: var(--fs-13); }
.he-modal-count { font-size: var(--fs-12); font-weight: 600; color: var(--c-muted); white-space: nowrap; }
.he-modal-foot { display: flex; gap: 10px; padding: 12px 16px; border-top: 1px solid var(--c-border); }

/* Warn-Indikator (#208 Etappe D): Zivilschutz-Zeichen (oranger Kreis + blaues
   Dreieck) der aktivsten Bevoelkerungswarnung; der Ring traegt die Status-Farbe
   (--wi-col). Immer solide (kein Hover-Wechsel), klickbar -> Warnung. */
.warn-indikator { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box;
    width: 34px; height: 34px; padding: 2px; border-radius: var(--radius-md);
    background: transparent; text-decoration: none; line-height: 0; flex: 0 0 auto; align-self: center; }
.warn-indikator .warn-tri { width: 100%; height: 100%; display: block; }
/* Fokus-Ring in fester, kontraststarker Farbe (nicht die Statusfarbe — grau/gelb
   verfehlten sonst die 3:1-Fokus-Sichtbarkeit). */
.warn-indikator:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 2px; }
/* v4.7.5 (Bugpaket, D1): FESTE Groesse statt Zeilenhoehe. Vorher hatte
   --full align-self:stretch + width/height:auto — das Symbol uebernahm die
   Hoehe der Zeile, und die haengt vom Inhalt ab (EM-Chips, Personal-Pill
   machen die Zeile hoeher). Ergebnis: unterschiedlich grosse Symbole in
   derselben Liste (gemeldeter Bug). Die urspruengliche Absicht (Skalierung
   Komfort <-> Kompakt) bleibt erhalten, kommt jetzt aber aus einer zweiten
   EXPLIZITEN Groesse unter body.list-compact, nicht mehr aus dem
   zufaelligen Zeileninhalt. align-self:center steht zwar schon in der
   Basisregel oben, wird hier trotzdem noch mal hingeschrieben — genau das
   ist der Unterschied zum alten Bug. Abstand zur Meta-Spalte kommt weiter
   aus .ec-meta-wrap { gap: 8px } weiter unten, kein zusaetzlicher Margin
   noetig. Keine eigene .warn-tri-Regel mehr noetig: bei fester Box-Groesse
   traegt die Basisregel (.warn-indikator .warn-tri, oben) die SVG genauso
   sauber wie sie es bei --detail/--sp schon immer tat. */
.warn-indikator--full { align-self: center; width: 34px; height: 34px; }
/* Kompakt-Ansicht: dieselbe Regel, nur kleiner (Faktor ~0.82 — dieselbe
   Verkleinerung wie die Status-Kachel daneben, die dort von 66px auf 54px
   schrumpft, siehe body.einsatz-index.list-compact in einsaetze.css). */
body.list-compact .warn-indikator--full { width: 28px; height: 28px; }
/* Einsatz-Detail und Schwerpunkt-Sidebar hatten nie den Stretch-Bug (schon
   immer feste Groesse) — Werte bewusst unveraendert, damit die Familie
   gestuft bleibt: 28 Kompakt < 34 Komfort-Liste < 44 SP-Banner < 52 Detail.
   Viele Zeilen -> kleines Symbol, ein einzelnes prominentes Symbol im
   Banner/Detail -> groesser. */
.warn-indikator--detail { width: 52px; height: 52px; }
.warn-indikator--sp { width: 44px; height: 44px; }

/* Schmale Viewports: gestuft verkleinern, damit das Symbol nichts verdeckt.
   .ec-meta ist white-space:nowrap und tr.einsatz-card bricht nie um — ein
   fixes 34px/44px/52px-Symbol wuerde Status/Zeit/Disponent sonst aus der
   schmalen Meta-Spalte draengen. Breakpoints wiederverwendet statt neu
   erfunden: 900px = derselbe Umbruchpunkt wie das Liste-Grid (weiter oben
   in einsaetze.css), 560px = derselbe Punkt, an dem info-titlerow (Detail)
   selbst umbricht (ebenfalls einsaetze.css). info-titlerow/sp-banner
   brechen dort bereits per flex-wrap sichtbar aus, die Symbole schrumpfen
   trotzdem mit — sonst wirkt die Familie ausgerechnet dort inkonsistent. */
@media (max-width: 900px) {
    .warn-indikator--full { width: 28px; height: 28px; }
    body.list-compact .warn-indikator--full { width: 24px; height: 24px; }
    .warn-indikator--detail { width: 44px; height: 44px; }
    .warn-indikator--sp { width: 38px; height: 38px; }
}
@media (max-width: 560px) {
    .warn-indikator--full,
    body.list-compact .warn-indikator--full { width: 24px; height: 24px; }
    .warn-indikator--detail { width: 36px; height: 36px; }
    .warn-indikator--sp { width: 32px; height: 32px; }
}

/* Einsatzlisten-Zelle: Indikator links, Rest rechts. .ec-meta-wrap fuellt
   weiterhin die Zelle (height:100%) — nicht mehr, damit der Indikator
   selbst die Zeilenhoehe annimmt (der hat jetzt eine feste Groesse + eigenes
   align-self:center, s. o.), sondern damit .ec-meta-inner seinen Inhalt per
   justify-content:center ueber die volle Zeilenhoehe vertikal zentrieren
   kann. */
.ec-meta-wrap { display: flex; gap: 8px; align-items: stretch; height: 100%; }
.ec-meta-inner { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; }

/* ---- Kachel-Uebersichten (.tile-grid / .tile) ------------------------
   Das Raster der Uebersichtsseiten im Admin-Bereich (admin/index.php,
   admin/warnung.php). Lag bis 09.08.2026 in jeder Seite als fast
   wortgleicher <style>-Block. Wer eine neue Uebersicht anlegt, vergisst
   ihn zuverlaessig — die Kacheln rendern dann als nackte, unterstrichene
   Links (genau so passiert beim ersten Anlauf der Wetter-Uebersicht).
   Deshalb hier zentral: Markup mit .tile-grid + .tile genuegt, die Seite
   braucht kein eigenes Kachel-CSS mehr.

   Das Raster heisst bewusst .tile-grid und nicht .grid: admin/system-
   status.php fuehrt ein EIGENES .grid (260px-Spalten, ohne margin-top).
   Ein globales .grid in dieser Datei wuerde dort durchschlagen.

   AKZENTFARBE: nicht border-left ueberschreiben, sondern --tile-accent
   setzen —

       .tile-xyz { --tile-accent: var(--c-primary); }

   faerbt linken Rand UND Hover-Rand in einem Zug. Die Basis setzt die
   Variable nie selbst (der Standardton steht als var()-Ausweichwert),
   damit eine Variante nicht mehr davon abhaengt, ob sie VOR oder NACH
   .tile steht. Vorher war genau diese Reihenfolge eine Falle und musste
   in den Seiten als Warnkommentar mitgeschleppt werden. */
.tile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 14px;
    margin-top: 10px;
}
.tile {
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-left: 4px solid var(--tile-accent, var(--c-warn));
    border-radius: var(--radius-lg);
    padding: 20px 18px;
    text-decoration: none;
    color: var(--c-fg);
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 130px;
    transition: transform 0.12s ease, box-shadow 0.14s ease, border-color 0.12s ease;
    box-shadow: var(--theme-shadow);
}
/* Kacheln sind <a>-Links — die globale Link-Farbe (a:link/:visited/:hover
   weiter oben in dieser Datei, Spezifitaet 0,1,1) wuerde sie nach
   Klick/Hover blau einfaerben. Mit 0,2,0 ueberschreiben, damit die
   Kacheln in allen Zustaenden neutral bleiben (wie das Hauptmenue).
   Die .desc behaelt ihre eigene Muted-Farbe (eigene Regel unten). */
.tile:link, .tile:visited, .tile:hover, .tile:active { color: var(--c-fg); }
.tile:hover {
    transform: translateY(-2px);
    /* Token statt des frueheren Hartcodes 0 6px 18px rgba(0,0,0,0.08):
       gleiche Geometrie, im Dark-Mode aber ueberhaupt erst sichtbar. */
    box-shadow: var(--theme-shadow-hover);
    border-color: var(--tile-accent, var(--c-warn));
}
.tile .icon  { font-size: 28px; line-height: 1; }
.tile .label { font-weight: 600; font-size: 15.5px; margin-top: 4px; }
.tile .desc  { font-size: var(--fs-sm); color: var(--c-muted); line-height: 1.4; }

/* Varianten. */
/* Nicht freigeschaltetes Zusatzmodul (admin/index.php): sichtbar, aber
   erkennbar zurueckgenommen — gestrichelter Rand statt Vollton. Bewusst
   NICHT ueber --tile-accent, sondern nur ueber die linke Kante: der
   Hover soll wie bisher den Warn-Ton zeigen (.tile:hover hat 0,2,0 und
   gewinnt ohnehin, die gestrichelte Linienart bleibt dabei stehen). */
.tile-modul-aus { border-left-style: dashed; border-left-color: var(--c-border); opacity: .82; }
.tile-modul-aus .label { color: var(--c-muted); }
/* Noch offener Einrichtungsschritt — faellt durch den Primaerton auf,
   damit man beim Einrichten nicht ausgerechnet den Schritt uebersieht,
   ohne den ein Modul stumm bleibt. */
.tile-offen { --tile-accent: var(--c-primary); }

/* ---------------------------------------------------------------------------
   .lead-note — der erklaerende Absatz ueber oder unter einem Bereich.

   Wurde bislang in jeder Seite neu erfunden (13 Seiten nutzen die Klasse,
   definiert war sie in zweien) — auf allen uebrigen fiel sie wirkungslos aus
   und der Hinweistext sah aus wie normaler Fliesstext. Gehoert deshalb hier
   in die Komponenten, nicht in Page-Styles.
   -------------------------------------------------------------------------*/
.lead-note {
    font-size: var(--fs-13);
    color: var(--c-muted);
    line-height: 1.5;
    margin: 0 0 14px;
}
.lead-note:last-child { margin-bottom: 0; }

/* ---- Alarmieren-Haken (Auslöse-Modal + Auslöse-Banner, 31.08.2026) -----
   Beide Auslösewege fragen dasselbe: soll überhaupt alarmiert werden? Das
   Tippziel ist das ganze LABEL — das 15-px-Kästchen allein trifft auf einem
   Tablet niemand. `align-items: flex-start`, weil die Erklärung darunter
   zweizeilig werden darf. */
.alarm-opt {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 6px 0;
    min-height: 44px;
    font-size: var(--fs-13);
    cursor: pointer;
}
.alarm-opt input { width: auto; margin-top: 2px; accent-color: var(--c-primary); }
.alarm-opt .hint { display: block; margin-top: 2px; }

/* ---- „Alarmierung ausgesetzt" (31.08.2026) -----------------------------
   Auf JEDER Seite, ganz oben, nicht wegklickbar. Ein stummer Alarm-Bus
   sieht im Normalbetrieb genauso aus wie „es ist gerade nichts los" —
   und diese Verwechslung ist die teuerste, die diese Anwendung kennt.

   Warnfarbe, nicht Fehlerfarbe: Es ist ein gewollter Zustand, aber einer,
   der sichtbar bleiben muss. */
.alarm-aus-balken {
    position: sticky;
    top: 0;
    z-index: 60;
    padding: 10px 16px;
    /* DIESELBEN TOKEN WIE .toast.warn — es gibt sie, und sie sind fuer
       Hell und Dunkel gepflegt. Eigene Hex-Werte haetten im Dunkelmodus
       einen hellen Balken ergeben. */
    background: var(--theme-toast-warn-bg);
    color: var(--theme-toast-warn-fg);
    border-bottom: 2px solid var(--theme-toast-warn-border);
    font-size: var(--fs-13);
    line-height: 1.4;
}
.alarm-aus-balken a {
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
}

/* AUF SCHMALEN GERAETEN UNTER DIE MOBIL-LEISTE. Sie ist `fixed` mit
   z-index 900 (--z-drawer-topbar); ein Balken bei `top: 0` klebte ab dem
   ersten Scrollen dahinter und war nur in Scrollposition 0 zu sehen —
   ausgerechnet auf dem Geraet, auf dem geprueft wird. */
@media (max-width: 800px) {
    .alarm-aus-balken {
        top: calc(52px + env(safe-area-inset-top, 0px));
    }
}

/* ---- Auswahl-Pille (#124, zentral seit 31.08.2026) ---------------------
   Ein Kaestchen, das wie eine Pille aussieht: Die Checkbox selbst ist
   optisch versteckt, das ganze Label ist das Tippziel. Stand bis zum
   31.08.2026 nur in einsaetze.css — auf jeder anderen Seite war es
   deshalb ein nacktes Kaestchen ohne Flaeche. */
.checkpill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: 16px;
    min-height: 34px;
    font-size: var(--fs-sm); cursor: pointer;
    background: var(--c-card); /* token-basiert -> Dark automatisch */
    border: 1px solid var(--c-border);
    color: var(--c-fg); user-select: none;
    transition: background 0.12s, border-color 0.12s;
}
/* Checkbox visuell ausgeblendet (bleibt tastatur-fokussierbar) — die Pille
   selbst ist der Toggle, wie bei den Lagekarte-Filtern. */
.checkpill input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); }
.checkpill:hover { background: var(--c-btn-soft-hover); }
.checkpill:focus-within { outline: 2px solid var(--c-primary); outline-offset: 1px; }  /* Tastatur-Fokus (#124) */
.checkpill.active { background: var(--c-identity); color: var(--c-identity-fg); border-color: var(--c-identity); font-weight: 600; }
/* Dark: rotes Aktiv durchsetzen gegen das generische .checkpill-Dark-Override in theme.css. */
html[data-theme="dark"] .checkpill.active { background: var(--c-identity); color: var(--c-identity-fg); border-color: var(--c-identity); font-weight: 600; }

/* ---- Angekreuzt, ohne Skript (31.08.2026) ------------------------------
   `.active` setzt nur die Server-Seite (export.php rendert es beim Aufbau).
   Fuer eine Auswahl, die sich WAEHREND des Ausfuellens aendert, traegt das
   nicht: Michael klickte einen Wochentag an und die Pille blieb grau.

   `:has(input:checked)` ist dafuer das Muster, das diese Datei bei
   `.ort-chip` schon benutzt — es braucht kein JavaScript und kann deshalb
   auch nicht vergessen werden. Dieselbe Spezifitaet wie das Dark-Override
   in theme.css, aber spaeter geladen; der Dark-Zwilling darunter macht es
   trotzdem ausdruecklich, damit es nicht an der Ladereihenfolge haengt. */
.checkpill:has(input:checked) {
    background: var(--c-identity);
    color: var(--c-identity-fg);
    border-color: var(--c-identity);
    font-weight: 600;
}
html[data-theme="dark"] .checkpill:has(input:checked) {
    background: var(--c-identity);
    color: var(--c-identity-fg);
    border-color: var(--c-identity);
    font-weight: 600;
}

/* =====================================================================
   BILDLAUFLEISTEN IM HAUSDESIGN (02.09.2026)
   ---------------------------------------------------------------------
   Michael: „Kannst Du die Bildlaufleisten in unserem Design gestalten —
   und nicht die Standard-Leisten des Browsers? Gerne generell, wo
   horizontale und vertikale entstehen."

   Die hellgraue Windows-Leiste auf einer dunklen Tafel ist genau der
   Bruch, den man auf einem Tablet aus zwei Metern zuerst sieht. Deshalb
   hier zentral und fuer ALLE Bereiche — die Protokolltabelle, die
   Dialoge, die Seite selbst.

   BEIDE FASSUNGEN kommen von selbst: Die Farben stehen als Tokens und
   werden im Dunkelmodus mitgedreht. Erfunden wird hier nichts —
   `--theme-card-hover` und `--theme-input-border` gibt es beide schon.
   Die Ersatzwerte sind fuer die Anmeldeseite, die bewusst ohne
   tokens.css laeuft.

   ZWEI SYNTAXEN, weil die Browser sich nicht einig sind: Firefox kennt
   `scrollbar-color`, die Chromium-Familie `::-webkit-scrollbar`. Wer
   beides nicht kann, bekommt die Systemleiste — das ist kein Verlust,
   nur kein Gewinn.
   ===================================================================== */
:root {
    /* `thin` war zweimal falsch: Es verkleinert genau die Trefferflaeche,
       die der Kommentar unten schuetzen will, und der Griff in
       --theme-input-border liegt mit 1,40:1 (hell) bzw. 1,44:1 (dunkel)
       so dicht an der Bahn, dass man ihn nicht sieht. Auf der
       AUE-Tafel ist der Balken an der Protokolltabelle der einzige
       Hinweis, dass rechts noch etwas steht. */
    scrollbar-width: auto;
    scrollbar-color: var(--c-muted, #404a58) var(--theme-card-hover, #fafbfc);
}

::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}
::-webkit-scrollbar-track {
    background: var(--theme-card-hover, #fafbfc);
}
::-webkit-scrollbar-thumb {
    background: var(--c-muted, #404a58);
    border-radius: 999px;
    /* Der Rand in der Bahnfarbe laesst den Griff schmaler wirken, ohne
       die Trefferflaeche zu verkleinern — mit Handschuh zaehlt die. */
    border: 3px solid var(--theme-card-hover, #fafbfc);
}
::-webkit-scrollbar-thumb:hover {
    background: var(--c-fg, #1b2530);
}
::-webkit-scrollbar-corner {
    background: var(--theme-card-hover, #fafbfc);
}
