/* =====================================================================
   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; }

/* ---- 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: 10000; 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: 6px;
    background: var(--theme-card-hover);
    color: var(--c-fg);
    font-size: 13px;
    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);
}

/* 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: 6px;
    background: var(--c-btn-soft-bg);
    color: var(--c-fg);
    font-size: 13px;
    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: 6px;
    font-size: 13px;
    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: 6px;
    font-size: 13px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s, transform 0.18s;
    z-index: 999;
    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: 13px; 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: 13px;
    padding: 5px 28px 5px 10px;
    border: 1px solid var(--c-border);
    border-radius: 6px;
    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: 12px; 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; }

.form-grid input,
.form-grid textarea,
.form-grid select {
    font: inherit;
    font-size: 14px;
    padding: 7px 10px;
    border: 1px solid var(--c-border);
    border-radius: 5px;
    background: var(--theme-input-bg);
    color: var(--c-fg);
    width: 100%;
}
.form-grid textarea {
    min-height: 60px;
    font-family: ui-monospace, "Consolas", monospace;
    font-size: 12.5px;
}
.form-grid label { font-size: 13px; color: var(--c-muted); }
.form-grid .hint {
    font-size: 11.5px;
    color: var(--c-muted);
    font-style: italic;
    margin-top: 2px;
}
.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: 13px;
}
.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: 12px;
    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: 12px;
    font-size: 11px;
    font-weight: 600;
}
.pill-on  { background: #dff6e3; color: #1f6f3a; }
.pill-off { background: var(--theme-card-hover); color: var(--c-muted); }
/* 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: 12.5px;
    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: 12px; }

/* ---- 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: 14px;
    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: 11px;
    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; }

/* ---- 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.
   ===================================================================== */
@media (max-width: 760px) {
    .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, .btn-link { min-height: 44px; }
    .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). */
    .cmp-table,
    .cmp-scope table:not(.sp-table) { 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: 10001;
    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: 22px; 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: 14px; 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". */
.modal-x {
    position: absolute; top: 10px; right: 10px;
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0; border: none; background: transparent; border-radius: 7px;
    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; }

/* === 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; }

/* === 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: 12px;
    color: var(--c-muted);
    white-space: nowrap;
}
.live-refresh-group {
    display: inline-flex;
    border: 1px solid var(--c-border);
    border-radius: 6px;
    overflow: hidden;
}
.live-refresh-btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 28px;
    padding: 5px 10px;
    font-size: 12.5px;
    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: 1300;
    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: 12px; padding: 16px 18px;
    width: min(520px, 100%); max-height: 80vh; overflow-y: auto;
}
.absperre-title { margin: 0 0 6px; font-size: 16px; }
.absperre-msg { font-size: 13px; 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: 12px; font-weight: 700; color: var(--c-muted); min-width: 46px; text-align: center; }
.absperre-name { flex: 1; min-width: 0; font-size: 14px; 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; }
