/* Switzer (Indian Type Foundry, Fontshare), selbst gehostet unter fonts/.
   ITF Free Font License erlaubt kommerzielle Nutzung und Self-Hosting, aber keine
   veränderte Datei (kein Subsetting, keine Formatumwandlung) — Lizenz liegt daneben.
   Eine variable Datei deckt alle Stärken 100–900 ab. */
@font-face {
  font-family: 'Switzer';
  src: url('fonts/Switzer-Variable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Design-Tokens (UI-Überarbeitung 2026-09-18). Markenfarben aus dem Logo:
   Navy #012D73 (Wortmarke) und Petrol #058E9E (Schild). Navy trägt Aktionen und
   den aktiven Menüpunkt, Petrol nur den Fokusring und die Mitarbeiter-Art —
   bewusst sparsam, damit Farbe Bedeutung behält. Neutraltöne leicht bläulich
   wie das Logo. Statusfarben (--badge-*, --alert-*) unverändert. */
:root {
  --font-sans: 'Switzer', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  --brand-navy: #012D73;
  --brand-teal: #058E9E;

  --content-bg: #F3F5F8;
  --card-bg: #FFFFFF;
  --header-bg: #FFFFFF;
  --surface-sunken: #EDF0F4;
  --text-primary: #0F1A2B;
  --text-secondary: #3A4659;
  --text-muted: #626E82;
  --border: #E2E6EC;
  --border-strong: #CDD4DE;
  --row-hover: #F6F8FB;

  --accent: var(--brand-navy);
  --accent-hover: #0B3E91;
  --accent-soft: #E8EEF7;
  --focus: var(--brand-teal);
  --focus-ring: 0 0 0 3px color-mix(in srgb, var(--brand-teal) 28%, transparent);

  /* Einziger Verlauf im Projekt: das Symbolquadrat der Startmenü-Kacheln.
     Farbe bleibt damit sparsam und bedeutungstragend (Spec 2026-09-22). */
  --brand-gradient: linear-gradient(135deg, var(--brand-navy), var(--brand-teal));

  --radius-sm: 6px;
  --radius: 8px;
  --radius-lg: 12px;
  --shadow-xs: 0 1px 2px rgba(15, 26, 43, 0.05);
  --shadow-md: 0 6px 16px -4px rgba(15, 26, 43, 0.10), 0 2px 4px rgba(15, 26, 43, 0.04);
  --shadow-lg: 0 24px 56px -12px rgba(15, 26, 43, 0.30), 0 4px 12px rgba(15, 26, 43, 0.06);

  /* Halbtransparentes Panel über der Karte (/dispatch). Als Token, damit die
     Werte nicht als Hex in einzelnen Regeln stehen. */
  --glass-bg: rgba(255, 255, 255, 0.84);
  --glass-border: rgba(255, 255, 255, 0.75);

  /* Helle Sidebar; Navy nur am aktiven Eintrag. */
  --sidebar-bg: #FFFFFF;
  --sidebar-border: var(--border);
  --sidebar-divider: var(--border);
  --sidebar-hover: #F1F4F8;
  --sidebar-active: var(--accent-soft);
  --sidebar-text: var(--text-secondary);
  --sidebar-accent: var(--accent);

  --alert-danger-bg: oklch(97% 0.025 25);
  --alert-danger-border: oklch(88% 0.08 25);
  --alert-danger-text: oklch(38% 0.18 25);
  --badge-expired-bg: oklch(95.5% 0.04 25);
  --badge-expired-text: oklch(38% 0.20 25);
  --badge-expired-dot: oklch(55% 0.22 25);
  --badge-critical-bg: oklch(96% 0.05 50);
  --badge-critical-text: oklch(40% 0.16 50);
  --badge-critical-dot: oklch(62% 0.20 50);
  --badge-warning-bg: oklch(96.5% 0.05 85);
  --badge-warning-text: oklch(42% 0.14 85);
  --badge-warning-dot: oklch(68% 0.17 85);
  --badge-ok-bg: oklch(95.5% 0.04 145);
  --badge-ok-text: oklch(36% 0.16 145);
  --badge-ok-dot: oklch(56% 0.18 145);

  /* Routen im Google-Maps-Look (Spec 2026-09-21): Linie mit dunklerem Mantel, roter Ziel-Tropfen. */
  --route-line: #1A73E8;
  --route-casing: #1558B8;
  --route-pin-end: #EA4335;
  --route-pin-end-dark: #B31412;
  --route-pin-ring: #3C4043;
}

/* Base */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body, #root { height: 100%; }
body { font-family: var(--font-sans); font-size: 14px; line-height: 1.45; background: var(--content-bg); color: var(--text-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* Sichtbarer Tastatur-Fokus überall (Maus-Klicks lösen :focus-visible nicht aus).
   Eingabefelder haben stattdessen den weichen Ring aus --focus-ring.
   tabindex="-1" bleibt ausgenommen: Blazor fokussiert nach jeder Navigation die
   Seitenüberschrift per Code (FocusOnNavigate), die bekäme sonst einen Rahmen. */
:where(a, button, [role="button"], [tabindex]:not([tabindex="-1"]), summary, input[type="checkbox"], input[type="radio"]):focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Edge setzt in Passwortfelder ein eigenes Auge — wir haben schon eins. */
input::-ms-reveal, input::-ms-clear { display: none; }
/* Per Code fokussierte Elemente (FocusOnNavigate setzt tabindex="-1" auf die
   Überschrift) bekommen keinen Rahmen — auch nicht den Standardrahmen des Browsers. */
[tabindex="-1"]:focus { outline: none; }
/* Das hidden-Attribut greift bei <svg> nicht zuverlässig (UA-Regel gilt für HTML-
   Elemente). Sonst zeigt z. B. der Passwort-Umschalter beide Augen gleichzeitig. */
svg[hidden] { display: none; }

/* Layout */
/* 100dvh statt nur 100vh: iOS Safari rechnet 100vh mit eingefahrener Leiste, also
   höher als der sichtbare Bereich. Die Seite selbst wurde dadurch um die Leistenhöhe
   scrollbar, am unteren Ende von .content sprang die Wischgeste auf die Seite über
   und blieb dort hängen — .content ließ sich danach nicht mehr scrollen. */
.app-shell { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }

.sidebar {
  width: 248px; flex-shrink: 0; z-index: 100;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--sidebar-border);
  display: flex; flex-direction: column;
  transition: transform 0.25s cubic-bezier(.4,0,.2,1), width 0.2s cubic-bezier(.4,0,.2,1);
}

.dash-hero {
  padding: 18px 20px 14px;
  display: flex; align-items: center; gap: 11px;
  cursor: pointer;
  transition: background 0.15s;
  user-select: none;
  flex-shrink: 0;
  text-decoration: none;
}
.dash-hero:hover { background: var(--sidebar-hover); }
.dash-hero.active { background: transparent; }
.dash-hero img { height: 36px; width: auto; flex-shrink: 0; }
.dash-hero-text { line-height: 1.25; }
.dash-hero-name { font-size: 14px; font-weight: 700; color: var(--brand-navy); letter-spacing: -0.01em; }
.dash-hero-sub  { font-size: 12px; color: var(--text-muted); }

.sidebar-nav { flex: 1; overflow-y: auto; padding: 4px 0 12px; }

.nav-section-label {
  padding: 18px 20px 6px;
  font-size: 12px; font-weight: 600;
  color: var(--text-muted);
}

.nav-item {
  display: flex; align-items: center; gap: 10px;
  margin: 1px 10px; padding: 7px 10px; border-radius: var(--radius);
  font-size: 14px; font-weight: 500;
  cursor: pointer; color: var(--sidebar-text);
  transition: background 0.12s, color 0.12s; user-select: none;
  text-decoration: none;
}
.nav-item:hover { background: var(--sidebar-hover); color: var(--text-primary); }
.nav-item.active { background: var(--sidebar-active); color: var(--sidebar-accent); font-weight: 600; }
.nav-icon { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.7; display: flex; align-items: center; }
.nav-item.active .nav-icon { opacity: 1; }

.sidebar-footer {
  padding: 14px 20px; border-top: 1px solid var(--sidebar-divider); flex-shrink: 0;
}
.sidebar-user { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.sidebar-user-info { line-height: 1.3; min-width: 0; }
.sidebar-user-name  { font-size: 13px; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-user-email { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-logout { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 13px; color: var(--text-muted); cursor: pointer; background: none; border: none; font-family: inherit; width: 100%; }
.sidebar-logout:hover { color: var(--text-primary); }

/* ── Eingeklappte Sidebar (nur Desktop) ──────────────────────────────────
   Umschalter in der Topbar, Zustand als html.sidebar-collapsed (sidebar.js,
   localStorage). Nur Symbole; der Name steht im title der Links (Tooltip).
   Abschnittsüberschriften werden zu dünnen Trennlinien. Unter 700px gilt
   weiter die ausfahrende Sidebar mit Hamburger — dort greift nichts hiervon. */
.sidebar-toggle { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin-left: -6px; background: none; border: none; border-radius: var(--radius); color: var(--text-muted); cursor: pointer; }
.sidebar-toggle:hover { background: var(--row-hover); color: var(--text-primary); }
@media (min-width: 701px) {
  html.sidebar-collapsed .sidebar { width: 72px; }
  html.sidebar-collapsed .dash-hero { justify-content: center; padding: 18px 0 14px; }
  html.sidebar-collapsed .dash-hero-text,
  html.sidebar-collapsed .nav-label,
  html.sidebar-collapsed .sidebar-user-info { display: none; }
  html.sidebar-collapsed .nav-section-label { height: 1px; padding: 0; margin: 12px 18px; overflow: hidden; font-size: 0; background: var(--border); }
  html.sidebar-collapsed .nav-item { justify-content: center; margin: 2px 14px; padding: 9px 0; }
  html.sidebar-collapsed .nav-icon { opacity: 0.85; }
  html.sidebar-collapsed .sidebar-footer { padding: 14px 0; }
  html.sidebar-collapsed .sidebar-user { justify-content: center; }
  html.sidebar-collapsed .sidebar-logout { justify-content: center; }
}

.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.topbar {
  height: 56px; background: var(--header-bg);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; padding: 0 28px; gap: 12px; flex-shrink: 0;
}
.topbar-title { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.topbar-spacer { flex: 1; }
.avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--accent); color: white; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; flex-shrink: 0; }
.topbar-role { font-size: 12px; color: var(--text-secondary); background: var(--surface-sunken); padding: 3px 10px; border-radius: 99px; font-weight: 500; }

/* Home-Knopf und Abmelden in der Topbar — nur am Handy sichtbar, weil es dort
   keine Seitenleiste gibt. Am Desktop bleiben beide in der Seitenleiste. */
.topbar-home { display: none; align-items: center; padding: 2px; border-radius: var(--radius-sm); }
.topbar-home img { width: 26px; height: 26px; display: block; }
.topbar-home:hover { background: var(--row-hover); }
.topbar-logout-form { display: none; }
.topbar-logout { background: none; border: none; cursor: pointer; color: var(--text-muted); padding: 5px; border-radius: var(--radius-sm); display: flex; align-items: center; }
.topbar-logout:hover { background: var(--row-hover); color: var(--text-primary); }

.hamburger { display: none; background: none; border: none; cursor: pointer; color: var(--text-muted); padding: 4px; border-radius: var(--radius-sm); }
.hamburger:hover { background: var(--row-hover); }
/* Abdunkelung hinter der ausgefahrenen Seitenleiste. cursor: pointer ist Pflicht —
   ohne sie liefert iOS Safari den Klick nicht an Blazor aus (CLAUDE.md, Dialoge). */
.sidebar-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 99; cursor: pointer; -webkit-tap-highlight-color: transparent; }

/* overscroll-behavior: contain — am Ende der Liste gibt die Wischgeste nicht an die
   Seite weiter (zweite Sicherung zum 100dvh an .app-shell). */
.content { flex: 1; overflow-y: auto; overscroll-behavior-y: contain; padding: 28px 32px 40px; }

/* Page header */
.page-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 24px; gap: 12px; flex-wrap: wrap; }
.page-title  { font-size: 24px; font-weight: 650; color: var(--text-primary); line-height: 1.2; letter-spacing: -0.015em; }
.page-subtitle { font-size: 14px; color: var(--text-muted); margin-top: 4px; }
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Stat grid */
.stat-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 16px; margin-bottom: 24px; }
.stat-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 18px 20px; box-shadow: var(--shadow-xs); }
.stat-label { font-size: 13px; font-weight: 500; color: var(--text-muted); margin-bottom: 10px; }
.stat-value { font-size: 32px; font-weight: 650; letter-spacing: -0.02em; color: var(--text-primary); line-height: 1; font-variant-numeric: tabular-nums; }
.stat-sub   { font-size: 12.5px; color: var(--text-muted); margin-top: 8px; }

/* Alert banner */
.alert-banner { border-radius: 10px; padding: 12px 16px; margin-bottom: 18px; display: flex; align-items: flex-start; gap: 11px; border: 1px solid; }
.alert-banner.danger { background: var(--alert-danger-bg); border-color: var(--alert-danger-border); color: var(--alert-danger-text); }
.alert-icon  { flex-shrink: 0; margin-top: 1px; }
.alert-title { font-size: 14px; font-weight: 600; }
.alert-sub   { font-size: 13px; opacity: 0.8; margin-top: 2px; }

/* Table container */
.table-container { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 20px; box-shadow: var(--shadow-xs); }
.table-toolbar { padding: 12px 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.table-count { font-size: 13px; color: var(--text-muted); }
.table-container table { width: 100%; border-collapse: collapse; }
.table-container th { text-align: left; font-size: 12.5px; font-weight: 550; color: var(--text-muted); background: var(--row-hover); padding: 10px 16px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.table-container td { padding: 12px 16px; font-size: 13.5px; color: var(--text-primary); border-bottom: 1px solid var(--border); }
.table-container tr:last-child td { border-bottom: none; }
.table-container tbody tr { transition: background 0.1s; }
.table-container tbody tr:hover td { background: var(--row-hover); }

/* Badges */
.badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px 3px 8px; border-radius: 99px; font-size: 12px; font-weight: 550; white-space: nowrap; }
.badge-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.badge-expired  { background: var(--badge-expired-bg);  color: var(--badge-expired-text);  }
.badge-expired  .badge-dot { background: var(--badge-expired-dot); }
.badge-critical { background: var(--badge-critical-bg); color: var(--badge-critical-text); }
.badge-critical .badge-dot { background: var(--badge-critical-dot); }
.badge-warning  { background: var(--badge-warning-bg);  color: var(--badge-warning-text);  }
.badge-warning  .badge-dot { background: var(--badge-warning-dot); }
.badge-ok       { background: var(--badge-ok-bg);       color: var(--badge-ok-text);       }
.badge-ok       .badge-dot { background: var(--badge-ok-dot); }
.badge-fehlt    { background: var(--badge-expired-bg);  color: var(--badge-expired-text);  font-style: italic; }
.badge-fehlt    .badge-dot { background: var(--badge-expired-dot); }
.badge-none     { color: var(--text-muted); }

/* Buttons */
.btn { display: inline-flex; align-items: center; gap: 7px; text-decoration: none; padding: 8px 14px; border-radius: var(--radius); font-size: 13.5px; font-weight: 550; line-height: 1.3; cursor: pointer; border: 1px solid transparent; font-family: inherit; transition: background 0.13s, border-color 0.13s, color 0.13s, box-shadow 0.13s; white-space: nowrap; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn-primary { background: var(--accent); color: white; box-shadow: var(--shadow-xs); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn-ghost  { background: var(--card-bg); color: var(--text-secondary); border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.btn-ghost:hover:not(:disabled) { background: var(--row-hover); color: var(--text-primary); }
.btn-danger { background: transparent; color: var(--badge-expired-text); border: none; }
.btn-danger:hover { background: var(--badge-expired-bg); }
.btn-excel  { background: oklch(42% 0.15 145); color: white; border: none; }
.btn-excel:hover { filter: brightness(1.1); }
.btn-toggle { background: transparent; color: var(--accent); border: 1.5px solid var(--accent); border-radius: var(--radius); }
.btn-toggle:hover { background: var(--accent-soft); }
.btn-sm { padding: 5px 10px; font-size: 12.5px; }
.btn-secondary { background: var(--card-bg); color: var(--text-primary); border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.btn-secondary:hover:not(:disabled) { background: var(--row-hover); }

/* Search input */
.search-input { height: 36px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--card-bg); color: var(--text-primary); font-family: inherit; font-size: 13.5px; padding: 0 12px; outline: none; width: 220px; transition: border-color 0.15s, box-shadow 0.15s; }
.search-input:focus { border-color: var(--focus); box-shadow: var(--focus-ring); }
.search-input::placeholder { color: var(--text-muted); }
.filter-checkboxes { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; }
.filter-checkbox { display: flex; align-items: center; gap: 6px; font-size: 13.5px; color: var(--text-primary); cursor: pointer; user-select: none; }
.filter-checkbox input[type="checkbox"] { accent-color: var(--accent); cursor: pointer; }

/* Urgent list */
.urgent-row { display: flex; align-items: center; padding: 11px 16px; border-bottom: 1px solid var(--border); gap: 12px; }
.urgent-row:last-child { border-bottom: none; }
.urgent-info { flex: 1; min-width: 0; }
.urgent-name { font-size: 13px; font-weight: 500; }
.urgent-meta { font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }

/* Vehicle cards */
.vehicle-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; padding: 16px; }
.vehicle-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; box-shadow: var(--shadow-xs); transition: box-shadow 0.18s, border-color 0.18s, transform 0.18s; }
.vehicle-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); transform: translateY(-1px); }
.vehicle-photo { width: 100%; aspect-ratio: 16 / 9; background: var(--surface-sunken); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; position: relative; }
.vehicle-photo-type { font-size: 13px; font-weight: 550; color: var(--text-muted); text-align: center; }
.vehicle-photo-note { font-size: 12px; color: var(--text-muted); opacity: 0.75; }
.vehicle-photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }

.vehicle-photo-upload-wrap { position: relative; }
.vehicle-photo-upload { position: relative; display: block; cursor: pointer; }
/* The file input covers the whole photo area instead of being clipped away.
   A file input accepts dropped files natively, so stretching it is what makes
   drag & drop work — without it the drop target is a single pixel nobody can
   hit. Transparent, so the photo below stays visible; clicking it opens the
   file picker exactly like clicking the label did before. */
.vehicle-photo-upload input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.vehicle-photo-upload input[type="file"]:disabled { cursor: default; }
/* Must stack above the stretched input, otherwise the "Foto bearbeiten"
   button underneath it is no longer clickable. */
.vehicle-photo-upload-hint { position: absolute; inset: 0; z-index: 1; display: flex; align-items: center; justify-content: center; gap: 10px; background: rgba(0, 0, 0, 0.45); color: #fff; font-size: 12px; font-weight: 600; opacity: 0; transition: opacity 0.15s; border-radius: 6px; pointer-events: none; }
.vehicle-photo-upload-wrap:hover .vehicle-photo-upload-hint { opacity: 1; }
/* Drag & Drop am Fotorahmen: Beim Ziehen einer Datei greift :hover nicht, deshalb
   kommt der Zustand aus Blazor (@ondragenter/@ondragleave/@ondrop am Input) als
   Klasse herein — dasselbe Muster wie bei .file-drop-zone.
   Liegt über .vehicle-photo-upload-hint (z-index 1), damit beim Ziehen nicht noch
   "Foto ändern" durchscheint. */
.vehicle-photo-upload-wrap.is-dragover::after { content: "Hier ablegen"; position: absolute; inset: 0; z-index: 2; pointer-events: none; display: flex; align-items: center; justify-content: center; border: 2px dashed var(--accent); border-radius: 6px; background: rgba(0, 0, 0, 0.45); color: #fff; font-size: 12px; font-weight: 700; letter-spacing: 0.04em; }

/* Verarbeitungs-Overlay: deckt die Zeit zwischen Drop und geöffnetem Cropper ab
   (Browser skaliert das Bild, die Bytes wandern per SignalR zum Server und zurück —
   bei einem Handyfoto mehrere Sekunden) und danach den eigentlichen Upload.
   Ohne pointer-events-Freigabe blockt es Klicks, damit nicht zweimal gestartet wird. */
.photo-busy-overlay { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; background: rgba(0, 0, 0, 0.55); color: #fff; font-size: 12px; font-weight: 600; border-radius: 6px; }
.photo-busy-spinner { width: 26px; height: 26px; border: 2.5px solid rgba(255, 255, 255, 0.3); border-top-color: #fff; border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Nicht abschalten, nur verlangsamen — sonst bliebe als einzige Rückmeldung ein
   stehender Ring, und genau die fehlende Rückmeldung ist ja das Problem. */
@media (prefers-reduced-motion: reduce) { .photo-busy-spinner { animation-duration: 2.4s; } }
.vehicle-photo-edit-btn { pointer-events: auto; font: inherit; font-size: 11px; font-weight: 600; color: #fff; background: rgba(255, 255, 255, 0.18); border: 1px solid rgba(255, 255, 255, 0.6); border-radius: 4px; padding: 4px 10px; cursor: pointer; }
.vehicle-photo-edit-btn:hover { background: rgba(255, 255, 255, 0.3); }
.vehicle-photo-edit-btn:disabled { opacity: 0.5; cursor: default; }

.photo-crop-overlay { position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.75); display: flex; flex-direction: column; overflow: hidden; }
/* Cropper.js sizes its container to however large the <img> renders at init.
   Without a height cap a portrait photo renders at full natural height and
   the cropper overlaps the toolbar buttons below it. */
.photo-crop-image-wrap { flex: 1; min-height: 0; padding: 20px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.photo-crop-image-wrap img { display: block; max-width: 100%; max-height: 100%; }
.photo-crop-toolbar { flex-shrink: 0; padding: 14px 20px; display: flex; justify-content: flex-end; gap: 10px; background: var(--card-bg); border-top: 1px solid var(--border); }
.vehicle-info { padding: 14px 16px; }
.vehicle-plate { display: flex; }
.vehicle-model { font-size: 14px; font-weight: 600; color: var(--text-primary); margin-top: 10px; }
.vehicle-meta  { font-size: 13px; color: var(--text-muted); margin-top: 2px; margin-bottom: 12px; }
.vehicle-footer { display: flex; align-items: center; justify-content: space-between; }

/* Employee cards */
.employee-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; padding: 16px; }
.employee-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; box-shadow: var(--shadow-xs); transition: box-shadow 0.18s, border-color 0.18s, transform 0.18s; }
.employee-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); transform: translateY(-1px); }
.employee-photo { width: 100%; aspect-ratio: 3 / 4; background: var(--surface-sunken); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; position: relative; }
.employee-photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.employee-info { padding: 14px 16px; }
.employee-type { font-size: 12px; font-weight: 600; color: var(--brand-teal); margin-bottom: 2px; }
.employee-name { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; color: var(--text-primary); }
.employee-meta { font-size: 13px; color: var(--text-muted); margin-top: 2px; margin-bottom: 12px; }
/* flex-wrap: "Ausgeschieden seit 30.09.2026" oder Badge + "Führerschein" passen auf der
   schmalen Handy-Kachel (2–3 Spalten) nicht in eine Zeile und würden sonst abgeschnitten. */
.employee-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; }

/* ── Führerscheinprüfung ─────────────────────────────────────────── */
.license-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; padding: 10px; }
/* Der farbige Rand ist die Ampel — 4 px links reichen auf dem Handy nicht, deshalb rundum 2 px plus Balken oben. */
.license-card { background: var(--card-bg); border: 2px solid var(--border); border-top-width: 6px; border-radius: 10px; padding: 10px 12px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.license-card.is-red { border-color: var(--badge-expired-dot); }
.license-card.is-yellow { border-color: var(--badge-warning-dot); }
.license-card.is-green { border-color: var(--badge-ok-dot); }
.license-card.is-inactive { border-color: var(--border); opacity: 0.6; }
.license-card-number { font-size: 11px; font-weight: 600; letter-spacing: 0.05em; color: var(--text-muted); }
.license-card-name { font-size: 14px; font-weight: 700; color: var(--text-primary); margin: 1px 0 8px; }
.license-card-row { display: flex; justify-content: space-between; gap: 6px; font-size: 11.5px; color: var(--text-muted); }
.license-card-row strong { color: var(--text-primary); font-weight: 600; }

/* Vollbild-Ablauf: liegt im SectionOutlet "license-check" außerhalb jedes Dialogs (iOS-Regel). */
.license-flow { position: fixed; inset: 0; z-index: 320; display: flex; flex-direction: column; background: var(--content-bg); }
.license-flow-header { flex-shrink: 0; padding: 14px 16px; border-bottom: 1px solid var(--border); background: var(--card-bg); }
.license-flow-title { font-size: 15px; font-weight: 700; }
.license-flow-sub { font-size: 12px; color: var(--text-muted); }
.license-flow-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 14px; }
.license-flow-footer { flex-shrink: 0; display: flex; gap: 10px; padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); border-top: 1px solid var(--border); background: var(--card-bg); }
.license-flow-footer .btn { flex: 1; min-height: 48px; justify-content: center; font-size: 15px; }
.license-flow-photo { position: relative; width: 100%; max-height: 50vh; object-fit: contain; border-radius: 8px; border: 1px solid var(--border); background: #000; }
/* Wie die Foto-Rahmen: der Datei-Input liegt unsichtbar über dem ganzen Knopf, ein Tipp öffnet direkt die Kamera. */
.camera-button { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; min-height: 180px; border-radius: 12px; background: var(--accent); color: #fff; font-size: 16px; font-weight: 700; overflow: hidden; }
.camera-button svg { width: 44px; height: 44px; }
.camera-button input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.signature-box { flex: 1 1 auto; min-height: 220px; display: flex; flex-direction: column; border: 2px dashed var(--border); border-radius: 10px; background: #fff; overflow: hidden; }
/* Die Fläche bestimmt die Größe, nicht die Canvas: eine Canvas hat ihre Bitmap-Maße als natürliche Größe,
   und die Bitmap ist CSS-Größe × Pixeldichte — als Flex-Element würde sie das Layout selbst verändern. */
.signature-surface { position: relative; flex: 1 1 auto; min-height: 160px; }
/* touch-action: none — sonst scrollt das Handy die Seite, statt zu zeichnen. */
.signature-canvas { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; display: block; }
.signature-caption { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 10px; font-size: 11.5px; color: #555; border-top: 1px solid #ddd; }
/* Unter der Zeichenfläche statt darüber: über der Canvas fing der Knopf Striche ab und war schwer zu treffen. */
/* Eigene Füllung statt nur .btn-danger: .btn-danger ist im Projekt transparent mit roter Schrift
   (passt für einen Link-artigen Löschen-Knopf in einer Liste), hier soll „Löschen" aber als
   eindeutig roter Knopf erkennbar sein. */
.signature-clear { flex-shrink: 0; min-height: 40px; padding: 0 18px; font-size: 14px; background: var(--badge-expired-dot); color: #fff; border: 1px solid var(--badge-expired-dot); border-radius: 8px; }
.signature-clear:disabled { opacity: 0.45; }
/* Querformat am Handy: die Höhe ist knapp — Kopf und Ränder eindampfen, damit die Zeichenfläche bleibt. */
@media (orientation: landscape) and (max-height: 500px) {
  .license-flow-header { padding: 6px 16px; }
  .license-flow-sub { display: none; }
  .license-flow-body { padding: 8px 12px; gap: 8px; }
  .signature-box { min-height: 150px; }
  .signature-surface { min-height: 100px; }
  .license-flow-footer { padding-top: 6px; padding-bottom: calc(6px + env(safe-area-inset-bottom)); }
  .license-flow-footer .btn { min-height: 40px; }
}
.btn-success { background: var(--badge-ok-dot); color: #fff; border-color: var(--badge-ok-dot); }
.btn-success:disabled { opacity: 0.45; }

/* Büromaterial-Kacheln */
.supply-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; padding: 16px; }
.supply-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; box-shadow: var(--shadow-xs); transition: box-shadow 0.18s, border-color 0.18s, transform 0.18s; }
.supply-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); transform: translateY(-1px); }
.supply-card.low { border-color: var(--badge-expired-dot); }
.supply-photo { width: 100%; aspect-ratio: 1 / 1; background: var(--surface-sunken); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; position: relative; }
.supply-photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.supply-info { padding: 14px 16px; }
.supply-name { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; color: var(--text-primary); }
.supply-stock { font-size: 22px; font-weight: 650; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; color: var(--text-primary); margin-top: 6px; }
.supply-stock-unit { font-size: 12px; font-weight: 500; color: var(--text-muted); margin-left: 4px; }
.supply-meta { font-size: 13px; color: var(--text-muted); margin-top: 2px; margin-bottom: 10px; }
.supply-footer { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.supply-barcode { font-size: 11px; font-family: ui-monospace, Consolas, monospace; color: var(--text-muted); }
.scan-bar { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--border); }
.scan-input { height: 40px; font-size: 15px; font-family: ui-monospace, Consolas, monospace; flex: 1; max-width: 340px; }

/* Kamera-Knopf neben Scan-Feldern (Büromaterialien) und der Kamera-Dialog dazu
   (BarcodeCameraDialog.razor). Der Dialog liegt über anderen Popups (Picker,
   Artikel-Popup), deshalb z-index wie der Dokumentviewer. */
.btn-camera { flex-shrink: 0; width: 40px; height: 40px; padding: 0; justify-content: center; }
.btn-camera svg { width: 20px; height: 20px; }
.barcode-camera-overlay { z-index: 300; }
.modal.barcode-camera { width: min(520px, 100%); }
.barcode-camera-view { position: relative; flex-shrink: 0; aspect-ratio: 4 / 3; background: #000; border-radius: var(--radius); overflow: hidden; }
.barcode-camera-video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Zielrahmen: breit und flach, wie ein Strichcode. Nur Orientierung, ZXing liest das ganze Bild. */
.barcode-camera-target { position: absolute; left: 12%; right: 12%; top: 32%; bottom: 32%; border: 2px solid rgba(255, 255, 255, 0.9); border-radius: 8px; box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.35); pointer-events: none; }
.barcode-camera-hint { font-size: 13px; color: var(--text-muted); margin: 10px 0 0; text-align: center; }
@media (max-width: 700px) {
  .barcode-camera-overlay { padding: 0; }
  .modal.barcode-camera { width: 100%; max-width: none; height: 100%; max-height: none; border-radius: 0; border: none; }
  .barcode-camera-view { aspect-ratio: 3 / 4; }
}

@media (max-width: 1100px) { .supply-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 760px)  { .supply-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 10px; } }
@media (max-width: 480px)  { .supply-grid { grid-template-columns: 1fr; } }

/* Modal */
/* cursor: pointer ist Pflicht, nicht Deko: iOS Safari liefert click-Events auf
   normalen <div>s nur dann an Blazors zentralen Listener aus, wenn das Element
   wie ein Bedienelement aussieht. Ohne die Zeile schliesst Tippen auf die graue
   Flaeche am iPhone nicht. */
.modal-overlay { position: fixed; inset: 0; background: rgba(10, 20, 40, 0.45); z-index: 200; display: flex; align-items: center; justify-content: center; padding: 24px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
/* Flex-Spalte: Kopf und Fuss behalten ihre Hoehe, nur .modal-body scrollt.
   Dadurch bleiben X-Button und Aktions-Buttons immer sichtbar. */
.modal { background: var(--card-bg); border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow-lg); width: 100%; max-width: 520px; max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; cursor: auto; }
.modal-lg { max-width: 680px; }
.modal-xl { max-width: 860px; }
.modal-header { flex: 0 0 auto; padding: 18px 22px 16px; gap: 12px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
.modal-title { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.modal-close { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: none; border: none; cursor: pointer; color: var(--text-muted); font-size: 16px; line-height: 1; border-radius: var(--radius); font-family: inherit; }
.modal-close:hover { background: var(--row-hover); color: var(--text-primary); }
.modal-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 22px; display: flex; flex-direction: column; gap: 16px; }
.modal-footer { flex: 0 0 auto; padding: 14px 22px; border-top: 1px solid var(--border); display: flex; gap: 8px; justify-content: flex-end; align-items: center; }
.modal-footer-spacer { flex: 1; }

/* Form elements */
.form-group { display: flex; flex-direction: column; gap: 6px; }
.form-label { font-size: 13px; font-weight: 550; color: var(--text-secondary); }
.form-input { height: 38px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--card-bg); color: var(--text-primary); font-family: inherit; font-size: 14px; padding: 0 12px; outline: none; transition: border-color 0.15s, box-shadow 0.15s; width: 100%; }
/* iOS Safari gibt Datums-/Zeitfeldern eine eigene Mindestbreite (überstimmt width: 100%) und zentriert den Text.
   Ohne diese Regel ragen sie aus Dialogen heraus und der Dialog wird seitlich scrollbar. */
.form-input[type="date"], .form-input[type="time"], .form-input[type="datetime-local"] { min-width: 0; max-width: 100%; -webkit-appearance: none; appearance: none; display: block; text-align: left; }
.form-input::-webkit-date-and-time-value { text-align: left; }
.form-input:focus { border-color: var(--focus); box-shadow: var(--focus-ring); }
.form-input:disabled { background: var(--surface-sunken); color: var(--text-muted); cursor: not-allowed; }
textarea.form-input { height: auto; padding: 9px 12px; line-height: 1.45; }

/* Mengen-Stepper (Buchungsdialog): [−] [Zahl] [+] als ein zusammenhängendes
   Bedienelement. Knöpfe 44px breit, damit sie am Handy mit dem Daumen
   treffbar sind; das Zahlenfeld bleibt tippbar (25 Stück = tippen, nicht
   24× klicken). Schrift im Feld 16px, sonst zoomt iOS beim Fokussieren. Die
   nativen Spinner-Pfeile werden ausgeblendet — unsere Knöpfe ersetzen sie. */
.qty-stepper { display: flex; align-items: stretch; height: 40px; }
.qty-stepper .form-input { width: 80px; height: auto; text-align: center; border-radius: 0; font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; -moz-appearance: textfield; appearance: textfield; }
.qty-stepper .form-input::-webkit-outer-spin-button, .qty-stepper .form-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-btn { width: 44px; border: 1px solid var(--border); background: var(--content-bg); color: var(--text-primary); font-size: 20px; line-height: 1; font-family: inherit; cursor: pointer; transition: background 0.13s; }
.qty-btn:first-child { border-radius: 6px 0 0 6px; border-right: none; }
.qty-btn:last-child { border-radius: 0 6px 6px 0; border-left: none; }
.qty-btn:hover:not(:disabled) { background: var(--row-hover); }
.qty-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.form-section-title { font-size: 14px; font-weight: 650; color: var(--text-primary); margin-bottom: 10px; margin-top: 4px; }
.maintenance-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.maintenance-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 10px; cursor: pointer; transition: border-color 0.15s, background 0.15s; }
.maintenance-row:hover { border-color: var(--border-strong); background: var(--row-hover); }
.maintenance-row-title { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.maintenance-row-meta { font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }
.maintenance-row-desc { font-size: 13px; color: var(--text-muted); margin-top: 4px; }

/* ── Picker dialogs (Fahrzeug- und Artikel-Auswahl für Schnellaktionen) ──
   Geteilt von VehiclePickerDialog (Dashboard) und ArtikelPickerDialog
   (Büromaterialien): Suchfeld oben, scrollbare Trefferliste darunter. */
.picker { max-width: 480px; }
.picker-body { flex: 1; min-height: 0; gap: 10px; overflow: hidden; }
.picker-search { height: 44px; font-size: 16px; } /* 16px: iOS zooms into smaller inputs on focus */
.picker-search-row { display: flex; gap: 8px; flex-shrink: 0; }
.picker-search-row .picker-search { flex: 1; min-width: 0; }
.picker-search-row .btn-camera { width: 44px; height: 44px; }
.picker-list { display: flex; flex-direction: column; overflow-y: auto; max-height: 50vh; border: 1px solid var(--border); border-radius: 10px; }
.picker-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; min-height: 48px; padding: 10px 14px; background: var(--card-bg); border: none; border-bottom: 1px solid var(--border); text-align: left; cursor: pointer; font-family: inherit; }
.picker-row:last-child { border-bottom: none; }
.picker-row:hover { background: var(--row-hover); }
.picker-row-main { flex: 1; min-width: 0; font-size: 14px; font-weight: 600; color: var(--text-primary); }
.picker-row-sub { display: block; font-size: 12.5px; font-weight: 400; color: var(--text-muted); margin-top: 1px; }
.picker-row-meta { font-size: 12.5px; color: var(--text-muted); text-align: right; white-space: nowrap; }

/* ── Inline-Kombifeld (z.B. Mitarbeiter-Suche im Urlaubsantrag) ──
   Gleiches Prinzip wie die Picker-Dialoge oben (tippen filtert eine Liste),
   aber als Dropdown direkt am Feld statt als eigener Dialog — für einzelne
   Formularfelder, bei denen ein ganzer Popup-Dialog übertrieben wäre. */
.combo-wrapper { position: relative; }
.combo-menu { position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; right: 0; max-height: 220px; overflow-y: auto; background: var(--card-bg); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-md); }
.combo-option { padding: 9px 12px; font-size: 14px; cursor: pointer; }
.combo-option:hover { background: var(--row-hover); }
.combo-empty { padding: 9px 12px; font-size: 12.5px; color: var(--text-muted); }

/* ── Role dashboards ── */
.dashboard-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); margin-bottom: 20px; overflow: hidden; box-shadow: var(--shadow-xs); }
.dashboard-card-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.dashboard-card-title { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
.dashboard-card-sub { font-size: 13px; color: var(--text-muted); margin-top: 3px; }
.dashboard-card-ok { padding: 16px; background: var(--badge-ok-bg); border-color: var(--badge-ok-dot); }
.dashboard-card-ok .dashboard-card-title,
.dashboard-card-ok .dashboard-card-sub { color: var(--badge-ok-text); }
.dashboard-confirmation { background: var(--badge-ok-bg); color: var(--badge-ok-text); border: 1px solid var(--badge-ok-dot); border-radius: 8px; padding: 10px 14px; font-size: 13px; margin-bottom: 14px; }

.alert-row { display: flex; align-items: center; gap: 12px; padding: 12px 18px; border-bottom: 1px solid var(--border); border-left: 4px solid transparent; }
.alert-row:last-child { border-bottom: none; }
.alert-row-danger  { border-left-color: var(--badge-expired-dot); }
.alert-row-warning { border-left-color: var(--badge-warning-dot); }
.alert-row-info { flex: 1; min-width: 0; }
.alert-row-plate { font-size: 14px; font-weight: 650; font-variant-numeric: tabular-nums; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.alert-row-driver { font-size: 13px; font-weight: 400; color: var(--text-muted); letter-spacing: 0; }
.alert-row-meta { font-size: 13px; color: var(--text-muted); margin-top: 4px; }
.alert-row-danger .alert-row-meta { color: var(--badge-expired-text); font-weight: 500; }

/* Immer zwei Spalten (auch mobil); max-width deckelt die Kachel, damit das
   Quadrat am Desktop nicht auf Spaltenbreite aufgeblasen wird. */
.dashboard-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; max-width: 348px; margin-bottom: 16px; }
.dashboard-action { flex-direction: column; align-items: center; justify-content: center; gap: 10px; aspect-ratio: 1; padding: 12px; border-radius: var(--radius-lg); font-size: 14px; font-weight: 600; line-height: 1.3; text-align: center; white-space: normal; }
.dashboard-action svg { width: 28px; height: 28px; flex-shrink: 0; }

/* ── Startmenü (Spec 2026-09-22) ──────────────────────────────────────
   Startseite für dispatcher, office_management und driver: Begrüßung plus
   ein Raster aus Modul-Kacheln. Keine Kennzahlen, keine Warnungen. */
.start-greeting { font-size: 24px; font-weight: 650; letter-spacing: -0.015em; line-height: 1.2; color: var(--text-primary); }
.start-greeting-sub { font-size: 14px; color: var(--text-muted); margin-top: 4px; margin-bottom: 24px; }
.start-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; max-width: 640px; }
.start-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; aspect-ratio: 1; padding: 16px; text-align: center; text-decoration: none;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs); transition: box-shadow 0.13s, border-color 0.13s;
}
.start-tile:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.start-chip {
  width: 40px; height: 40px; border-radius: 10px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-gradient); color: #fff;
}
.start-tile-name { font-size: 15px; font-weight: 600; color: var(--text-primary); line-height: 1.25; }

/* Kachel und Menüeintrag sind Flex-Elemente. Die allgemeinen Regeln
   .mobile-only / .desktop-only setzen aber display:block bzw. display:none
   mit !important — ohne diese Zeilen stünden Symbol und Text eines sichtbaren
   mobile-only-Eintrags untereinander statt nebeneinander, und der Inhalt einer
   Kachel wäre nicht mehr zentriert. Höhere Spezifität schlägt die Grundregel.
   Nötig, seit die Anzeige-Art am einzelnen Element hängt (ModuleCatalog) und
   nicht mehr an einem umhüllenden <div>. */
.start-tile.mobile-only,
.nav-item.mobile-only { display: none !important; }
@media (max-width: 700px) {
  .start-tile.mobile-only { display: flex !important; }
  .start-tile.desktop-only { display: none !important; }
  .nav-item.mobile-only { display: flex !important; }
  .nav-item.desktop-only { display: none !important; }
}

/* Drei Schnellaktionen nebeneinander (Büromaterialien). Auf schmalen Handys
   werden die Quadrate klein, deshalb dort etwas kleinere Schrift, damit
   "Wareneingang" nicht aus der Kachel läuft. */
.page-actions { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 528px; }
@media (max-width: 480px) { .page-actions .dashboard-action { font-size: 12px; gap: 8px; padding: 8px; } .page-actions .dashboard-action svg { width: 24px; height: 24px; } }

.recent-row { display: flex; align-items: center; gap: 12px; padding: 11px 18px; border-bottom: 1px solid var(--border); }
.recent-row:last-child { border-bottom: none; }
.recent-row-plate { font-size: 13.5px; font-weight: 650; font-variant-numeric: tabular-nums; min-width: 112px; }
.recent-row-info { flex: 1; min-width: 0; }
.recent-row-title { font-size: 13.5px; font-weight: 500; }
.recent-row-meta { font-size: 12.5px; color: var(--text-muted); margin-top: 1px; }

select.form-input { cursor: pointer; }

/* Mobile cards */
.m-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); padding: 14px 16px; margin-bottom: 10px; }
.m-card-name    { font-size: 14px; font-weight: 600; margin-bottom: 2px; }
.m-card-meta    { font-size: 11.5px; color: var(--text-muted); margin-bottom: 10px; }
.m-card-badges  { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.m-card-label   { font-size: 12.5px; color: var(--text-muted); font-weight: 500; }
.m-card-actions { display: flex; gap: 8px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.desktop-only { }
.mobile-only { display: none !important; }

/* Login */
.login-shell { display: flex; min-height: 100dvh; }
.login-left {
  width: 40%; background: var(--brand-navy);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  padding: 40px;
}
.login-left-logo { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.login-left-logo img { height: 280px; width: auto; }
.login-company { font-size: 22px; font-weight: 700; color: #fff; letter-spacing: -0.01em; }
.login-tagline { font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: #fff; opacity: 0.55; }
.login-right {
  flex: 1; background: var(--content-bg);
  display: flex; align-items: center; justify-content: center; padding: 40px;
}
.login-form-box { width: 100%; max-width: 380px; }
.login-title { font-size: 26px; font-weight: 650; letter-spacing: -0.015em; color: var(--text-primary); margin-bottom: 4px; }
.login-subtitle { font-size: 14px; color: var(--text-muted); margin-bottom: 28px; }
.login-form { display: flex; flex-direction: column; gap: 16px; }
.login-field { display: flex; flex-direction: column; gap: 6px; }
.login-label { font-size: 13px; font-weight: 550; color: var(--text-secondary); }
.login-input {
  height: 44px; border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--card-bg); color: var(--text-primary);
  font-family: inherit; font-size: 16px; padding: 0 12px;
  outline: none; transition: border-color 0.15s; width: 100%;
}
.login-input:focus { border-color: var(--focus); box-shadow: var(--focus-ring); }
.login-input-wrap { position: relative; }
.login-input-wrap .login-input { padding-right: 40px; }
.pw-toggle { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: var(--text-muted); font-size: 14px; }
.pw-toggle:hover { color: var(--accent); }
.password-wrapper { position: relative; display: flex; align-items: center; }
.password-wrapper .login-input { padding-right: 44px; flex: 1; }
.password-toggle { position: absolute; right: 10px; background: none; border: none; padding: 4px; cursor: pointer; color: var(--text-muted); transition: color .15s; }
.password-toggle:hover { color: var(--accent); }
.login-btn {
  height: 44px; background: var(--accent); color: white; border: none;
  border-radius: var(--radius); font-family: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer; margin-top: 4px; transition: background 0.13s; width: 100%;
}
.login-btn:hover:not(:disabled) { background: var(--accent-hover); }
.login-btn:disabled { opacity: 0.7; cursor: not-allowed; }
.login-divider { display: flex; align-items: center; gap: 10px; margin: 18px 0; color: var(--text-muted); font-size: 12.5px; }
.login-divider::before, .login-divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.login-btn-microsoft { display: flex; align-items: center; justify-content: center; gap: 10px; height: 44px; background: var(--card-bg); color: var(--text-primary); border: 1px solid var(--border-strong); border-radius: var(--radius); font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer; text-decoration: none; box-shadow: var(--shadow-xs); transition: background 0.13s; }
.login-btn-microsoft:hover { background: var(--row-hover); }
.login-footer-links { display: flex; align-items: center; gap: 8px; margin-top: 20px; font-size: 12px; color: var(--text-muted); justify-content: center; }
.login-footer-links a { color: var(--text-muted); text-decoration: underline; cursor: pointer; }
.login-footer-links a:hover { color: var(--text-primary); }
.login-error { background: var(--badge-expired-bg); border: 1px solid var(--badge-expired-dot); border-radius: 6px; color: var(--badge-expired-text); font-size: 13px; padding: 10px 14px; margin-bottom: 16px; }
.login-success { background: var(--badge-ok-bg); border: 1px solid var(--badge-ok-dot); border-radius: 6px; color: var(--badge-ok-text); font-size: 13px; padding: 10px 14px; margin-bottom: 16px; }
.login-sub { font-size: 13px; color: var(--text-muted); margin-bottom: 24px; line-height: 1.5; }
.login-footer { font-size: 12px; color: var(--text-muted); margin-top: 20px; text-align: center; }
.login-footer a { color: var(--text-muted); }

/* Routes sub-table */
.routes-expanded td { background: var(--content-bg) !important; }
.sub-table { width: 100%; border-collapse: collapse; }
.sub-table th { background: transparent; font-size: 12px; font-weight: 550; color: var(--text-muted); padding: 7px 16px; border-bottom: 1px solid var(--border); }
.sub-table td { font-size: 13px; padding: 9px 16px; border-bottom: 1px solid var(--border); color: var(--text-primary); }
.sub-table tr:last-child td { border-bottom: none; }
.price-form-table { width: 100%; border-collapse: collapse; }
.price-form-table th { text-align: left; font-size: 12px; font-weight: 550; color: var(--text-muted); padding: 7px 8px; border-bottom: 1px solid var(--border); }
.price-form-table td { padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.price-form-table tr:last-child td { border-bottom: none; }

/* Country badge (inline tag) */
.country-tag { display: inline-block; margin-left: 5px; font-size: 11.5px; font-weight: 500; color: var(--text-secondary); background: var(--surface-sunken); padding: 1px 6px; border-radius: 4px; }

/* Misc */
.error-message { color: var(--badge-expired-text); font-size: 12px; margin-top: 4px; }
.loading-hint  { color: var(--text-muted); font-size: 14px; padding: 20px; }
.empty-hint    { color: var(--text-muted); font-size: 14px; padding: 28px 16px; text-align: center; }
.page-placeholder { color: var(--text-muted); font-size: 13px; }
.placeholder-card {
  background: var(--card-bg); border: 1.5px dashed var(--border-strong); border-radius: var(--radius-lg);
  padding: 48px 24px; text-align: center;
}
.placeholder-icon {
  width: 40px; height: 40px; border: 2px dashed var(--border); border-radius: 8px;
  margin: 0 auto 12px; opacity: 0.5;
}

/* ── Rechnungstool ─────────────────────────────────────────────────────── */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; }
.tab { background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px; padding: 10px 14px; font-family: inherit; font-size: 14px; font-weight: 550; color: var(--text-muted); cursor: pointer; white-space: nowrap; }
.tab:hover { color: var(--text-primary); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.inline-input { height: 30px; width: 110px; font-size: 12.5px; text-align: right; }
.rt-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 20px; }
.rt-action { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 22px 24px; background: var(--accent); border: 1px solid transparent; border-radius: var(--radius-lg); cursor: pointer; font-family: inherit; text-align: left; color: white; box-shadow: var(--shadow-xs); transition: background 0.13s; }
.rt-action:hover:not(:disabled) { background: var(--accent-hover); }
/* Gesperrt, solange die Rechnungsliste lädt — ohne das leuchtet ein toter Knopf beim Überfahren auf. */
.rt-action:disabled { opacity: 0.6; cursor: default; }
.rt-action-title { font-size: 15px; font-weight: 700; }
.rt-action-sub { font-size: 12.5px; color: rgba(255,255,255,0.82); }
.chip { display: inline-block; padding: 2px 8px; border-radius: 99px; font-size: 11.5px; font-weight: 600; background: var(--badge-ok-bg); color: var(--badge-ok-text); margin: 1px 3px 1px 0; white-space: nowrap; }
.chip-warn { background: var(--badge-warning-bg); color: var(--badge-warning-text); }
.warning-list { background: var(--badge-warning-bg); color: var(--badge-warning-text); border-radius: 8px; padding: 12px 16px 12px 30px; font-size: 13.5px; line-height: 1.5; margin: 0; max-height: 320px; overflow-y: auto; }
.warning-list li { margin: 3px 0; }
.review-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.review-table th { position: sticky; top: 0; background: var(--card-bg); text-align: left; font-size: 11.5px; font-weight: 550; color: var(--text-muted); padding: 6px 8px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.review-table td { padding: 5px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
.review-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.review-table tr.row-manual td { background: var(--badge-warning-bg); }
.totals-box { display: grid; grid-template-columns: auto auto; gap: 4px 24px; justify-content: end; font-size: 13px; font-variant-numeric: tabular-nums; }
.totals-box .total-strong { font-weight: 700; font-size: 14px; }
.modal-xxl { max-width: 1240px; }

/* ── Dispatch: Karte ─────────────────────────────────────────────────── */
/* isolation: Google Maps und die eigenen Bedienelemente (bis z-index 1000,
   .map-layers) malen sonst über .modal-overlay (200) — der Disponieren-Dialog
   läge dann halb unter der Karte. */
.dispatch-map-wrap { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); overflow: hidden; margin-bottom: 18px; isolation: isolate; }
.dispatch-map { width: 100%; } /* Höhe kommt ausschließlich von .dispatch-shell .dispatch-map (unten) — .dispatch-map rendert nur innerhalb von .dispatch-shell. */
.dispatch-banner { padding: 8px 14px; font-size: 12.5px; background: var(--badge-warning-bg); color: var(--badge-warning-text); border-bottom: 1px solid var(--badge-warning-dot); }
/* Legende auf der Karte, unten links. Rechts bleiben 64 px für den
   Kartenstil-Umschalter frei; wird es eng, bricht die Leiste um statt ihn zu
   verdecken. pointer-events nur auf den Flächen selbst, damit sich die Karte
   zwischen Detail und Leiste weiter ziehen lässt. */
/* Bewusst ohne z-index: kein eigener Stapelkontext, Googles Kartenebenen und
   die eigenen Bedienelemente/Werkzeuge ordnen sich weiter gemeinsam in
   .dispatch-map-area. */
.dispatch-map-stage { position: relative; }
.map-legend { position: absolute; left: 10px; bottom: 10px; max-width: calc(100% - 74px); z-index: 998; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; pointer-events: none; }
.map-legend-bar, .map-legend-detail { pointer-events: auto; background: rgba(255,255,255,.94); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-md); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.map-legend-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 12px; padding: 5px 10px; font-size: 12px; line-height: 1.5; color: var(--text-secondary); }
.map-legend-item { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.map-legend-item b { font-weight: 650; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.map-legend-item .dm-dot { position: static; flex: 0 0 auto; width: 10px; height: 10px; border: none; box-shadow: none; }
.map-legend-more { border: none; background: none; padding: 0; font: inherit; color: var(--badge-warning-text); cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.map-legend-detail { display: flex; flex-direction: column; gap: 2px; max-height: 160px; overflow-y: auto; padding: 8px 10px; font-size: 12px; color: var(--text-secondary); }
.map-legend-detail strong { font-weight: 650; color: var(--text-primary); }

/* Eigene Bedienelemente auf der Karte (Googles Standardsteuerelemente sind aus,
   disableDefaultUI). Eine Familie: card-bg, kein dunkler Rahmen, shadow-md. */
/* bottom = .map-layers bottom (28px) + dessen Höhe (76px) + 12px Abstand wie
   zuvor = 116px, damit Zoom weiter direkt über dem Ebenen-Quadrat sitzt. */
.map-zoom { position: absolute; right: 12px; bottom: 116px; z-index: 4; display: flex; flex-direction: column; background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow-md); overflow: hidden; }
.map-zoom-btn { width: 36px; height: 36px; border: none; background: none; color: var(--text-primary); font: 400 19px/1 var(--font-sans); cursor: pointer; }
.map-zoom-btn + .map-zoom-btn { border-top: 1px solid var(--border); }
.map-zoom-btn:hover { background: var(--row-hover); }

/* Vollbild oben rechts, rund, in einer Reihe mit den Werkzeugen (MapTools).
   z-index 1000: über .cn-panel/.map-search (999) — sonst liegt ein offenes
   Werkzeug-Panel über dem Knopf und die obere rechte Ecke ist unklickbar. */
.map-fullscreen-btn { position: absolute; top: 12px; right: 12px; z-index: 1000; width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border: none; border-radius: 50%; background: var(--card-bg); color: var(--text-primary); box-shadow: var(--shadow-md); cursor: pointer; }
.map-fullscreen-btn:hover { background: var(--row-hover); }
.map-fullscreen-btn:focus-visible { box-shadow: var(--focus-ring); }

/* Ebenen-Umschalter unten rechts, im Google-Maps-Muster: ein 76-px-Quadrat
   zeigt die Vorschau des Kartentyps, zu dem ein Klick WECHSELT (nicht des
   aktuellen), links davon ein kleiner runder "Ebenen"-Knopf und, wenn offen,
   ein Streifen mit weiteren Kacheln (Verkehr, Postleitzahlen, Länder).
   bottom: 28px statt 12px — sonst deckt das Quadrat Googles eigenes Logo
   unten links bzw. die Attributionszeile unten rechts ab (2026-09-19 im
   Live-Betrieb beobachtet); dieselbe 28-px-Regel gilt spiegelbildlich für die
   Legende unten links, siehe .dispatch-shell .map-legend weiter unten.
   z-index 1000: über .cn-panel/.map-search (999), sonst deckt ein offenes
   Werkzeug-Panel den Streifen zu. */
.map-layers { position: absolute; right: 12px; bottom: 28px; z-index: 1000; display: flex; align-items: flex-end; gap: 8px; }

/* Streifen: hängt links von Knopf+Quadrat (right: 100% der eigenen Box, siehe
   .map-layers), taucht per Übergang auf statt per Layout-Sprung — dadurch
   verschieben sich Knopf/Quadrat beim Öffnen nie. is-pinned ist EIN
   Code-Pfad für alle Geräte (Klick auf .map-layers-pin, schließt bei Klick
   außerhalb oder Escape); @media (hover: hover) öffnet zusätzlich rein
   optisch bei Hover/Fokus, ohne dass JS zwischen Touch und Maus unterscheiden
   muss. flex-wrap fängt sehr schmale Bildschirme auf (Handy, mehrere Reihen
   statt Überlauf). */
.map-layers-strip { position: absolute; right: 100%; bottom: 0; margin-right: 8px; width: max-content; max-width: calc(100vw - 140px); display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: flex-end; gap: 10px; padding: 10px; background: var(--card-bg); border-radius: var(--radius-lg); box-shadow: var(--shadow-md); opacity: 0; transform: translateX(8px); pointer-events: none; transition: opacity .15s ease, transform .15s ease; }
@media (hover: hover) {
  .map-layers:hover .map-layers-strip,
  .map-layers:focus-within .map-layers-strip { opacity: 1; transform: translateX(0); pointer-events: auto; }
}
@media (hover: hover) {
  /* Mit Maus öffnet Hover den Streifen — der runde Ebenen-Knopf wäre ein zweiter
     Knopf ohne Mehrwert. Er bleibt nur für Touch, wo Tippen aufs Quadrat den
     Kartentyp wechselt. Die unsichtbare Brücke hält :hover über der 8px-Lücke. */
  .map-layers-strip::after { content: ""; position: absolute; left: 100%; top: 0; bottom: 0; width: 8px; }
}
.map-layers.is-pinned .map-layers-strip { opacity: 1; transform: translateX(0); pointer-events: auto; }
@media (prefers-reduced-motion: reduce) {
  .map-layers-strip { transition: none; }
}
/* display:contents lässt die Kacheln von postcodeOverlay.js so in der Reihe
   liegen, als wären sie direkte Streifen-Kinder — der Abschnitt selbst zeigt
   sonst nichts an. */
.map-layers-postcodes { display: contents; }

/* Kachel im Streifen: ~64-px-Vorschau + Beschriftung darunter, aktiver
   Zustand = 2-px-Ring in --accent. Echter <button aria-pressed>. */
.map-layers-tile { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 64px; padding: 0; border: none; background: none; font-family: inherit; cursor: pointer; }
.map-layers-tile-thumb { display: block; width: 64px; height: 64px; border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-xs); border: 2px solid transparent; }
.map-layers-tile-thumb svg { display: block; width: 100%; height: 100%; }
.map-layers-tile-cap { font-size: 11.5px; font-weight: 600; line-height: 1.15; color: var(--text-secondary); }
.map-layers-tile[aria-pressed="true"] .map-layers-tile-thumb { border-color: var(--accent); }
.map-layers-tile[aria-pressed="true"] .map-layers-tile-cap { color: var(--accent); }
.map-layers-tile:disabled { opacity: .45; cursor: not-allowed; }
.map-layers-tile:focus-visible { outline: none; }
.map-layers-tile:focus-visible .map-layers-tile-thumb { box-shadow: var(--focus-ring); }

/* Länderkarte des PLZ-Overlays: klappt ÜBER dem Streifen auf (nicht über dem
   Quadrat), ausgelöst von der "Länder"-Kachel. */
/* Der Aufsatz trägt Position UND den 8px-Abstand als Innenabstand: so bleibt
   die Fläche zwischen Streifen und Länderkarte überfahrbar (:hover reißt nicht
   ab), und der Aufsatz ist kein Flex-Kind mit eigener Lücke im Streifen. */
.map-layers-card-slot { position: absolute; left: 0; bottom: 100%; padding-bottom: 8px; }
.map-layers-card { min-width: 220px; max-height: 260px; overflow-y: auto; padding: 10px 12px; display: grid; gap: 6px; background: var(--card-bg); border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow-lg); font-size: 12.5px; color: var(--text-primary); }
.map-layers-card[hidden] { display: none; }
.map-layers-check-all { padding-bottom: 6px; border-bottom: 1px solid var(--border); font-weight: 600; }
.map-layers-check { display: flex; align-items: center; gap: 8px; cursor: pointer; }

/* Kleiner runder Knopf zwischen Streifen und Quadrat — Touch-Auslöser fürs
   Auf-/Zuklappen, auf Hover-Geräten ein zusätzlicher Pin. */
.map-layers-pin { flex: 0 0 auto; width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; border: none; border-radius: 50%; background: var(--card-bg); color: var(--text-primary); box-shadow: var(--shadow-md); cursor: pointer; }
.map-layers-pin:hover { background: var(--row-hover); }
.map-layers-pin:focus-visible { box-shadow: var(--focus-ring); }
.map-layers-pin[aria-expanded="true"] { background: var(--accent); color: #fff; }
/* Muss NACH der Grundregel oben stehen (gleiche Spezifität, die spätere gewinnt). */
@media (hover: hover) { .map-layers-pin { display: none; } }

/* Quadrat: zeigt eine Kartenvorschau (Foto-Look) statt einer Fläche — deshalb
   eigene, dunklere Textfarbe fürs Beschriftungsfeld über einem Verlaufsschleier
   statt var(--card-bg)/var(--text-primary) wie die übrigen Bedienelemente. */
.map-layers-square { position: relative; flex: 0 0 auto; width: 76px; height: 76px; padding: 0; overflow: hidden; border: none; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); cursor: pointer; }
.map-layers-square:focus-visible { box-shadow: var(--focus-ring); }
.map-layers-square-thumb { position: absolute; inset: 0; display: block; }
.map-layers-square-thumb svg { display: block; width: 100%; height: 100%; }
.map-layers-square-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 4px 0 5px; background: linear-gradient(to top, rgba(0,0,0,.55), transparent); color: #fff; font: 650 12px/1 var(--font-sans); text-align: center; }

/* Quellenangabe des PLZ-Overlays (ODbL/CC BY verlangen sie), nur solange das
   Overlay an ist. Unten links über Legende (10px) und ORS-Zuschreibung (44px),
   damit sich die drei nie überdecken; Googles eigene Zuschreibung bleibt
   unangetastet. Bricht um statt abzuschneiden — eine Lizenzangabe darf am
   Handy nicht halb verschwinden. */
.map-attribution { position: absolute; left: 10px; bottom: 78px; z-index: 3; max-width: min(62%, 560px); padding: 3px 10px; background: color-mix(in srgb, var(--card-bg) 90%, transparent); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-xs); font: 500 11px/1.45 var(--font-sans); color: var(--text-muted); }
.map-attribution a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* Hinweis statt leerer grauer Fläche (Key/Map ID fehlt, Skript blockiert,
   gm_authFailure). Das Panel bleibt daneben voll nutzbar. */
.dispatch-map-error { position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; justify-content: center; padding: 24px; text-align: center; background: var(--surface-sunken); color: var(--text-muted); font-size: 13.5px; }

/* Leerer Aufsatz nur für JS-erzeugte Bedienelemente (Zoom, Vollbild, Ebenen,
   ORS-Zuschreibung) — Blazor rendert ihn ohne Kinder und rührt sein Inneres
   nie an (DispatchMap.razor). inset:0 deckt die ganze Kartenfläche ab,
   pointer-events:none lässt Ziehen/Zoomen der Karte durch die Lücken durch;
   erst die Kinder selbst (Knöpfe, Popup, Pille) sind wieder klickbar. */
.dispatch-map-controls { position: absolute; inset: 0; pointer-events: none; }
.dispatch-map-controls > * { pointer-events: auto; }

/* ORS-Lizenzpflicht: nur sichtbar, solange eine berechnete Route der
   Karten-Werkzeuge auf der Karte liegt (dispatchMap.setOverlay/clearOverlay).
   bottom: 44px statt 10px — über der Legende, damit sie Googles eigenes Logo
   unten links nicht verdeckt. */
.map-route-credit { position: absolute; left: 10px; bottom: 44px; z-index: 3; padding: 3px 10px; background: color-mix(in srgb, var(--card-bg) 90%, transparent); border: 1px solid var(--border); border-radius: 999px; box-shadow: var(--shadow-xs); font: 500 11.5px/1.4 var(--font-sans); color: var(--text-muted); white-space: nowrap; }

/* Zusammenfassung einer Auftragsroute (Spec 2026-09-21): eigene Karte, wieder
   34px höher gestapelt — diesmal über der PLZ/ORS-Zuschreibung
   (.map-attribution), nicht über .map-route-credit, sonst überdeckt sie sich
   mit der Zuschreibung, wenn beide gleichzeitig stehen (Review-Fund). Stapel
   unten→oben: Legende, Routen-Zuschreibung, PLZ-Zuschreibung, Routen-Karte.
   Folgt derselben Panel-Breite/Sheet-Kante wie .map-route-credit, siehe jede
   Stelle unten, die dessen Position setzt. */
.map-route-summary { position: absolute; left: 10px; bottom: 112px; z-index: 3; display: flex; align-items: center; gap: 10px; max-width: min(520px, calc(100% - 20px)); padding: 7px 8px 7px 14px; background: var(--card-bg); border-radius: 999px; box-shadow: var(--shadow-md); font: 600 13px/1.3 var(--font-sans); color: var(--text-primary); }
.map-route-summary > span { min-width: 0; }
.map-route-summary small { display: block; font-weight: 500; font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.map-route-summary.is-error small { color: var(--badge-expired-text); }
.map-route-summary button { flex: 0 0 auto; width: 26px; height: 26px; border: none; border-radius: 50%; background: transparent; color: var(--text-muted); cursor: pointer; }
.map-route-summary button:hover { background: var(--row-hover); }

/* Vollbild-Knopf und Vollbild-Zustand. Bewusst kein
   echtes Browser-Vollbild (Fullscreen-API) — die Karte soll nur den Platz
   innerhalb der Website ausfüllen, Adress-/Lesezeichenleiste bleiben sichtbar.
   dispatchMap.js schaltet dafür nur die Klasse .is-pseudo-fullscreen. z-index
   150: über Sidebar (100), unter Dialogen (200). Die Karte füllt dann den Rest
   neben Banner und Legende. */
.dispatch-map-wrap.is-pseudo-fullscreen { position: fixed; inset: 0; z-index: 150; display: flex; flex-direction: column; border: none; border-radius: 0; margin: 0; }
.dispatch-map-wrap.is-pseudo-fullscreen .dispatch-map-area { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.dispatch-map-wrap.is-pseudo-fullscreen .dispatch-map-stage { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.dispatch-map-wrap.is-pseudo-fullscreen .dispatch-map { flex: 1 1 auto; height: auto; min-height: 0; }
/* Ausgang aus dem Vollbild: derselbe Knopf wie zum Öffnen (zeigt dann das
   Verkleinern-Symbol + aria-label "Vollbild beenden", siehe dispatchMap.js
   refresh()) und Escape — kein zusätzliches ✕. Ein zweites Steuerelement an
   derselben Stelle stand bis 2026-09-19 doppelt übereinander. */
.dispatch-map-wrap.is-pseudo-fullscreen .cn-panel { top: 54px; }

/* Rahmen um die Karte: Bezugspunkt fürs CourierNet-Tool. z-index 0 macht einen
   eigenen Stapelkontext — die Karte, die eigenen Bedienelemente (bis 1001) und
   das Panel bleiben darin gefangen und liegen nie über Sidebar oder Dialogen. */
.dispatch-map-area { position: relative; z-index: 0; }

/* Karten-Werkzeuge (CourierNet-Tool, Entfernungs-Tool): Knöpfe links unter
   Zoom (10 + 71 px) und Vollbild (10 + 36 px), also ab 137 px, im Ruhezustand
   quadratisch wie die eigenen Knöpfe darüber. Beim Überfahren fährt der Knopf
   selbst auf und gibt den Namen frei (kein Hover auf dem Handy → Karte bleibt
   frei). Panel rechts mit eigenem Scrollen; unten bleiben ~76 px für den
   Kartenstil-Umschalter und die Attribution frei.
   z-index 999 < Vollbild/Ebenen (1000, siehe oben): der aufgeklappte
   Ebenen-Umschalter liegt über dem Panel, nie darunter. Die Knöpfe selbst
   liegen mit 998 eine Stufe tiefer als Panel und Suchleiste. Unter 700 px
   liegt das Panel unter der Karte statt darüber (siehe Responsive). */
.map-tools { position: absolute; z-index: 998; display: flex; gap: 8px; } /* Position/Richtung/Abstand kommen ausschließlich von .dispatch-shell .map-tools (unten) — .map-tools rendert nur innerhalb von .dispatch-shell. */
/* Google-Maps-Chip-Look, dieselbe Familie wie die Suchpille: card-bg, kein
   Rahmen, shadow-md; Symbol in --focus (Petrol), Beschriftung in
   --text-primary. Beschriftung ist seit 2026-09-19 immer sichtbar (kein
   Hover-Aufklappen mehr — auf dem Handy gab es ohnehin kein Hover, am
   Desktop war „nur Symbol" nicht selbsterklärend genug). */
.map-tool-btn { display: inline-flex; align-items: center; gap: 8px; height: 40px; padding: 0 14px 0 12px; border: none; border-radius: 20px; background: var(--card-bg); color: var(--text-primary); box-shadow: var(--shadow-md); font: 500 13px/1.3 var(--font-sans); cursor: pointer; }
.map-tool-btn svg { flex: 0 0 auto; width: 18px; height: 18px; color: var(--focus); }
/* "Ein Schritt dunkler" (--row-hover) + kräftigerer Schatten, kein
   Transform-Sprung. */
.map-tool-btn:hover { background: var(--row-hover); box-shadow: var(--shadow-lg); }
.map-tool-btn:focus-visible { box-shadow: var(--focus-ring); }
.map-tool-btn[aria-pressed="true"] { background: var(--accent); color: #fff; }
.map-tool-btn[aria-pressed="true"] svg { color: #fff; }
.map-tool-btn[aria-pressed="true"]:hover { box-shadow: var(--shadow-lg); }
.map-tool-label { white-space: nowrap; }
/* Suchleiste (Fahrzeug oder Ort) oben links neben dem Zoom-Control (10 + 34 px);
   rechts oben ist seit dem Umzug des Kartenstil-Umschalters nach unten nichts
   mehr im Weg. Look wie .map-tool-btn, z-index 999 < Vollbild/Ebenen (1000). */
.map-search { position: absolute; top: 10px; left: 54px; width: 300px; max-width: calc(100% - 64px); z-index: 999; display: flex; flex-direction: column; gap: 4px; }
.map-search-field { position: relative; display: flex; }
.map-search-field input { width: 100%; height: 36px; padding: 0 30px 0 12px; border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-md); background: #fff; background-clip: padding-box; color: var(--text-primary); font: 500 13px/1.3 var(--font-sans); }
/* iOS Safari zoomt beim Antippen in Felder unter 16 px hinein und nicht zurück. */
@media (pointer: coarse) { .map-search-field input { font-size: 16px; } }
.map-search-clear { position: absolute; right: 4px; top: 4px; width: 28px; height: 28px; border: none; background: none; color: var(--text-muted); font-size: 13px; line-height: 1; cursor: pointer; }
.map-search-results { max-height: 220px; overflow-y: auto; background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-md); }
.map-search-item { display: block; width: 100%; text-align: left; padding: 6px 9px; border: none; border-bottom: 1px solid var(--border); background: none; color: var(--text-primary); font-family: inherit; font-size: 12.5px; cursor: pointer; }
.map-search-item:last-child { border-bottom: none; }
.map-search-item:hover { background: var(--row-hover); }
.map-search-item span { display: block; font-size: 11.5px; color: var(--text-muted); }
.map-search-hint { padding: 6px 9px; font-size: 11.5px; color: var(--text-muted); }

.cn-panel { position: absolute; top: 10px; right: 10px; bottom: 76px; width: 360px; max-width: calc(100% - 20px); z-index: 999; display: flex; flex-direction: column; background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 28px rgba(0,0,0,.18); font-size: 12.5px; }
.cn-panel-header { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.cn-panel-title { flex: 1; font-weight: 700; font-size: 13.5px; }
.cn-panel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.cn-label { font-weight: 700; font-size: 11.5px; color: var(--text-muted); margin-bottom: 3px; }
.cn-place { display: grid; grid-template-columns: 118px 1fr auto; gap: 6px; }
.cn-place select, .cn-place input, .cn-panel select { height: 30px; padding: 0 6px; border: 1px solid var(--border); border-radius: 6px; font-family: inherit; font-size: 12.5px; min-width: 0; background: var(--card-bg); color: var(--text-primary); }
.cn-place .btn-icon { width: 30px; height: 30px; padding: 0; justify-content: center; }
.cn-avoid { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.cn-avoid .chip button { margin-left: 4px; border: none; background: none; cursor: pointer; font-size: 12px; line-height: 1; color: inherit; padding: 0; }
.cn-result { background: var(--badge-ok-bg); color: var(--badge-ok-text); border-radius: 6px; padding: 8px 10px; font-size: 14px; font-weight: 700; }
.cn-hint { color: var(--text-muted); font-size: 11.5px; }
.cn-found { color: var(--text-muted); font-size: 11.5px; line-height: 1.4; }
.cn-table { width: 100%; border-collapse: collapse; }
.cn-table th { text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); padding: 4px 4px; border-bottom: 1px solid var(--border); }
.cn-table td { padding: 5px 4px; border-bottom: 1px solid var(--border); vertical-align: top; }
.cn-table td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.cn-table tr.is-stale td { color: var(--text-muted); }

/* Route und Pins (Klassen, die dispatchMap.setOverlay per JS setzt). */
/* Routen- und Orts-Pins im Google-Look. AdvancedMarkerElement verankert die
   Unterkante-Mitte des Inhalts an der Koordinate: Kreise schieben sich um die
   halbe Höhe nach unten (sitzen mittig), der Tropfen steht mit der Spitze drauf. */
.dm-pin { position: relative; }
.dm-pin-start { width: 14px; height: 14px; transform: translateY(50%); }
.dm-pin-stop { width: 18px; height: 18px; transform: translateY(50%); }
.dm-pin-dot { position: absolute; inset: 0; box-sizing: border-box; border-radius: 50%; background: #fff; border: 3px solid var(--route-pin-ring); box-shadow: 0 1px 4px rgba(0,0,0,.4); }
.dm-pin-stop .dm-pin-dot { border-width: 2px; font: 700 10px/14px var(--font-sans); text-align: center; color: var(--route-pin-ring); font-variant-numeric: tabular-nums; }
.dm-pin-end, .dm-pin-place { width: 27px; height: 43px; }
.dm-pin-drop { display: block; filter: drop-shadow(0 1px 2px rgba(0,0,0,.35)); }
/* Farben als CSS-Regel, nicht nur als SVG-Attribut: var() in Präsentationsattributen greift nicht in jedem Browser (iOS). */
.dm-pin-drop path { fill: var(--route-pin-end); stroke: var(--route-pin-end-dark); }
.dm-pin-drop circle { fill: var(--route-pin-end-dark); }
.dm-pin .dm-label { left: 22px; top: -2px; }
.dm-pin-end .dm-label, .dm-pin-place .dm-label { left: 31px; top: 4px; }

/* Marker: farbiger Punkt + Kennzeichen-Schild. dispatchMap.js setzt die Klasse
   .dm-marker auf den Inhalt des AdvancedMarkerElement; die Farbe hängt am
   Zustand (moving/parked/stale). */
/* AdvancedMarkerElement setzt die Unterkante der Mitte auf die Koordinate;
   translateY(50%) schiebt den Punkt wieder in die Mitte. */
.dm-marker { position: relative; width: 14px; height: 14px; transform: translateY(50%); cursor: pointer; }
.dm-dot { position: absolute; left: 0; top: 0; width: 14px; height: 14px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,.35); background: var(--text-muted); }
.dm-moving .dm-dot { background: var(--badge-ok-dot); }
.dm-parked .dm-dot { background: var(--accent); }
.dm-stale .dm-dot { background: oklch(70% 0.01 243); }
.dm-label { position: absolute; left: 18px; top: -2px; white-space: nowrap; font: 600 11px/1.5 var(--font-sans); color: var(--text-primary); background: rgba(255,255,255,.95); border: none; border-radius: 6px; box-shadow: 0 1px 3px rgba(15,26,43,.28); padding: 0 6px; pointer-events: none; }
.dm-stale .dm-label { color: var(--text-muted); }
/* Fahrerfoto statt Punkt: Zustandsfarbe wandert auf den Ring. Das Bild kommt
   als Inline-background-image (schlägt die background-Kurzform oben), die
   Hintergrundfarbe bleibt als Ersatz, falls das Foto nicht lädt. */
.dm-marker.has-photo { width: 32px; height: 32px; }
.dm-dot.dm-photo { width: 32px; height: 32px; border-width: 3px; background-size: cover; background-position: center top; background-repeat: no-repeat; box-sizing: border-box; box-shadow: 0 1px 5px rgba(0,0,0,.45); }
.dm-moving .dm-photo { border-color: var(--badge-ok-dot); }
.dm-parked .dm-photo { border-color: var(--accent); }
.dm-stale .dm-photo { border-color: oklch(70% 0.01 243); filter: grayscale(1); }
.has-photo .dm-label { left: 36px; top: 7px; }
/* Zeile im Panel überfahren → Petrol-Ring am Marker (Zeile → Karte, kein Rückweg). */
.dm-marker.is-highlight .dm-dot { box-shadow: 0 0 0 4px color-mix(in srgb, var(--focus) 45%, transparent), 0 1px 5px rgba(0,0,0,.45); }
.dm-marker.is-highlight .dm-label { box-shadow: 0 0 0 2px color-mix(in srgb, var(--focus) 45%, transparent); }
/* Laufender Auftrag am Fahrzeug: kleines Navy-Rund mit Paket unten rechts. */
.dm-marker.is-loaded::after, .dm-loaded-dot { content: ""; width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid #fff; box-sizing: border-box; background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linejoin='round'%3E%3Cpath d='M3 8l9-5 9 5v8l-9 5-9-5z'/%3E%3Cpath d='M3 8l9 5 9-5M12 13v8'/%3E%3C/svg%3E") center / 7px no-repeat; }
.dm-marker.is-loaded::after { position: absolute; right: -6px; bottom: -6px; box-shadow: 0 1px 3px rgba(0,0,0,.4); }
.dm-marker.has-photo.is-loaded::after { right: -3px; bottom: -3px; width: 14px; height: 14px; background-size: 8px; }
.dm-loaded-dot { display: inline-block; flex: 0 0 auto; }
/* Marker-Popup: laufende Aufträge */
.dm-popup-jobs { margin-top: 8px; padding-top: 6px; border-top: 1px solid var(--border); display: grid; gap: 4px; }
.dm-popup-job { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.dm-popup-route { border: none; background: none; padding: 2px 0; font: 600 12.5px var(--font-sans); color: var(--route-line); cursor: pointer; white-space: nowrap; }
.dm-popup-route:hover { text-decoration: underline; }
/* Google-InfoWindow im App-Look. .gm-style begrenzt die Regel auf die Karte. */
.gm-style .gm-style-iw-d { font: 12.5px/1.5 var(--font-sans); color: var(--text-primary); }

/* ── Dispatch: Zeitleiste, Reiter, Blöcke ────────────────────────────── */
/* Eine Zeile: Tag/KW-Schalter, ‹ Label ›, Heute, Datumssymbol. Muss bei der
   schmalen Panel-Breite (392 px) ohne Umbruch passen — deshalb überall kleine,
   feste Maße statt Buttons aus dem allgemeinen .btn-Baukasten. */
.time-bar { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; width: 100%; }
/* Segmentierter Schalter (Mockup: graue Schiene, aktiv = weiß + Schatten) —
   eigene Klassen statt .filter-chip: der Look ist eine Schiene, keine Pille,
   und unterscheidet sich bewusst von den drei Reiter-Chips darüber. */
.dispatch-seg { display: inline-flex; flex: 0 0 auto; background: var(--surface-sunken); border-radius: 9px; padding: 2px; }
.dispatch-seg-btn { padding: 3px 10px; border: none; border-radius: 7px; background: none; color: var(--text-secondary); font: 500 12.5px/1.3 var(--font-sans); cursor: pointer; }
.dispatch-seg-btn.is-active { background: var(--card-bg); color: var(--text-primary); box-shadow: var(--shadow-xs); }
.time-bar-nav { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; min-width: 0; }
.time-bar-arrow { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border); background: var(--card-bg); color: var(--text-muted); font-size: 14px; line-height: 1; padding: 0; cursor: pointer; }
.time-bar-arrow:hover { background: var(--row-hover); color: var(--text-primary); }
.time-bar-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; font-weight: 600; font-size: 13px; }
.time-bar-today { flex: 0 0 auto; border: none; background: none; padding: 0; font: 500 13px/1.3 var(--font-sans); color: var(--focus); cursor: pointer; }
.time-bar-today:hover { text-decoration: underline; }
/* Datumsfeld bleibt ein echtes <input type="date"> (Tastatur/Screenreader),
   wird aber auf ein 26-px-Kalendersymbol geschrumpft: Text unsichtbar, das
   Kalender-Icon-Pseudoelement füllt und bedient den ganzen Knopf (Chromium-
   Trick). Ohne die WebKit-Selektoren (Firefox) bleibt das native Feld
   sichtbar — kein Darstellungsfehler, nur weniger kompakt. */
.time-bar-datepick { position: relative; flex: 0 0 auto; }
/* Rund-Icon-Trick ist reines WebKit/Blink (::-webkit-datetime-edit*,
   ::-webkit-calendar-picker-indicator). Firefox kennt diese Pseudo-Elemente
   nicht: Ohne dieses @supports-Gate würde es trotzdem Breite/Höhe/Radius/
   color:transparent übernehmen und nur einen leeren 26-px-Kreis ohne
   klickbares Icon zeigen (Datumstext unsichtbar, eigenes Kalender-Symbol aus
   der Box geschnitten) — nichts zum Anklicken. Firefox bekommt so stattdessen
   das normale, mit der Maus bedienbare Datumsfeld in Originalgröße. */
@supports selector(::-webkit-calendar-picker-indicator) {
  .time-bar-datepick { width: 26px; height: 26px; }
  /* Transparent statt card-bg: eine weiße Kreisfläche stach bisher aus dem
     Glas-Panel heraus (Live-Test 2026-09-19). Hover ist derselbe dezente
     Neutralton wie bei den Pfeil-Knöpfen direkt daneben (.time-bar-arrow). */
  .time-bar-datepick input[type="date"] { width: 100%; height: 100%; margin: 0; padding: 0; border: none; border-radius: 50%; background: transparent; color: transparent; font-size: 11px; cursor: pointer; }
  .time-bar-datepick input[type="date"]:hover { background: var(--row-hover); }
  .time-bar-datepick input[type="date"]::-webkit-datetime-edit,
  .time-bar-datepick input[type="date"]::-webkit-datetime-edit-fields-wrapper,
  .time-bar-datepick input[type="date"]::-webkit-datetime-edit-text,
  .time-bar-datepick input[type="date"]::-webkit-datetime-edit-month-field,
  .time-bar-datepick input[type="date"]::-webkit-datetime-edit-day-field,
  .time-bar-datepick input[type="date"]::-webkit-datetime-edit-year-field { display: none; }
  .time-bar-datepick input[type="date"]::-webkit-calendar-picker-indicator { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: .65; cursor: pointer; }
  .time-bar-datepick input[type="date"]::-webkit-inner-spin-button { display: none; }
}
.tab-count { margin-left: 5px; padding: 0 6px; border-radius: 9px; background: rgba(0,0,0,.08); font-size: 11px; }
.filter-chip.active .tab-count { background: rgba(255,255,255,.25); }
/* ── Dispatch: Seite und Job-Panel ───────────────────────────────────── */
/* Die Seite füllt den Inhaltsbereich ohne Innenabstand. :has statt einer
   Sonderregel im MainLayout — /dispatch ist die einzige Seite, die das will. */
.content:has(.dispatch-shell) { padding: 0; overflow: hidden; }
.dispatch-shell { position: relative; height: 100%; }
.dispatch-shell .dispatch-map-wrap { height: 100%; margin: 0; border: none; border-radius: 0; box-shadow: none; display: flex; flex-direction: column; }
.dispatch-shell .dispatch-map-area { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.dispatch-shell .dispatch-map-stage { flex: 1 1 auto; min-height: 0; }
.dispatch-shell .dispatch-map { height: 100%; min-height: 0; }

/* Panel links: halbtransparent, 12 px Abstand zu den Rändern. Die Zeilen
   werden beim Überfahren deckend weiß, damit der Text auch über Satellit
   lesbar bleibt. */
.dispatch-panel { position: absolute; left: 12px; top: 12px; bottom: 12px; z-index: 6; display: flex; flex-direction: column; background: var(--glass-bg); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4); border: 1px solid var(--glass-border); border-radius: 16px; box-shadow: var(--shadow-lg); transition: width .18s ease; }
.dispatch-panel.is-narrow { width: 392px; }
.dispatch-panel.is-wide { width: 760px; }
.dispatch-panel.is-collapsed { width: 0; border: none; box-shadow: none; background: none; backdrop-filter: none; -webkit-backdrop-filter: none; }
.dispatch-panel.is-collapsed > .dispatch-panel-head,
.dispatch-panel.is-collapsed > .dispatch-panel-list,
.dispatch-panel.is-collapsed > .dispatch-panel-foot { display: none; }

.dispatch-panel-head { padding: 12px 12px 10px; display: flex; flex-direction: column; gap: 10px; border-bottom: 1px solid var(--border); }
/* Die Suchpille bekommt seit Task 6 einen eigenen Rahmen über dem Sheet-Kopf
   (siehe DispatchPanel.razor) — auf dem Handy schwebt sie frei über der
   Karte, am PC steht sie einfach als eigene Zeile über den Reiter-Chips. */
.dispatch-panel-search { padding: 12px 12px 0; }
/* Breiter Zustand (Mockup „2 · Breit"): Suchpille und Zeitleiste auf einer
   Zeile, Reiter-Chips darunter — wie vor Task 6, nur dass die Suchpille jetzt
   ein eigenes Element neben .dispatch-panel-head ist (nicht mehr darin), weil
   sie auf dem Handy per position:fixed herausschweben muss. .dispatch-panel-head
   bekommt hier display:contents, damit Reiter-Chips und Zeitleiste als eigene
   Grid-Felder neben der Suchpille stehen — sein eigenes Padding/Border
   entfällt dadurch und wandert auf die drei Kinder. Ohne TimeBar (andere
   Reiter als Disposition) bleibt die "timebar"-Spalte einfach leer. */
/* Nur am PC: unter 700 px bedeutet .is-wide "Sheet voll" (siehe Media Query
   unten), dort ist die Suchpille ohnehin ausgeblendet und Reiter-Chips/
   Zeitleiste bleiben in der normalen (gestapelten) .dispatch-panel-head-Zeile
   — ein zweispaltiges Grid mit einer für die versteckte Suchpille reservierten
   Spalte hätte die Zeitleiste dort nur unnötig nach rechts gedrängt. */
@media (min-width: 700.01px) {
  .dispatch-panel.is-wide { display: grid; grid-template-columns: 1fr auto; grid-template-rows: auto auto minmax(0, 1fr) auto; grid-template-areas: "search timebar" "tabs tabs" "list list" "foot foot"; column-gap: 12px; }
  .dispatch-panel.is-wide > .dispatch-panel-search { grid-area: search; padding: 12px 0 10px 12px; align-self: center; }
  .dispatch-panel.is-wide > .dispatch-panel-head { display: contents; }
  .dispatch-panel.is-wide > .dispatch-panel-head > .time-bar { grid-area: timebar; width: auto; padding: 12px 12px 10px 0; align-self: center; }
  .dispatch-panel.is-wide > .dispatch-panel-head > .dispatch-tabs { grid-area: tabs; padding: 0 12px 10px; border-bottom: 1px solid var(--border); }
  .dispatch-panel.is-wide > .dispatch-panel-list { grid-area: list; }
  .dispatch-panel.is-wide > .dispatch-panel-foot { grid-area: foot; }
}
.dispatch-panel-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0 8px 8px; }
.dispatch-panel-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 8px 14px; font-size: 12px; color: var(--text-muted); border-top: 1px solid var(--border); background: rgba(255,255,255,.9); border-radius: 0 0 16px 16px; }
.dispatch-panel-foot a { color: var(--accent); text-decoration: none; }
.dispatch-panel-foot a:hover { text-decoration: underline; }

/* Griff am rechten Rand: schmal → breit → eingeklappt → schmal. Text statt
   bloßem Pfeil (Rückmeldung 2026-09-19: ein Symbol allein war nicht
   selbsterklärend) — die Beschriftung steht als lotrechter Text in der
   Pille, der Pfeil darüber. Pille ~26px breit, ~130px hoch, straddlt die
   Panel-Kante wie zuvor (right = -halbe Breite); eingeklappt (Panel-Breite 0)
   rückt sie ganz nach außen (right = -volle Breite). */
.dispatch-panel-handle { position: absolute; right: -15px; top: 50%; transform: translateY(-50%); width: 30px; height: 64px; padding: 0; z-index: 7; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; overflow: visible; border: 1px solid var(--border); border-radius: 13px; background: var(--card-bg); color: var(--text-muted); box-shadow: var(--shadow-md); cursor: pointer; }
.dispatch-panel-handle:hover { color: var(--text-primary); background: var(--row-hover); }
.dispatch-panel.is-collapsed .dispatch-panel-handle { right: -30px; }
.dispatch-panel-handle-chevron { font-size: 17px; font-weight: 600; line-height: 1; color: var(--accent); }
.dispatch-panel-handle-short { font-size: 11.5px; font-weight: 650; line-height: 1; color: var(--text-secondary); }
/* Desktop zeigt die Kurzform (Auf/Zu) waagerecht; der lange Text gehört dem Handy-Sheet. */
.dispatch-panel-handle-label { display: none; }

/* Die Suchpille zieht ins Panel: nicht mehr absolut auf der Karte. */
.dispatch-panel .map-search { position: static; width: auto; max-width: none; }
.dispatch-panel .map-search-field input { height: 44px; border-radius: 22px; padding: 0 34px 0 16px; }
.dispatch-panel .map-search-clear { top: 8px; right: 8px; }

/* Eingeklappter Zustand (Desktop), seit 2026-09-19 ohne Layout-Sprung: Das
   Panel behält seine schmale Breite und wird nur durchsichtig und
   klick-durchlässig; Kopf, Liste und Fuß gleiten nach links weg und blenden
   aus. Die Suchpille bleibt dadurch als normales Flex-Kind GENAU an ihrem
   Platz — sie verschwindet und springt nicht mehr, weder beim Zu- noch beim
   Aufklappen (vorher: Breite 0 + display:none + absolut positionierte Pille).
   visibility wird beim Ausblenden erst nach der Animation umgeschaltet, damit
   die versteckte Liste weder Klicks noch den Tab-Fokus fängt. Das Handy-Sheet
   (unter 700px) nutzt weiter die Grundregeln oben. */
@media (min-width: 700.01px) {
  .dispatch-panel { transition: width .22s ease, background-color .22s ease, border-color .22s ease, box-shadow .22s ease, backdrop-filter .22s ease, -webkit-backdrop-filter .22s ease; }
  .dispatch-panel.is-collapsed { width: 392px; border: 1px solid transparent; background: transparent; backdrop-filter: blur(0) saturate(1); -webkit-backdrop-filter: blur(0) saturate(1); pointer-events: none; }
  .dispatch-panel > .dispatch-panel-head,
  .dispatch-panel > .dispatch-panel-list,
  .dispatch-panel > .dispatch-panel-foot { transition: opacity .2s ease, transform .22s ease, visibility 0s; }
  .dispatch-panel.is-collapsed > .dispatch-panel-head,
  .dispatch-panel.is-collapsed > .dispatch-panel-foot { display: flex; }
  .dispatch-panel.is-collapsed > .dispatch-panel-list { display: block; }
  .dispatch-panel.is-collapsed > .dispatch-panel-head,
  .dispatch-panel.is-collapsed > .dispatch-panel-list,
  .dispatch-panel.is-collapsed > .dispatch-panel-foot { opacity: 0; transform: translateX(-28px); visibility: hidden; transition: opacity .18s ease, transform .22s ease, visibility 0s linear .22s; }
  .dispatch-panel.is-collapsed > .dispatch-panel-search .map-search,
  .dispatch-panel.is-collapsed > .dispatch-panel-handle { pointer-events: auto; }
  .dispatch-panel-handle { transition: right .22s ease, background-color .16s ease, color .16s ease; }
  .dispatch-panel.is-collapsed .dispatch-panel-handle { right: calc(100% - 30px); }
  .dispatch-shell .map-legend, .dispatch-shell .map-attribution, .dispatch-shell .map-route-credit, .dispatch-shell .map-route-summary { transition: left .22s ease; }
}
/* Schmal ↔ breit: Das Layout wechselt zwischen Flex-Spalte und Grid — das
   lässt sich nicht stufenlos überblenden. Die Suchpille steht in beiden
   Zuständen oben links und wächst mit der Panel-Breite mit, sie bleibt also
   ruhig. Alles, was den Platz wechselt (Reiter-Chips, Zeitleiste, ein- bzw.
   zweispaltige Liste), blendet stattdessen kurz neu ein, während das Panel
   seine Breite ändert. Zwei gleich aussehende Keyframes mit verschiedenen
   Namen: nur ein Namenswechsel startet eine CSS-Animation neu. */
@keyframes dispatch-settle-narrow { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@keyframes dispatch-settle-wide   { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (min-width: 700.01px) {
  .dispatch-panel.is-narrow .dispatch-tabs,
  .dispatch-panel.is-narrow .time-bar,
  .dispatch-panel.is-narrow .dispatch-rows { animation: dispatch-settle-narrow .24s ease .06s both; }
  .dispatch-panel.is-wide .dispatch-tabs,
  .dispatch-panel.is-wide .time-bar,
  .dispatch-panel.is-wide .dispatch-rows { animation: dispatch-settle-wide .24s ease .06s both; }
}
/* Weiche Übergänge für alle Bedienelemente der Dispatch-Seite (2026-09-19):
   Zustandswechsel an Knöpfen blenden über, neu erscheinende Flächen (Liste nach
   Reiter-/Tag-KW-/Datumswechsel, Werkzeug-Panel, Länderkarte, Suchtreffer)
   gleiten kurz ein. Verschwinden bleibt sofort — Blazor entfernt die Elemente
   aus dem DOM, und ein künstliches Warten würde die Bedienung nur träger machen. */
.dispatch-shell .filter-chip, .dispatch-shell .tab-count, .dispatch-seg-btn, .time-bar-arrow, .time-bar-today,
.map-tool-btn, .map-tool-btn svg, .map-zoom-btn, .map-fullscreen-btn, .map-layers-pin,
.map-layers-tile-thumb, .map-layers-tile-cap, .map-layers-square, .dj-row {
  transition: background-color .16s ease, color .16s ease, border-color .16s ease, box-shadow .16s ease, opacity .16s ease;
}
@keyframes dispatch-fade-down { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@keyframes dispatch-fade-up   { from { opacity: 0; transform: translateY(6px); }  to { opacity: 1; transform: none; } }
@keyframes dispatch-fade-left { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
.dispatch-list-view { animation: dispatch-fade-down .2s ease backwards; }
.dispatch-shell .cn-panel { animation: dispatch-fade-left .2s ease backwards; }
.map-layers-card:not([hidden]) { animation: dispatch-fade-up .16s ease backwards; }
.dispatch-shell .map-search-results { animation: dispatch-fade-down .14s ease backwards; }
@media (prefers-reduced-motion: reduce) {
  .dispatch-list-view, .dispatch-shell .cn-panel, .map-layers-card, .dispatch-shell .map-search-results, .dj-routeinfo-spinner { animation: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .dispatch-panel .dispatch-tabs, .dispatch-panel .time-bar, .dispatch-panel .dispatch-rows { animation: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .dispatch-panel, .dispatch-panel > *, .dispatch-shell .map-legend, .dispatch-shell .map-attribution, .dispatch-shell .map-route-credit, .dispatch-shell .map-route-summary { transition: none !important; }
}

.dispatch-tabs { display: flex; gap: 6px; flex-wrap: wrap; }

/* Überschriften bleiben beim Scrollen stehen. */
/* backdrop-filter fehlte bisher — var(--glass-bg) allein (84% Weiß) wirkte über
   den durchscrollenden Zeilen wie ein solider weißer Balken statt Glas (Live-
   Test 2026-09-19). Dieselbe Unschärfe wie das Panel selbst, damit Zeilen
   darunter unlesbar statt hart abgeschnitten wirken. */
.dispatch-section-title { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: 8px; padding: 10px 6px 6px; background: var(--glass-bg); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4); font-size: 12.5px; font-weight: 650; }
.dispatch-day-title { position: sticky; top: 30px; z-index: 1; padding: 6px 6px 4px; background: var(--glass-bg); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4); font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.dispatch-empty { padding: 10px 6px 14px; font-size: 13px; color: var(--badge-ok-text); }
.dispatch-rows { display: grid; grid-template-columns: 1fr; gap: 2px; margin-top: 4px; margin-bottom: 8px; }
/* Breiter Zustand: Zeilen zweispaltig je Abschnitt/Tag. */
.dispatch-panel.is-wide .dispatch-rows { grid-template-columns: 1fr 1fr; gap: 2px 8px; }

/* ── Dispatch: Job-Zeile ─────────────────────────────────────────────── */
/* Zwei Textzeilen statt einer Karte: bei 30+ Jobs muss die Liste scrollen
   können. Das Routen-Zeichen links trägt die Statusfarbe (currentColor). */
.dj-row { display: grid; grid-template-columns: 18px 1fr auto; gap: 0 10px; align-items: center; padding: 9px 10px 9px 8px; border-radius: 10px; cursor: pointer; }
.dj-row:hover, .dj-row:focus-within { background: var(--card-bg); box-shadow: var(--shadow-md); }
.dj-row.is-open { color: var(--badge-warning-dot); }
.dj-row.is-dispatched { color: var(--badge-ok-dot); }
.dj-row.is-overdue { color: var(--badge-expired-dot); }
.dj-row.is-selected { background: var(--card-bg); box-shadow: var(--shadow-md), inset 3px 0 0 var(--focus); }
.dj-route { grid-row: 1 / span 2; position: relative; width: 18px; height: 34px; }
.dj-route::before { content: ""; position: absolute; left: 8px; top: 6px; bottom: 6px; width: 2px; background: currentColor; opacity: .45; }
.dj-route i, .dj-route s { position: absolute; left: 4px; width: 10px; height: 10px; border-radius: 50%; border: 2.5px solid currentColor; background: var(--card-bg); }
.dj-route i { top: 0; }
.dj-route s { bottom: 0; background: currentColor; }
.dj-line1 { font-weight: 600; font-size: 14px; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dj-time { font-weight: 600; font-size: 13px; text-align: right; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.dj-line2 { grid-column: 2 / -1; font-size: 12.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dj-row.is-overdue .dj-line2 { color: var(--badge-expired-text); }
.dj-actions { grid-column: 2 / -1; grid-row: 3; display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 5px; min-width: 0; }
.dj-who { display: inline-flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden; }
.dj-buttons { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.dj-running { font-size: 12px; font-weight: 600; color: var(--badge-ok-text); background: var(--badge-ok-bg); border-radius: 999px; padding: 1px 8px; white-space: nowrap; }
.dj-driver { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dj-driver-photo { width: 18px; height: 18px; border-radius: 50%; background: var(--border-strong); background-size: cover; background-position: center top; flex: 0 0 auto; }
.dj-routeinfo { grid-column: 2 / -1; grid-row: 4; display: flex; align-items: center; gap: 8px; margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); font-size: 12.5px; font-weight: 600; color: var(--text-primary); }
.dj-routeinfo.is-error { color: var(--badge-expired-text); font-weight: 500; }
.dj-routeinfo-spinner { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--border-strong); border-top-color: var(--focus); animation: dj-spin .7s linear infinite; }
@keyframes dj-spin { to { transform: rotate(360deg); } }

/* Legende: unten, rechts neben dem Panel. Sie sitzt in .dispatch-map-stage,
   der Abstand folgt daher der Panel-Breite. bottom: 28px, nicht 12px — sonst
   deckt die Legende Googles eigenes Logo unten links ab (dieselbe 28-px-Regel
   wie beim Ebenen-Quadrat unten rechts, siehe .map-layers weiter oben; im
   Live-Betrieb 2026-09-19 beobachtet, verschärft durch die im eingeklappten
   Panel-Zustand jetzt frei schwebende Suchpille dort oben — unten war die
   Legende vorher schon zu nah dran). */
/* TRAGEND FÜR DIE NUTZUNGSBEDINGUNGEN: Der Selektor hängt an Googles Logo-Link
   (href beginnt mit https://maps.google.com/maps). Ändert Google das Markup,
   rutscht das Logo still wieder unter das Panel — nach Maps-Updates prüfen.
   Googles Logo sitzt fest unten links in der Karte — dort läge es unter dem
   Job-Panel. Die Nutzungsbedingungen verlangen ein sichtbares Logo, nicht
   diese Ecke: es rückt deshalb wie die Legende neben das Panel. */
@media (min-width: 700.01px) {
  .dispatch-shell .dispatch-map div:has(> a[href^="https://maps.google.com/maps"]) { left: 412px !important; }
  .dispatch-shell:has(.dispatch-panel.is-wide) .dispatch-map div:has(> a[href^="https://maps.google.com/maps"]) { left: 780px !important; }
  .dispatch-shell:has(.dispatch-panel.is-collapsed) .dispatch-map div:has(> a[href^="https://maps.google.com/maps"]) { left: 52px !important; }
}
.dispatch-shell .map-legend { left: 416px; bottom: 28px; max-width: calc(100% - 520px); }
.dispatch-shell:has(.dispatch-panel.is-wide) .map-legend { left: 784px; max-width: calc(100% - 888px); }
.dispatch-shell:has(.dispatch-panel.is-collapsed) .map-legend { left: 56px; max-width: calc(100% - 160px); }

/* PLZ-Quellenangabe (Lizenzpflicht, solange das Overlay an ist), ORS-Routen-
   Zuschreibung und die Auftragsroute-Karte folgen derselben Panel-Breite wie
   die Legende — sonst liegen sie auf dem Desktop unsichtbar unter dem
   Job-Panel. Alle drei stapeln sich mit demselben 34-px-Abstand, unten→oben
   Routen-Zuschreibung → PLZ-Zuschreibung → Auftragsroute-Karte, ab der
   28-px-Grundlinie der Legende statt der alten 12px. */
.dispatch-shell .map-route-credit { left: 416px; bottom: 62px; }
.dispatch-shell .map-attribution  { left: 416px; bottom: 96px; max-width: calc(100% - 520px); }
.dispatch-shell .map-route-summary { left: 416px; bottom: 140px; }
.dispatch-shell:has(.dispatch-panel.is-wide) .map-route-credit,
.dispatch-shell:has(.dispatch-panel.is-wide) .map-route-summary,
.dispatch-shell:has(.dispatch-panel.is-wide) .map-attribution { left: 784px; }
.dispatch-shell:has(.dispatch-panel.is-collapsed) .map-route-credit,
.dispatch-shell:has(.dispatch-panel.is-collapsed) .map-route-summary,
.dispatch-shell:has(.dispatch-panel.is-collapsed) .map-attribution { left: 56px; }

/* Werkzeuge oben rechts, waagerecht, links neben dem Vollbild-Knopf. Beschriftete
   Pillen mit fester Größe (siehe .map-tool-btn oben) — kein Hover-Aufklappen
   mehr. Unter 700 px werden aus den Pillen 40-px-Kreise mit nur dem Symbol,
   weil dort weniger Platz ist und es kein Hover gibt. */
.dispatch-shell .map-tools { top: 12px; left: auto; right: 60px; flex-direction: row; align-items: center; }
@media (max-width: 699px) {
  .dispatch-shell .map-tool-btn { width: 40px; padding: 0; justify-content: center; }
  .dispatch-shell .map-tool-label { display: none; }
}
/* Panel der Werkzeuge: endet über der Ecke unten rechts (Ebenen + Zoom). */
.dispatch-shell .cn-panel { top: 62px; bottom: 116px; } /* endet über dem angehobenen Zoom+Ebenen-Stapel, siehe .map-zoom/.map-layers oben */

.notice-warning { background: var(--badge-warning-bg); color: var(--badge-warning-text); border: 1px solid var(--badge-warning-dot); border-radius: 8px; padding: 10px 14px; font-size: 13px; margin-bottom: 14px; }

/* Responsive */
@media (max-width: 1100px) { .vehicle-grid { grid-template-columns: repeat(2,1fr); } }
@media (max-width: 1100px) { .employee-grid { grid-template-columns: repeat(3,1fr); } }
@media (max-width: 900px)  { .stat-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 700px) {
  /* Am Handy hat nur, wer kein Kachel-Startmenü sieht, noch eine Seitenleiste:
     owners und mechanic (Klasse has-mobile-sidebar am .app-shell). Für alle
     anderen ersetzt das Raster auf der Startseite die Navigation, und in der
     Topbar stehen Logo und Abmelden. */
  .sidebar { display: none; }
  .has-mobile-sidebar .sidebar {
    display: flex; position: fixed; top: 0; left: 0; bottom: 0;
    transform: translateX(-100%);
  }
  .has-mobile-sidebar .sidebar.open { transform: translateX(0); box-shadow: 8px 0 32px rgba(0,0,0,0.25); }
  .has-mobile-sidebar .sidebar-overlay.open { display: block; }
  .has-mobile-sidebar .hamburger { display: flex; }
  .topbar-home { display: flex !important; }
  .topbar-logout-form { display: flex !important; }
  .sidebar-toggle { display: none; }
  .topbar-role { display: none; }
  .content { padding: 16px; }
  .topbar { padding: 0 16px; }
  .page-title { font-size: 21px; }
  .desktop-only { display: none !important; }
  /* /dispatch auf dem Handy: das Panel wird zum Bottom Sheet mit drei
     Ruhehöhen (Apple HIG, „Sheets"): Spitze, halb, voll. Dieselben drei
     Klassen wie am PC, nur bedeuten sie hier Höhe statt Breite —
     is-collapsed = Spitze, is-narrow = halb, is-wide = voll. Gewischt wird mit
     dem Finger (dispatchSheet.js), getippt auf den Griffstreifen.

     Das Sheet ist IMMER so hoch wie im vollen Zustand; die kleineren Höhen
     entstehen dadurch, dass seine Unterkante unter den Bildschirmrand rutscht
     (--sheet-bottom, gesetzt von dispatchSheet.js). Dadurch bleibt der Inhalt
     beim Ziehen unverändert gesetzt — der Browser muss ihn nicht in jedem Bild
     neu umbrechen — und ein Wisch nach oben hat von Anfang an etwas zu zeigen.
     Ohne JS (Prerender, privates Fenster) greift --sheet-fallback, also genau
     die Höhe, die die Klasse meint.

     position: fixed statt absolute, weil das Sheet im vollen Zustand über die
     Topbar hinauswächst (so gewünscht: für die Navigation wischt man es
     herunter). z-index 90 hält es über der Topbar (die keinen hat) und unter
     Seitenleiste (100), deren Abdunkelung (99) und jedem Dialog (200). */
  .dispatch-panel {
    position: fixed; left: 0; right: 0; top: auto;
    bottom: var(--sheet-bottom, var(--sheet-fallback, calc(8px - 50dvh)));
    z-index: 90;
    width: auto !important;
    height: calc(100vh - 8px); height: calc(100dvh - 8px);
    background: none; backdrop-filter: none; -webkit-backdrop-filter: none;
    border-radius: 16px 16px 0 0; border-width: 1px 0 0;
    box-shadow: 0 -8px 30px rgba(8,22,56,.22);
    /* Einrasten wie bei iOS: schnell los, weich aus. */
    transition: bottom .32s cubic-bezier(.32, .72, 0, 1);
  }
  .dispatch-panel.is-wide { --sheet-fallback: 0px; }
  .dispatch-panel.is-narrow { --sheet-fallback: calc(8px - 50dvh); }
  .dispatch-panel.is-collapsed { --sheet-fallback: calc(112px - 100dvh); }
  /* Am Finger gibt es nichts zu animieren — das Sheet ist ja schon dort. */
  .dispatch-panel.is-sheet-dragging { transition: none; }
  /* Die Suchpille schwebt per position:fixed über der Karte (weiter unten) —
     ein Vorfahre mit backdrop-filter schränkt deren Fixed-Kontext auf die
     eigene Box ein (CSS: filter/backdrop-filter erzeugt ein Containing Block
     auch für fixed positionierte Nachfahren). Deshalb trägt hier nicht mehr
     .dispatch-panel selbst den Weichzeichner, sondern Kopf und Liste einzeln —
     optisch identisch, weil sie lückenlos aneinander anschließen; der Fuß hat
     ohnehin einen eigenen, deckenderen Hintergrund (siehe .dispatch-panel-foot
     oben). Ohne diesen Umbau läge die Suchpille bei „Spitze" unsichtbar unter
     dem unteren Bildschirmrand, weil sie dann relativ zur (dort nur 76 px
     hohen) Panel-Box statt zum Bildschirm positioniert würde. */
  .dispatch-panel > .dispatch-panel-head,
  .dispatch-panel > .dispatch-panel-list { background: var(--glass-bg); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4); }
  .dispatch-panel > .dispatch-panel-head { border-radius: 16px 16px 0 0; }
  /* Der Inhalt sieht in allen drei Höhen gleich aus — kleiner heißt nur
     „weniger davon zu sehen", nicht „anders gesetzt". Das ist der Grund, warum
     ein Sheet sich beim Ziehen ruhig anfühlt: Nichts springt, während es
     wandert. Oben bleibt Platz für den Griffstreifen (44px + Luft). */
  .dispatch-panel > .dispatch-panel-head { padding-top: 52px; }
  /* Am Desktop ist "eingeklappt" ein leeres Panel (Regel ganz oben blendet
     Kopf, Liste und Fuß aus). Am Handy heißt dieselbe Klasse "Spitze": Griff
     und Chips bleiben stehen, der Rest schaut unten aus dem Bild — deshalb
     hier wieder einschalten. */
  .dispatch-panel.is-collapsed > .dispatch-panel-head { display: flex; }
  .dispatch-panel.is-collapsed > .dispatch-panel-list { display: block; }
  /* Der Griffstreifen und die Kopfzeile sind die Ziehfläche: der Browser soll
     dort gar nicht erst selbst scrollen wollen. */
  .dispatch-panel > .dispatch-panel-head,
  .dispatch-panel-handle { touch-action: none; }
  /* Die Liste scrollt nur im vollen Zustand. In den beiden anderen Höhen zieht
     derselbe Wisch das Sheet weiter auf — sonst müsste der Finger erraten,
     welche der beiden Bewegungen gerade gemeint ist. Ganz oben angekommen,
     übergibt die Liste wieder ans Sheet (dispatchSheet.js). */
  .dispatch-panel-list { overscroll-behavior: contain; }
  .dispatch-panel:not(.is-wide) > .dispatch-panel-list { overflow: hidden; touch-action: none; }

  /* Suchpille schwebt über der Karte, nicht im Sheet. */
  .dispatch-panel-search { position: fixed; left: 12px; right: 12px; top: 68px; z-index: 8; padding: 0; }
  /* Ausgeblendet wird die Pille über html[data-sheet="wide"] weiter unten —
     das greift schon beim Wischen und blendet weich. */

  /* Griff: der graue Strich eines iOS-Sheets, ganz oben über die volle Breite.
     Kein Text mehr (bis 2026-09-19 stand „Aufklappen" darunter) — wer wischen
     kann, braucht ihn nicht, und ein Wort im Griff eines Sheets sieht nach
     Werkzeugleiste aus. Was ein Tippen tut, sagt das aria-label
     (DispatchPanelRules.SheetLabel). 44px hoch: Apples Mindestmaß für eine
     Fläche, die man mit dem Daumen trifft. */
  .dispatch-panel-handle { left: 0; right: 0; top: 0; width: auto; height: 44px; min-height: 0; padding: 0; transform: none; display: flex; align-items: center; justify-content: center; gap: 0; border: none; border-radius: 16px 16px 0 0; background: var(--glass-bg); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4); box-shadow: none; cursor: grab; -webkit-tap-highlight-color: transparent; }
  .dispatch-panel-handle:active { cursor: grabbing; }
  .dispatch-panel-handle::before { content: ""; width: 36px; height: 5px; border-radius: 3px; background: var(--border-strong); }
  .dispatch-panel-handle-chevron,
  .dispatch-panel-handle-short,
  .dispatch-panel-handle-label { display: none; }
  .dispatch-panel.is-collapsed .dispatch-panel-handle { right: 0; }

  /* Zeilen immer einspaltig, auch im Zustand "voll". */
  .dispatch-panel.is-wide .dispatch-rows { grid-template-columns: 1fr; }

  /* Fußzeile klebt am unteren Bildschirmrand statt am Sheet-Ende: im vollen
     Zustand fallen beide zusammen, in der halben Höhe läge das Sheet-Ende
     unter dem Bildschirmrand und die Zeile wäre weg. Dazu die
     Home-Indicator-Aussparung (Vorbild .license-flow-footer). In der Spitze
     ist kein Platz — dort gehört der Streifen Griff und Chips. Beim Ziehen
     blendet sie aus: sonst stünde sie schon über der Spitze, bevor das Sheet
     dort angekommen ist. */
  .dispatch-panel-foot { position: fixed; left: 0; right: 0; bottom: 0; border-radius: 0; padding-bottom: calc(8px + env(safe-area-inset-bottom)); transition: opacity .15s ease; }
  .dispatch-panel.is-collapsed > .dispatch-panel-foot { display: none; }
  .dispatch-panel.is-sheet-dragging > .dispatch-panel-foot { opacity: 0; pointer-events: none; }
  /* Platz für die Fußzeile, die als fixe Leiste über der Liste liegt. */
  .dispatch-panel-list { padding-bottom: calc(46px + env(safe-area-inset-bottom)); }

  /* Zoom-Knöpfe entfallen (Pinch), Ebenen sitzt über dem Sheet. Werkzeug-Knöpfe
     stehen auf dem Handy als Spalte rechts UNTER der Suchpille (nicht mehr in
     einer Reihe oben rechts) — dort lägen sie sonst über deren rechtem Ende
     (2026-09-19 vom Controller gemeldet). Der Vollbild-Knopf (JS-Control aus
     dispatchMap.js, landet in .dispatch-map-controls) rückt aus demselben
     Grund unter die beiden Werkzeug-Knöpfe, gleicher 8-px-Abstand: Suchpille
     endet bei 68+44=112px, +8 Werkzeuge (120), +40 Höhe je Knopf +8 Abstand
     ×2 = Vollbild bei 216px.
     Bei "voll" deckt das Sheet die ganze Fläche ab — Suchpille, Werkzeuge und
     Vollbild-Knopf haben dort nichts mehr zu bedienen und werden ausgeblendet;
     sie kommen zurück, sobald das Sheet wieder heruntergezogen ist. */
  .dispatch-shell .map-zoom { display: none; }

  /* ── Karten-Bedienelemente folgen der Sheet-Kante ──────────────────────
     Bis 2026-09-21 hingen sie an den Blazor-Klassen des Panels
     (:has(.dispatch-panel.is-narrow)) und wurden hart per display:none
     geschaltet. Beide Teile waren zu spät: Die Klasse wechselt erst, wenn der
     Server das Loslassen verarbeitet hat, und display kennt keinen Übergang —
     die Knöpfe „spawnten" also ruckartig, nachdem das Sheet längst stand
     (Rückmeldung 2026-09-21).
     Jetzt schreibt dispatchSheet.js in jedem Bild die sichtbare Sheet-Höhe als
     --sheet-visible und den gerundeten Zustand als data-sheet ans <html> —
     dasselbe Muster wie html.sidebar-collapsed in sidebar.js. Was unten sitzt,
     wandert dadurch mit dem Finger mit; was ein- oder ausblendet, tut das
     weich. */
  .dispatch-shell .map-tools,
  .dispatch-shell .map-fullscreen-btn,
  .dispatch-shell .map-layers,
  .dispatch-shell .map-legend,
  .dispatch-shell .map-route-credit,
  .dispatch-shell .map-route-summary,
  .dispatch-shell .map-attribution,
  .dispatch-shell .cn-panel,
  .dispatch-shell .dispatch-map div:has(> a[href^="https://maps.google.com/maps"]) {
    transition: bottom .32s cubic-bezier(.32, .72, 0, 1), opacity .2s ease, visibility 0s;
  }
  /* Am Finger: kein Übergang auf der Position, sonst hinkt sie hinterher. */
  html[data-sheet-dragging] .dispatch-shell .map-tools,
  html[data-sheet-dragging] .dispatch-shell .map-fullscreen-btn,
  html[data-sheet-dragging] .dispatch-shell .map-layers,
  html[data-sheet-dragging] .dispatch-shell .map-legend,
  html[data-sheet-dragging] .dispatch-shell .map-route-credit,
  html[data-sheet-dragging] .dispatch-shell .map-attribution,
  html[data-sheet-dragging] .dispatch-shell .cn-panel,
  html[data-sheet-dragging] .dispatch-shell .dispatch-map div:has(> a[href^="https://maps.google.com/maps"]) {
    transition: opacity .2s ease, visibility 0s;
  }
  /* Voll aufgezogen liegt die Karte vollständig unter dem Sheet: alles über
     ihr blendet aus (und ist nicht mehr per Tab erreichbar), statt zu
     verschwinden. */
  html[data-sheet="wide"] .dispatch-shell .map-tools,
  html[data-sheet="wide"] .dispatch-shell .map-fullscreen-btn,
  html[data-sheet="wide"] .dispatch-shell .map-layers,
  html[data-sheet="wide"] .dispatch-panel-search,
  html[data-sheet="narrow"] .dispatch-shell .map-legend,
  html[data-sheet="wide"] .dispatch-shell .map-legend,
  html[data-sheet="narrow"] .dispatch-shell .map-route-credit,
  html[data-sheet="wide"] .dispatch-shell .map-route-credit,
  html[data-sheet="narrow"] .dispatch-shell .map-attribution,
  html[data-sheet="wide"] .dispatch-shell .map-attribution {
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity .2s ease, visibility 0s linear .2s;
  }
  .dispatch-panel-search { transition: opacity .2s ease, visibility 0s; }
  /* Alles, was knapp über dem Sheet sitzt, rechnet ab --sheet-visible, der
     laufenden Sheet-Höhe; --sheet-peek (gemessene Spitzenhöhe) ist der Wert
     vor dem ersten Bild, 96px der Notnagel ohne JS. Vorher stand dieselbe Zahl
     hier fünfmal fest verdrahtet und ging jedes Mal daneben, wenn der
     Griffstreifen wuchs.
     Ebenen-Knopf: Sheet-Kante + 12px Abstand wie die Legende darunter,
     obendrauf 16px Luft zu Googles eigener Attributionszeile (dieselbe
     Google-Nutzungsbedingung wie am Desktop, siehe .map-layers oben) +
     Safe-Area. Er wandert jetzt mit und bleibt damit auch auf halber Höhe
     erreichbar — vorher war er dort ausgeblendet. */
  .dispatch-shell .map-layers { bottom: calc(var(--sheet-visible, var(--sheet-peek, 96px)) + 28px + env(safe-area-inset-bottom)); }
  .dispatch-shell .map-tools { top: 120px; right: 12px; left: auto; flex-direction: column; align-items: flex-end; }
  .dispatch-shell .map-fullscreen-btn { top: 216px; }
  /* Legende und die beiden Quellenangaben bleiben der Spitze vorbehalten: auf
     halber Höhe stapelten sie sich auf dem letzten Rest Karte. Sie blenden aus
     (s. o.), statt zu verschwinden. */
  /* Googles Logo läge unten links unter dem Sheet. Es rückt nach rechts in
     die freie Fläche unter dem Ebenen-Quadrat (Spitze) bzw. knapp über das
     halbhohe Sheet — sichtbar bleiben ist Pflicht (Nutzungsbedingungen). */
  .dispatch-shell .dispatch-map div:has(> a[href^="https://maps.google.com/maps"]) { left: auto !important; right: 12px !important; bottom: calc(var(--sheet-visible, var(--sheet-peek, 96px)) + 4px + env(safe-area-inset-bottom)) !important; }
  /* Bei halber Höhe knapp über die Sheet-Kante. In dvh gerechnet, nicht in
     Prozent: Prozent bezieht sich auf die Kartenfläche, die oben an der Topbar
     beginnt — das Logo landete damit rund 28px zu tief, also hinter dem Sheet
     (der Grund, warum es auf dem Handy nie zu sehen war). */

  .dispatch-shell .map-legend { left: 12px !important; bottom: calc(var(--sheet-visible, var(--sheet-peek, 96px)) + 12px); max-width: calc(100% - 110px) !important; }
  /* Quellenangabe des PLZ-Overlays und die Routen-Zuschreibung ebenfalls über
     das Sheet heben, beide nur in der Spitze — sonst schwebten sie über
     halb/voll geöffnetem Sheet. Route-Credit sitzt näher am Rand als die
     Attribution, wie am Desktop (44px vs. 78px dort), deshalb der gleiche
     34px-Abstand hier. */
  .dispatch-shell .map-route-credit { bottom: calc(var(--sheet-visible, var(--sheet-peek, 96px)) + 12px + env(safe-area-inset-bottom)); }
  .dispatch-shell .map-attribution { bottom: calc(var(--sheet-visible, var(--sheet-peek, 96px)) + 46px + env(safe-area-inset-bottom)); max-width: calc(100% - 110px); }
  /* Die Auftragsroute-Karte hängt NICHT am Sheet (folgt ihm also nicht wie
     Legende/Zuschreibungen): fest oben auf der Karte, unter der Suchpille
     (endet bei 68+44=112px) und LINKS neben der Werkzeug-Spalte (right: 64px
     lässt die 40-px-Kreise frei). Sichtbar in „Spitze" und „halb"; bei „voll"
     deckt das Sheet sie ab — dort steht dieselbe Zusammenfassung in der
     ausgewählten Zeile, und eine neue Route holt das Sheet ohnehin auf „halb"
     (DispatchPanel.ShowMapAsync). Der ✕-Knopf wird auf 32px vergrößert. */
  .dispatch-shell .map-route-summary { left: 12px !important; right: 64px; top: 116px; bottom: auto; max-width: none; }
  .dispatch-shell .map-route-summary button { width: 32px; height: 32px; }
  /* Werkzeug-Panel steht auf dem Handy über dem Sheet statt darunter. */
  .dispatch-shell .cn-panel { position: absolute; left: 12px; right: 12px; top: 116px; bottom: calc(var(--sheet-visible, var(--sheet-peek, 96px)) + 12px); width: auto; max-width: none; border-radius: var(--radius); border-width: 1px; box-shadow: var(--shadow-lg); }
  .dispatch-shell .cn-panel-body { overflow-y: auto; }

  /* Zeitraum-Leiste auf dem Handy: Zeile 1 = Tag/KW … Heute … Datumssymbol,
     Zeile 2 = ‹ Datum › in voller Breite. Das Symbol (26×26px) passt neben
     Tag/KW/Heute noch bequem in Zeile 1 (2026-09-19 auf Wunsch des Controllers
     wieder eingeblendet — vorher ganz ausgeblendet); .time-bar-nav bekommt als
     einziges Feld order:10 und flex-basis:100%, das reicht, um nur die Zeile
     mit ‹ Label › in eine eigene Reihe zu zwingen. */
  .time-bar { width: 100%; flex-wrap: wrap; }
  .time-bar-nav { order: 10; flex: 1 1 100%; }
  .mobile-only { display: block !important; }
  .stat-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .vehicle-grid { grid-template-columns: 1fr 1fr; gap: 10px; padding: 10px; }
  .employee-grid { grid-template-columns: repeat(3,1fr); gap: 10px; padding: 10px; }
  .login-left { display: none; }
  .login-right { padding: 24px; }
  .modal-overlay { padding: 10px; }
  /* Sicherheitsnetz: Dialoge dürfen auf dem Handy nie seitlich scrollen (nur hier, am Desktop haben
     Prüftabellen im Rechnungstool keinen eigenen Scroll-Rahmen und würden abgeschnitten). */
  .modal-body { overflow-x: hidden; }
  .form-row { grid-template-columns: 1fr; }
  .modal-footer { flex-wrap: wrap; }
  .modal-footer .btn { flex: 1 1 auto; justify-content: center; }
  .modal-footer-spacer { flex-basis: 100%; }
  .vehicle-picker { height: calc(100dvh - 20px); max-height: none; }
  .vehicle-picker-list { max-height: none; flex: 1; }
  .alert-row { flex-wrap: wrap; }
  .alert-row .btn { flex: 1 1 100%; justify-content: center; min-height: 40px; }
  .recent-row { flex-wrap: wrap; }
  .recent-row-plate { min-width: 0; }
}
@media (max-width: 480px) { .vehicle-grid { grid-template-columns: 1fr; } }
@media (max-width: 480px) { .employee-grid { grid-template-columns: repeat(2,1fr); } }

#blazor-error-ui {
  color-scheme: light only;
  background: lightyellow;
  bottom: 0;
  box-shadow: 0 -1px 2px rgba(0,0,0,0.2);
  box-sizing: border-box;
  display: none;
  left: 0;
  padding: 0.6rem 1.25rem 0.7rem;
  position: fixed;
  width: 100%;
  z-index: 1000;
}
#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: 0.75rem;
  top: 0.5rem;
}

/* ── Aufträge (/auftraege) ─────────────────────────────────────────────── */
.filter-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.filter-chip { height: 32px; padding: 0 12px; border-radius: 99px; border: 1px solid var(--border-strong); background: var(--card-bg); color: var(--text-secondary); font-family: inherit; font-size: 13px; font-weight: 550; cursor: pointer; transition: background 0.13s, color 0.13s, border-color 0.13s; }
.filter-chip:hover { color: var(--text-primary); background: var(--row-hover); }
.filter-chip.active, .filter-chip.active:hover { background: var(--accent); border-color: var(--accent); color: white; }

.shipment-list { display: flex; flex-direction: column; gap: 12px; padding: 16px; }
.shipment-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); cursor: pointer; box-shadow: var(--shadow-xs); transition: box-shadow 0.18s, border-color 0.18s; }
.shipment-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.shipment-card-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.shipment-customer { font-weight: 650; font-size: 14px; }
.shipment-reference { font-size: 14px; color: var(--text-primary); }
.shipment-created { margin-left: auto; font-size: 12.5px; color: var(--text-muted); }

.job-row { display: grid; grid-template-columns: 90px 1.4fr 1.2fr 1fr auto 120px; gap: 10px; align-items: center; padding: 10px 16px; font-size: 13px; border-bottom: 1px solid var(--border); }
.job-row:last-child { border-bottom: none; }
.job-route { font-weight: 500; }
.job-dates, .job-meta, .job-driver { color: var(--text-muted); }

.job-block { border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; }
.job-block-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.job-block-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }

/* Datei-Ablagefläche: das <input type="file"> liegt unsichtbar über der ganzen
   Fläche (opacity 0, nicht display:none — sonst nimmt es weder Klick noch Drop an). */
.file-drop-zone { position: relative; margin-top: 8px; padding: 14px 12px; border: 1.5px dashed var(--border); border-radius: 8px; background: var(--content-bg); color: var(--text-muted); text-align: center; transition: border-color 0.15s, background 0.15s, color 0.15s; }
.file-drop-zone input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; z-index: 1; }
.file-drop-zone:hover, .file-drop-zone:focus-within { border-color: var(--accent); color: var(--accent); }
.file-drop-zone.is-dragover { border-color: var(--accent); border-style: solid; background: color-mix(in oklch, var(--accent) 8%, var(--card-bg)); color: var(--accent); }
.file-drop-zone.is-disabled { opacity: 0.6; }
.file-drop-zone.is-disabled input[type="file"] { cursor: progress; }
.file-drop-zone-icon { display: block; margin: 0 auto 4px; }
.file-drop-zone-title { font-size: 12.5px; font-weight: 500; color: var(--text-primary); }
.file-drop-zone-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.file-drop-zone-hint { font-size: 11px; margin-top: 2px; }
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; font-size: 14px; }
.detail-label { font-size: 12.5px; font-weight: 500; color: var(--text-muted); }

.badge-muted { background: var(--border); color: var(--text-muted); }
.badge-muted .badge-dot { background: var(--text-muted); }

.job-form { padding: 4px 14px 14px; display: flex; flex-direction: column; gap: 10px; }

/* Job-Akkordeon im Auftragsdialog: eine Zeile je Job-Typ, Formular klappt darunter auf.
   Animiert wird grid-template-rows 0fr ↔ 1fr (height: auto lässt sich nicht animieren).
   Zugeklappt bleibt der Body im DOM, ist aber visibility: hidden — sonst landet man per
   Tab in unsichtbaren Feldern. Beim Zuklappen schaltet visibility erst nach der Animation um. */
/* flex-shrink: 0 ist Pflicht: .modal-body ist eine Flex-Spalte, und wegen overflow: hidden
   dürfte das Akkordeon sonst schrumpfen — es würde auf Dialoghöhe gequetscht statt zu scrollen,
   und ein zweiter aufgeklappter Job drückt den ersten scheinbar zu. */
.job-accordion { flex-shrink: 0; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.job-accordion-item + .job-accordion-item { border-top: 1px solid var(--border); }
.job-accordion-head { display: flex; align-items: center; gap: 10px; padding: 0 14px; transition: background 0.15s; }
.job-accordion-item.open .job-accordion-head { background: var(--row-hover); }
.job-accordion-head input[type="checkbox"] { width: 16px; height: 16px; flex-shrink: 0; accent-color: var(--accent); cursor: pointer; }
.job-accordion-toggle { flex: 1; min-width: 0; min-height: 44px; display: flex; align-items: center; gap: 10px; padding: 0; background: none; border: none; font: inherit; color: inherit; text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.job-accordion-title { font-size: 13px; font-weight: 600; white-space: nowrap; }
.job-accordion-toggle:hover .job-accordion-title { color: var(--accent); }
.job-accordion-summary { flex: 1; min-width: 0; font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.job-accordion-chevron { margin-left: auto; flex-shrink: 0; color: var(--text-muted); transform: rotate(-90deg); transition: transform 0.22s ease; }
.job-accordion-item.open .job-accordion-chevron { transform: rotate(0deg); }
.job-accordion-alert { padding: 0 14px 12px; }
.job-accordion-alert .alert-banner { margin-bottom: 0; }
.job-accordion-body { display: grid; grid-template-rows: 0fr; visibility: hidden; transition: grid-template-rows 0.22s ease, visibility 0s linear 0.22s; }
.job-accordion-item.open .job-accordion-body { grid-template-rows: 1fr; visibility: visible; transition: grid-template-rows 0.22s ease, visibility 0s; animation: job-accordion-open 0.22s ease; }
.job-accordion-body-inner { min-height: 0; overflow: hidden; }
/* Frisch angehakt kommt der Body schon "offen" ins DOM — ohne Keyframe gäbe es keinen Übergang. */
@keyframes job-accordion-open { from { grid-template-rows: 0fr; } }
@media (prefers-reduced-motion: reduce) {
    .job-accordion-body, .job-accordion-item.open .job-accordion-body, .job-accordion-chevron { transition: none; animation: none; }
}
.check-hint { font-size: 12px; margin-top: 4px; color: var(--text-muted); }
.check-hint.warning { color: var(--badge-warning-text); }

@media (max-width: 700px) {
    .job-row { grid-template-columns: 1fr 1fr; }
    .detail-grid { grid-template-columns: 1fr; }
}

/* ── Urlaubsverwaltung ─────────────────────────────────────────────────── */
.num-negative { color: var(--badge-expired-text); font-weight: 600; }
.num-cell { font-variant-numeric: tabular-nums; text-align: right; }
.table-container th.num-cell { text-align: right; }
.hint-row { display: flex; gap: 8px; align-items: flex-start; font-size: 12.5px; padding: 8px 10px; border-radius: 6px; background: var(--badge-warning-bg); color: var(--badge-warning-text); }
.hint-row.info { background: var(--badge-ok-bg); color: var(--badge-ok-text); }
.link-button { background: none; border: none; padding: 0; font: inherit; font-size: 12px; color: var(--accent); cursor: pointer; text-decoration: underline; align-self: flex-start; }
.year-select { height: 36px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--card-bg); color: var(--text-primary); font-family: inherit; font-size: 13px; font-weight: 600; padding: 0 8px; }
.row-clickable { cursor: pointer; }

/* Kalender-Monatsmatrix (UrlaubKalender.razor) */
.vacation-calendar { overflow-x: auto; }
.vacation-calendar table { border-collapse: collapse; font-size: 12px; }
.vacation-calendar th, .vacation-calendar td { border: 1px solid var(--border); padding: 0; height: 30px; }
/* Tagesspalten ohne feste Breite: Die Tabelle ist 100 % breit (.table-container), und der
   Platz, den die Namensspalte nicht braucht, verteilt sich auf die Tage. */
.vacation-calendar th.day { min-width: 26px; text-align: center; font-weight: 600; color: var(--text-muted); font-size: 11.5px; padding: 3px 0; }
.vacation-calendar th.day small { display: block; font-weight: 400; font-size: 10px; }
/* Pers.-Nr. und Name bleiben beim seitlichen Scrollen stehen. Zwei Sticky-Spalten brauchen
   eine feste Breite der ersten, sonst stimmt der left-Versatz der zweiten nicht — deshalb steht
   die gleich lange Personalnummer vorn und der Name rückt um genau ihre Breite ein. */
.vacation-calendar th.pnr, .vacation-calendar td.pnr { position: sticky; left: 0; background: var(--card-bg); text-align: left; padding: 0 10px; white-space: nowrap; width: 76px; min-width: 76px; max-width: 76px; overflow: hidden; text-overflow: ellipsis; z-index: 1; }
.vacation-calendar td.pnr { color: var(--text-muted); }
.vacation-calendar th.name, .vacation-calendar td.name { position: sticky; left: 76px; background: var(--card-bg); text-align: left; padding: 0 24px 0 10px; white-space: nowrap; width: 1%; z-index: 1; }
/* Handy: zwei feste Spalten ließen nur ~3 Tage sichtbar — Pers.-Nr. weg, Name rückt nach links. */
@media (max-width: 700px) {
    .vacation-calendar th.pnr, .vacation-calendar td.pnr { display: none; }
    .vacation-calendar th.name, .vacation-calendar td.name { left: 0; padding-right: 12px; }
}
.vacation-calendar .cal-off { background: var(--row-hover); }
.vacation-calendar .cal-cell { min-width: 26px; cursor: pointer; background: var(--cal-fill, var(--cal-color)); }
/* Die Zeilen-Hover-Regel der .table-container (tr:hover td) ist spezifischer als
   die Farbklassen und würde die Farbe beim Überfahren übermalen — hier gewinnt die Farbe. */
.vacation-calendar tbody tr:hover td.cal-cell { background: var(--cal-fill, var(--cal-color)); }
.vacation-calendar .cal-vacation { --cal-color: oklch(56% 0.18 145); }
.vacation-calendar .cal-sick { --cal-color: oklch(55% 0.22 25); }
.vacation-calendar .cal-unpaid { --cal-color: oklch(55% 0.02 250); }
.vacation-calendar .cal-special { --cal-color: oklch(55% 0.18 300); }
/* Blass nur den Hintergrund, nicht die Zelle: opacity würde auch den Heute-Rahmen ausbleichen. */
.vacation-calendar .cal-open { --cal-fill: color-mix(in oklch, var(--cal-color) 40%, transparent); }
/* Heute als durchgehende Spalte: jede Zelle zeichnet nur ihre Seitenlinien, die Kopfzelle
   oben, die letzte Zeile unten — zusammen ein Rahmen um die ganze Spalte. Rahmen statt
   box-shadow, weil bei border-collapse die breitere Linie gewinnt; die 1-px-Gitterlinien
   zwischen den Zeilen unterbrechen die Spalte so nicht. */
.vacation-calendar .cal-today { border-left: 2px solid var(--accent); border-right: 2px solid var(--accent); }
.vacation-calendar th.cal-today { border-top: 2px solid var(--accent); color: var(--accent); }
.vacation-calendar tbody tr:last-child .cal-today { border-bottom: 2px solid var(--accent); }
.vacation-calendar th.cal-today,
.vacation-calendar td.cal-today:not(.cal-cell) { background: color-mix(in oklch, var(--accent) 10%, var(--card-bg)); }
.calendar-toolbar { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.calendar-month { font-weight: 700; font-size: 14px; min-width: 150px; text-align: center; }
.calendar-legend { display: flex; gap: 12px; flex-wrap: wrap; font-size: 11.5px; color: var(--text-muted); margin-left: auto; }
.calendar-legend span::before { content: ""; display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 4px; vertical-align: -1px; background: var(--legend-color); }

/* ── Benutzerverwaltung ─────────────────────────────────────────────── */
.user-row { cursor: pointer; }
.user-row-disabled td { opacity: 0.55; }

/* Login-Art im Anlege-Dialog: zwei nebeneinander liegende Optionen */
.choice-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.choice-option { display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border: 1px solid var(--border-strong); border-radius: 10px; cursor: pointer; font-size: 13px; }
.choice-option.selected { border-color: var(--accent); background: var(--accent-soft); }
.choice-option input[type="radio"] { margin-top: 2px; accent-color: var(--accent); }
.choice-option small { display: block; color: var(--text-muted); font-size: 11.5px; margin-top: 2px; }
@media (max-width: 480px) { .choice-row { grid-template-columns: 1fr; } }

/* Passwortfeld mit Auge (wie .login-input-wrap, aber für .form-input im Dialog) */
.password-field { position: relative; }
.password-field .form-input { padding-right: 40px; }

/* Einmal angezeigtes Startpasswort */
.onetime-password { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border: 1px dashed var(--accent); border-radius: 8px; background: var(--row-hover); }
.onetime-password code { flex: 1; font-size: 16px; letter-spacing: 0.08em; word-break: break-all; }

.dialog-section-title { font-size: 14px; font-weight: 650; color: var(--text-primary); margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--border); }

/* ── Fehlerkasten (AppErrorBoundary, /Error) ───────────────── */
.error-boundary { background: var(--card-bg); border: 1px solid var(--badge-expired-dot); border-left-width: 4px; border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); padding: 18px 20px; max-width: 560px; margin: 24px auto; }
.error-boundary-title { font-size: 15px; font-weight: 700; margin-bottom: 6px; }
.error-boundary p { font-size: 13.5px; line-height: 1.5; margin: 0 0 8px; }
.error-boundary-id code { font-size: 14px; font-weight: 700; letter-spacing: 0.08em; font-variant-numeric: tabular-nums; }
.error-boundary-actions { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }

/* ── Dokumentlisten & Viewer (Components/Shared/DocumentList, DocumentViewerDialog,
   FileTypeIcon; Spec docs/superpowers/specs/2026-09-16-document-list-viewer-design.md) ── */
.doc-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.doc-row { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 10px; background: var(--card-bg); transition: border-color 0.15s, background 0.15s; }
.doc-row.is-clickable { cursor: pointer; }
.doc-row.is-clickable:hover, .doc-row.is-clickable:focus-visible { border-color: var(--border-strong); background: var(--row-hover); outline: none; }
.doc-main { flex: 1 1 auto; min-width: 0; }
.doc-name { font-size: 14px; font-weight: 500; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.doc-meta { font-size: 12.5px; color: var(--text-muted); margin-top: 1px; }
.doc-actions { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.doc-action { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 6px; background: none; color: var(--text-muted); cursor: pointer; font-family: inherit; }
.doc-action svg { width: 18px; height: 18px; }
.doc-action:hover { background: var(--border); color: var(--text-primary); }
.doc-action-danger:hover { background: var(--badge-expired-bg); color: var(--badge-expired-text); }
.doc-empty { font-size: 12.5px; color: var(--text-muted); margin-bottom: 8px; }
/* Kompakt (Tabellenzellen): kleine Zeilen nebeneinander, ohne Datum */
.doc-list-compact { flex-direction: row; flex-wrap: wrap; gap: 4px; margin-bottom: 0; }
.doc-list-compact .doc-row { min-height: 36px; padding: 3px 4px 3px 4px; gap: 6px; max-width: 260px; }
.doc-list-compact .doc-name { font-size: 12px; }
.doc-list-compact .doc-action { width: 28px; height: 28px; }
.doc-list-compact .doc-action svg { width: 16px; height: 16px; }

/* Typ-Icon: ein Seiten-Glyph, Farbe je Typ (oklch wie .btn-excel) */
.doc-icon { position: relative; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 36px; height: 36px; border-radius: 8px; }
.doc-icon svg { width: 22px; height: 22px; }
.doc-icon-label { position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%); font-size: 7px; font-weight: 800; letter-spacing: 0.04em; line-height: 1; padding: 1px 3px; border-radius: 2px; color: #fff; }
.doc-icon-pdf { color: oklch(52% 0.20 25); background: oklch(96% 0.03 25); }
.doc-icon-pdf .doc-icon-label { background: oklch(52% 0.20 25); }
.doc-icon-image { color: oklch(50% 0.13 200); background: oklch(96% 0.03 200); }
.doc-icon-image .doc-icon-label { background: oklch(50% 0.13 200); }
.doc-icon-word { color: oklch(48% 0.15 255); background: oklch(96% 0.03 255); }
.doc-icon-word .doc-icon-label { background: oklch(48% 0.15 255); }
.doc-icon-excel { color: oklch(42% 0.15 145); background: oklch(96% 0.03 145); }
.doc-icon-excel .doc-icon-label { background: oklch(42% 0.15 145); }
.doc-icon-other { color: var(--text-muted); background: var(--content-bg); }
.doc-icon-other .doc-icon-label { background: var(--text-muted); }
.doc-icon-sm { width: 28px; height: 28px; border-radius: 6px; }
.doc-icon-sm svg { width: 17px; height: 17px; }
.doc-icon-sm .doc-icon-label { font-size: 6px; bottom: 1px; }

/* Viewer: Vollbild über allen Dialogen (.modal-overlay ist 200) */
/* Viewer: abgedunkelte Fläche (schließt per Klick) + dunkle Karte in der Mitte;
   unter 700px füllt die Karte den Bildschirm. z-index 300 liegt über den
   Dialogen (200). Das Markup wird über SectionOutlet im MainLayout ausgegeben,
   also nie innerhalb eines .modal-body. */
.doc-viewer { position: fixed; inset: 0; z-index: 300; display: flex; align-items: center; justify-content: center; padding: 24px; background: rgba(0,0,0,0.6); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.doc-viewer-window { display: flex; flex-direction: column; width: 92%; max-width: 1100px; height: 90vh; height: 90dvh; border-radius: 10px; overflow: hidden; background: oklch(20% 0.02 243); color: #fff; box-shadow: 0 20px 60px rgba(0,0,0,0.45); cursor: auto; }
.doc-viewer-head { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: oklch(14% 0.02 243); border-bottom: 1px solid rgba(255,255,255,0.08); }
.doc-viewer-title { flex: 1 1 auto; min-width: 0; font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.doc-viewer-nav { display: flex; align-items: center; gap: 4px; }
.doc-viewer-counter { font-size: 12px; color: rgba(255,255,255,0.7); font-variant-numeric: tabular-nums; min-width: 44px; text-align: center; }
.doc-viewer-btn { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border: none; border-radius: 6px; background: none; color: #fff; cursor: pointer; font-family: inherit; }
.doc-viewer-btn svg { width: 20px; height: 20px; }
.doc-viewer-btn:hover:not(:disabled) { background: rgba(255,255,255,0.12); }
.doc-viewer-btn:disabled { opacity: 0.3; cursor: default; }
.doc-viewer-body { position: relative; flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.doc-viewer-frame { width: 100%; height: 100%; border: 0; background: #fff; cursor: auto; }
.doc-viewer-img { max-width: 100%; max-height: 100%; object-fit: contain; cursor: auto; }
.doc-viewer-none { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 24px; text-align: center; cursor: auto; }
.doc-viewer-none p { font-size: 13.5px; color: rgba(255,255,255,0.8); }
.doc-viewer-loading { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; background: oklch(20% 0.02 243); font-size: 12px; font-weight: 600; pointer-events: none; }
@media (max-width: 700px) {
  .doc-viewer { padding: 0; }
  .doc-viewer-window { width: 100%; max-width: none; height: 100vh; height: 100dvh; border-radius: 0; }
  .doc-viewer-head { padding: 6px 8px; gap: 6px; }
  .doc-viewer-counter { display: none; }
}

/* ── Kennzeichen ─────────────────────────────────────────────────────────
   Überall, wo ein echtes Fahrzeug-Kennzeichen steht (Fahrzeugkarte, Picker,
   Mechaniker-Dashboard, Detail-Popup), im Stil eines deutschen Schildes:
   weißes Feld, dunkler Rahmen, blauer EU-Streifen mit „D". Das Kennzeichen ist
   die wichtigste Kennung im Fuhrpark und in der Disposition — so erkennt man es
   auf einen Blick. Nur mit .plate, nie auf .alert-row-plate/.recent-row-plate
   selbst: diese Klassen tragen auf dem Büro-Dashboard auch Artikelnamen. */
.plate {
  display: inline-flex; align-items: center; gap: 7px;
  height: 26px; padding-right: 9px;
  background: #fff; color: #111;
  border: 1.5px solid #1a1a1a; border-radius: 5px; overflow: hidden;
  font-family: var(--font-sans); font-size: 14px; font-weight: 650; line-height: 1;
  letter-spacing: 0.06em; text-transform: uppercase; font-variant-numeric: tabular-nums;
  white-space: nowrap; flex-shrink: 0;
}
/* EU-Streifen: Sternenkranz als Ring (radial-gradient) über dem „D". */
.plate::before {
  content: "D"; align-self: stretch;
  display: flex; align-items: flex-end; justify-content: center;
  width: 13px; padding-bottom: 3px;
  background: radial-gradient(circle at 50% 32%, transparent 2.2px, #FFCC00 2.3px, #FFCC00 2.9px, transparent 3px), #1B44A6;
  color: #fff; font-size: 7.5px; font-weight: 700; letter-spacing: 0;
}
.plate-sm { height: 22px; font-size: 12.5px; gap: 6px; padding-right: 7px; }
.plate-sm::before { width: 11px; font-size: 6.5px; padding-bottom: 2px; }

/* ── Nachtrag aus dem Review vom 2026-09-19 ─────────────────────────────── */

/* iOS Safari zoomt in jedes fokussierte Eingabefeld unter 16px hinein und zoomt
   danach nicht von selbst zurück — auf dem Handy verrutschen dadurch Dialoge und
   das Dispatch-Sheet. Einzelne Felder hatten die 16px schon, die Grundklassen nicht. */
@media (pointer: coarse) {
    .form-input,
    .search-input,
    .inline-input,
    .year-select,
    .cn-place input,
    .cn-place select,
    .cn-panel select { font-size: 16px; }
}

/* Direkte Kinder von .modal-body mit overflow != visible verlieren ihre Mindesthöhe
   und werden auf Dialoghöhe gequetscht, statt den Body scrollen zu lassen (siehe
   CLAUDE.md "Dialoge"). Traf die Buchungshistorie: ab ~12 Buchungen waren die
   älteren Zeilen samt "Rückgängig" nicht mehr erreichbar. */
.modal-body > .table-container { flex-shrink: 0; }

/* Breite Tabellen in Dialogen dürfen waagerecht scrollen, statt rechts abgeschnitten
   zu werden (.modal-body versteckt overflow-x auf schmalen Geräten). */
.table-scroll { overflow-x: auto; }

/* ── Tracking-Links (Spec 2026-09-22) ──────────────────────────────────────
   Dialog aus dem Marker-Popup (/dispatch) und Zeile im Auftrags-Popup. Nur
   Layout — Farben, Radien und Schatten kommen aus den Tokens in :root. */

.tracking-link-field { display: flex; gap: 8px; align-items: center; margin-top: 4px; }
.tracking-link-field input {
    flex: 1 1 auto; min-width: 0; font-family: var(--font-sans); font-size: 13px;
    padding: 7px 10px; border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--surface-sunken); color: var(--text-primary);
}
.tracking-link-expiry { margin: 8px 0 0; font-size: 12.5px; color: var(--text-muted); }

.tracking-duration { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* Die gewählte Stufe hebt sich ab, ohne ein zweites Knopf-Aussehen zu erfinden. */
.tracking-duration .btn.is-selected {
    background: var(--accent); border-color: var(--accent); color: #fff;
}
.tracking-duration-custom {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 12.5px; color: var(--text-secondary);
}
.tracking-duration-custom input {
    width: 64px; font-family: var(--font-sans); font-size: 13px;
    padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius);
}

/* Zeile im Auftrags-Popup: Beschriftung, gekürzte URL, Knöpfe. */
.tracking-link-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 4px; }
.tracking-link-url {
    font-size: 12.5px; color: var(--text-secondary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}

/* ── Marken Auftragsbestätigung (Spec 2026-09-22) ─────────────────────────── */
/* Aufbau wie /dispatch: die Seite füllt den Inhaltsbereich ohne Innenabstand.
   Anders als dort liegt zwischen .content und der Hülle noch der
   desktop-only-Rahmen — der braucht die Höhe mit, sonst fällt .pruef-shell mit
   height:100% auf 0 zurück. Keine neuen Hex-Werte: alles aus :root. */
.content:has(.pruef-shell) { padding: 0; overflow: hidden; }
.content:has(.pruef-shell) > .desktop-only { height: 100%; }
.pruef-shell { height: 100%; display: grid; grid-template-columns: 392px minmax(0, 1fr); gap: 12px; padding: 12px; }

/* Panel links im Dispatch-Aufbau (Kopf, scrollende Liste, Fuß), aber als Karte
   statt Glasfläche: hier scheint keine Karte durch. */
.pruef-panel { min-height: 0; display: flex; flex-direction: column; background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); overflow: hidden; }
.pruef-panel-head { flex: 0 0 auto; padding: 12px; display: flex; flex-direction: column; gap: 10px; border-bottom: 1px solid var(--border); }
.pruef-panel-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0 8px 8px; }
.pruef-panel-foot { flex: 0 0 auto; display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 8px 12px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text-muted); }
.pruef-tabs { display: flex; gap: 6px; flex-wrap: wrap; }

/* Eigene Titelklassen: die .dispatch-*-title tragen Glas-Hintergrund. */
.pruef-section-title { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: 8px; padding: 10px 6px 6px; background: var(--card-bg); font-size: 12.5px; font-weight: 650; }
.pruef-day-title { position: sticky; top: 0; z-index: 1; padding: 8px 6px 4px; background: var(--card-bg); font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.pruef-empty { padding: 10px 6px 14px; font-size: 13px; color: var(--badge-ok-text); }
.pruef-rows { display: grid; grid-template-columns: 1fr; gap: 2px; margin-bottom: 8px; }

/* Zeile: Maße wie .dj-row. Der Punkt links trägt den Zustand — kein Badge. */
.pruef-row { display: grid; grid-template-columns: 14px 1fr auto; gap: 0 10px; align-items: center; padding: 9px 10px 9px 8px; border-radius: 10px; cursor: pointer; transition: background-color .16s ease, box-shadow .16s ease; }
.pruef-row:hover, .pruef-row:focus-within { background: var(--row-hover); }
.pruef-row.is-selected { background: var(--card-bg); box-shadow: var(--shadow-md), inset 3px 0 0 var(--focus); }
.pruef-dot { grid-row: 1 / span 2; width: 10px; height: 10px; border-radius: 50%; background: var(--border-strong); }
.pruef-row.is-open .pruef-dot { background: var(--badge-warning-dot); }
.pruef-row.is-checked .pruef-dot { background: var(--badge-ok-dot); }
.pruef-row-line1 { font-weight: 600; font-size: 14px; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pruef-row-date { font-weight: 600; font-size: 13px; text-align: right; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.pruef-row-line2 { grid-column: 2; font-size: 12.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pruef-row-count { grid-column: 3; font-size: 12.5px; font-weight: 600; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.pruef-row.is-muted .pruef-row-line1, .pruef-row.is-muted .pruef-row-date { color: var(--text-muted); }

/* Arbeitsbereich rechts. Gescrollt wird im Rahmen der Seite (.pruef-work);
   .pruef-main selbst bleibt overflow: visible — im v2-Popup ist es ein direktes
   Kind von .modal-body, und overflow != visible würde es dort auf Dialoghöhe
   quetschen (CLAUDE.md „Dialoge"). */
.pruef-work { min-height: 0; overflow-y: auto; padding-right: 4px; }
.pruef-main { display: flex; flex-direction: column; gap: 12px; }

/* Das einzige Textfeld im Ruhezustand — breit und groß, es wird hineingescannt. */
.pruef-hawb { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.pruef-hawb > .form-group { flex: 1 1 320px; }
.pruef-hawb-input { height: 52px; font-size: 22px; font-weight: 650; letter-spacing: .06em; font-variant-numeric: tabular-nums; }
.pruef-hawb > .pruef-leg { flex: 0 1 180px; }
.pruef-hint { font-size: 13px; color: var(--text-muted); }
.pruef-note { font-size: 12.5px; color: var(--text-muted); }
.pruef-warn { font-size: 12.5px; color: var(--badge-warning-text); background: var(--badge-warning-bg); border-radius: var(--radius); padding: 6px 10px; }

/* Prüfkarte */
.pruef-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.pruef-card-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.pruef-card-spacer { flex: 1 1 auto; }
.pruef-leg-number { font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pruef-card-route { font-size: 17px; font-weight: 600; }
.pruef-card-when { font-size: 15px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.pruef-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px 16px; font-size: 13px; }
.pruef-chips { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: 4px; }
.pruef-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 99px; border: 1px solid var(--border-strong); background: var(--card-bg); font-size: 13px; font-variant-numeric: tabular-nums; }
.pruef-chip.is-checked { background: var(--badge-ok-bg); border-color: var(--badge-ok-dot); color: var(--badge-ok-text); }
.pruef-chip.is-pending { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: 650; }
.pruef-chip-undo { border: none; background: none; padding: 0 0 0 2px; color: inherit; font: inherit; line-height: 1; cursor: pointer; opacity: .6; }
.pruef-chip-undo:hover { opacity: 1; }
.pruef-outcomes { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.pruef-outcome { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border-radius: var(--radius); border: 1px solid var(--border-strong); font-size: 13px; cursor: pointer; }
.pruef-outcome.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.pruef-stored { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; background: var(--surface-sunken); border-radius: var(--radius); padding: 8px 12px; font-size: 13px; }
.pruef-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* Rückfrage nach einem unscharfen Treffer: beide Schreibweisen untereinander. */
.pruef-compare { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; align-items: center; background: var(--surface-sunken); border-radius: var(--radius); padding: 10px 12px; }
.pruef-hawb-cmp { font-size: 17px; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: .04em; }
.pruef-diff { background: var(--badge-warning-bg); color: var(--badge-warning-text); border-radius: 3px; }
.pruef-ask { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; font-size: 13px; }

/* Auswahlliste: echte Knöpfe, damit Tab und Enter genügen. */
.pruef-cands { display: flex; flex-direction: column; gap: 6px; align-items: stretch; }
.pruef-cand { display: grid; grid-template-columns: auto 1fr auto; gap: 2px 12px; align-items: center; text-align: left; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--card-bg); font: inherit; color: var(--text-primary); cursor: pointer; }
.pruef-cand:hover { background: var(--row-hover); border-color: var(--border-strong); }
.pruef-cand-leg { grid-row: 1 / span 2; font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pruef-cand-hawb { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.pruef-cand-state { grid-column: 3; grid-row: 1 / span 2; }
.pruef-cand-meta { grid-column: 2; font-size: 12.5px; color: var(--text-muted); }

/* ── Rechnungserstellung v2 (Spec 2026-09-22) ─────────────────────────────── */
/* Normale Seite in voller Breite — 85 Zeilen passen in kein 392-px-Panel. Kopf
   in der Dispatch-Formensprache (.dispatch-seg, .time-bar, filter-chip), die
   Abschnitte sind gewöhnliche .table-container. */
.rv2-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.rv2-head .time-bar { width: auto; }
.rv2-summary { font-size: 13px; color: var(--text-muted); margin-bottom: 12px; }
.rv2-section { overflow: visible; }
.rv2-section-title { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 16px; border-bottom: 1px solid var(--border); }

/* ── Installationshinweis iPhone/iPad (InstallHint.razor) ──
   Unten über Safaris Werkzeugleiste, Abstand zur Home-Leiste über
   safe-area-inset. z-index 190: über der Vollbild-Karte (150), unter den
   Dialogen (200) — ein geöffneter Dialog verdeckt den Hinweis. */
.install-hint { position: fixed; left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 190; max-width: 480px; margin: 0 auto; display: flex; align-items: flex-start; gap: 12px; padding: 12px 10px 12px 12px; background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); font-size: 13.5px; line-height: 1.45; color: var(--text-secondary); }
.install-hint-icon { width: 40px; height: 40px; flex-shrink: 0; border-radius: 9px; }
.install-hint-text { flex: 1 1 auto; min-width: 0; }
.install-hint-title { font-size: 14px; font-weight: 650; color: var(--text-primary); margin-bottom: 2px; }
.install-hint-share { vertical-align: -3px; margin: 0 1px; color: var(--accent); }
.install-hint-close { flex-shrink: 0; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; background: none; border: none; border-radius: var(--radius); color: var(--text-muted); font-size: 15px; cursor: pointer; font-family: inherit; }
