/* ==========================================================================
   train-maxxing — Stylesheet

   Gestaltung: helles Glasmorphismus-Grundgerüst — weiße Panels mit
   dezenter Transparenz, dünne dunkelblaue Ränder, Sky/Violet/Emerald
   als Akzente, Outfit + JetBrains Mono; kombiniert mit der Informations-
   architektur des DB-Navigators (große Zeitangaben, Zuggattungs-Badges,
   Zeitachse im Detail, Verkehrsrot als Signalfarbe).

   Alles läuft über CSS-Variablen — zum Einbetten in die Website einfach
   :root nach dem Einbinden überschreiben.
   ========================================================================== */

:root {
  color-scheme: light;

  /* Flächen — hell mit dezenter Bläue, damit die Akzentfarben
     nicht auf sterilem Weiß liegen */
  --bg: #f5f7fb;
  --bg-deep: #e6ebf3;
  --surface: rgba(255, 255, 255, 0.78);
  --surface-solid: #ffffff;
  --surface-hover: rgba(255, 255, 255, 0.95);
  --surface-inset: rgba(15, 23, 42, 0.035);

  /* Eingabefelder brauchen einen DECKENDEN Grund. Eine halbtransparente
     Fläche über dem Glas-Panel ergibt je nach Untergrund unterschiedlichen
     Kontrast — und das native Aufklappmenü eines <select> malt seinen
     Hintergrund ohnehin selbst. Mit festen Werten ist das Paar aus Grund
     und Schrift in beiden Themes garantiert. */
  --field-bg: #ffffff;
  --field-bg-hover: #f8fafc;

  /* Anklickbare Flächen — Karten, Knöpfe, Panels. Ebenfalls deckend: über
     dem Glas-Panel und der Kartenkachel-Ebene ergibt eine halbtransparente
     Fläche je nach Untergrund einen anderen Kontrast, und genau daran sind
     die Eingabefelder schon gescheitert. Transparenz bleibt den rein
     dekorativen Containern (.panel, .map, .notice) vorbehalten. */
  --surface-card: #ffffff;
  --surface-card-hover: #f6f8fc;

  /* Ränder — Slate mit niedriger Deckkraft, sichtbar aber dezent */
  --border: rgba(15, 23, 42, 0.09);
  --border-strong: rgba(15, 23, 42, 0.18);

  /* Text — kräftige Slate-Töne für hohen Kontrast */
  --text: #0f172a;
  --text-dim: #475569;
  --text-muted: #64748b;

  /* Akzente — gegenüber dem Dark-Theme leicht abgedunkelt,
     damit sie auf hellem Grund sattigend wirken */
  --accent: #0284c7;
  --accent-soft: rgba(2, 132, 199, 0.11);
  --purple: #7c3aed;
  --purple-soft: rgba(124, 58, 237, 0.10);
  --green: #059669;
  --green-soft: rgba(5, 150, 105, 0.11);
  --amber: #b45309;
  --amber-soft: rgba(234, 179, 8, 0.15);
  --rose: #e11d48;
  --rose-soft: rgba(225, 29, 72, 0.10);

  /* Verkehrsrot — Signalfarbe für Fernverkehr, wie im DB-Navigator */
  --db-red: #dc2626;
  --db-red-soft: rgba(220, 38, 38, 0.11);

  /* Typografie */
  --font-main: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;

  /* Form */
  --radius: 12px;
  --radius-sm: 8px;
  --radius-xs: 4px;
  --blur: blur(12px);
  --glow-accent: 0 6px 22px rgba(2, 132, 199, 0.18);
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.05), 0 1px 3px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 4px 14px rgba(15, 23, 42, 0.08), 0 2px 4px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 14px 40px rgba(15, 23, 42, 0.14), 0 4px 12px rgba(15, 23, 42, 0.06);
  --transition: 160ms cubic-bezier(0.4, 0, 0.2, 1);

  /* Karten-Elemente, damit sie sich zwischen den Themes anpassen ohne
     Extra-Selektoren pro Regel schreiben zu müssen. */
  --map-line: #334155;
  --map-line-opacity: 0.55;
  --map-stop-fill: #ffffff;
  --map-stop-ring: #ffffff;
  --map-label: #0f172a;
  --map-label-halo: rgba(255, 255, 255, 0.92);
  --map-overlay-bg: #ffffff;
  --map-overlay-bg-soft: rgba(255, 255, 255, 0.85);
  --map-casing: rgba(255, 255, 255, 0.9);
  --calendar-icon-filter: none;

  /* Schiene der Schieberegler — kräftiger als --surface-inset, damit sie
     auf dem hellen Panel überhaupt sichtbar ist. */
  --slider-track: rgba(15, 23, 42, 0.13);
}

/* --- Dunkles Theme (per data-theme="dark" auf <html>) ------------------ */

[data-theme="dark"] {
  color-scheme: dark;

  --bg: #0a0e17;
  --bg-deep: #05070c;
  --surface: rgba(15, 20, 32, 0.72);
  --surface-solid: #0d1220;
  --surface-hover: rgba(28, 34, 52, 0.85);
  --surface-inset: rgba(255, 255, 255, 0.04);
  --field-bg: #141b2d;
  --field-bg-hover: #1b2438;
  --surface-card: #111827;
  --surface-card-hover: #182034;

  --border: rgba(255, 255, 255, 0.1);
  --border-strong: rgba(255, 255, 255, 0.18);

  --text: #f1f5f9;
  --text-dim: #cbd5e1;
  --text-muted: #94a3b8;

  --accent: #38bdf8;
  --accent-soft: rgba(56, 189, 248, 0.15);
  --purple: #c084fc;
  --purple-soft: rgba(192, 132, 252, 0.15);
  --green: #34d399;
  --green-soft: rgba(52, 211, 153, 0.14);
  --amber: #fbbf24;
  --amber-soft: rgba(251, 191, 36, 0.15);
  --rose: #fb7185;
  --rose-soft: rgba(251, 113, 133, 0.14);

  --db-red: #f87171;
  --db-red-soft: rgba(248, 113, 113, 0.16);

  --glow-accent: 0 0 25px rgba(56, 189, 248, 0.22);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 14px 40px rgba(0, 0, 0, 0.6), 0 4px 12px rgba(0, 0, 0, 0.35);

  --map-line: #94a3b8;
  --map-line-opacity: 0.45;
  --map-stop-fill: #030508;
  --map-stop-ring: #030508;
  --map-label: #e2e8f0;
  --map-label-halo: rgba(3, 5, 8, 0.9);
  --map-overlay-bg: #0b0d15;
  --map-overlay-bg-soft: rgba(3, 5, 8, 0.6);
  --map-casing: rgba(3, 5, 8, 0.9);
  --calendar-icon-filter: invert(0.7);

  --slider-track: rgba(255, 255, 255, 0.16);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-main);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

[data-theme="dark"] {
  --bg-glow-1: rgba(56, 189, 248, 0.08);
  --bg-glow-2: rgba(192, 132, 252, 0.06);
}

/*
 * Der Farbverlauf im Hintergrund liegt auf einer eigenen, fixierten Ebene
 * statt auf dem body.
 *
 * Vorher stand er per `background-attachment: fixed` direkt auf dem body —
 * das zwingt den Browser, bei JEDEM Scrollschritt den kompletten sichtbaren
 * Bereich neu zu zeichnen, inklusive beider Radialverläufe. Auf Rechnern
 * ohne GPU-Beschleunigung ist das der Hauptgrund für hakeliges Scrollen.
 *
 * Als eigenes fixiertes Pseudoelement bekommt der Verlauf eine eigene
 * Ebene: beim Scrollen wird nur noch verschoben, nicht neu gezeichnet.
 */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(1200px 700px at 12% -8%, var(--bg-glow-1, rgba(2, 132, 199, 0.10)), transparent 60%),
    radial-gradient(900px 520px at 88% 4%, var(--bg-glow-2, rgba(124, 58, 237, 0.07)), transparent 60%);
}

.wrap {
  max-width: 1000px;
  margin: 0 auto;
  padding: 2rem 1rem 5rem;
}

/* --- Kopf ---------------------------------------------------------- */

.page-head {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 1.5rem;
}

.page-head__title { min-width: 0; }

.back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 32px;
  margin-bottom: 0.35rem;
  padding: 0.2rem 0.6rem 0.2rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-inset);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  text-decoration: none;
  transition: var(--transition);
}

.back:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

.page-head h1 {
  margin: 0;
  font-size: 1.65rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.sub {
  margin: 0.35rem 0 0;
  color: var(--text-dim);
  font-size: 0.92rem;
  font-family: var(--font-mono);
  font-weight: 300;
}

.modes {
  display: flex;
  gap: 0.25rem;
  padding: 0.25rem;
  background: var(--surface-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.mode-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.05rem;
  padding: 0.45rem 0.9rem;
  border: 0;
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: var(--transition);
}

.mode-btn small {
  font-size: 0.66rem;
  font-weight: 300;
  opacity: 0.7;
}

.mode-btn:hover { color: var(--text-dim); }

.mode-btn.is-active {
  background: var(--surface-solid);
  color: var(--accent);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), inset 0 0 0 1px rgba(2, 132, 199, 0.25);
}

/* --- Theme-Umschalter ---------------------------------------------- */

.page-head__ctl {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Kreisförmiger Icon-Button neben den Modi. Zeigt die Sonne im Dunkeln
   (klick = wird hell) und den Mond im Hellen (klick = wird dunkel). */
.theme-toggle {
  --size: 40px;
  width: var(--size);
  height: var(--size);
  display: inline-grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-card);
  color: var(--text-dim);
  cursor: pointer;
  transition: var(--transition);
}

.theme-toggle:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

.theme-toggle__icon {
  width: 20px;
  height: 20px;
  display: block;
  background-color: currentColor;
  /* Mond-Icon (Standardzustand = helles Theme, Klick wechselt zu dunkel) */
  -webkit-mask: var(--icon-moon) center / contain no-repeat;
          mask: var(--icon-moon) center / contain no-repeat;
}

[data-theme="dark"] .theme-toggle__icon {
  /* Sonne im Dunkeln */
  -webkit-mask: var(--icon-sun) center / contain no-repeat;
          mask: var(--icon-sun) center / contain no-repeat;
}

/* Feather-Icons als data-URIs — kein Netzwerk-Fetch, kein Font.
   Wenn das Design mal wechselt: hier tauschen. */
:root {
  --icon-moon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'/></svg>");
  --icon-sun:  url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='4'/><path d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41'/></svg>");
}

/* --- Panels -------------------------------------------------------- */

/* backdrop-filter nur noch hier und auf .map: das sind die einzigen beiden
   Flächen, die wirklich halbtransparent sind. Auf allen anderen lag seit der
   Umstellung auf deckende Flächen ein unsichtbarer Blur — jeder davon kostet
   eine eigene Compositing-Ebene, bei .journey sogar eine pro Ergebniskarte.
   Auf älteren Rechnern ohne GPU-Beschleunigung war das der teuerste Posten
   der Seite. */
.panel {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  box-shadow: var(--shadow-md);
}

.row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: flex-end;
  margin-bottom: 0.9rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  position: relative;
  min-width: 0;
}

.field--grow { flex: 1 1 220px; }

/*
 * Die Optionszeile ist auf JEDER Breite ein Raster, nicht nur auf dem Telefon.
 *
 * Als Flexbox bestimmten die Feldinhalte die Breite — der längste Optionstext
 * zog sein Feld auf und schob die Nachbarn ineinander. Auf dem Telefon war
 * das behoben, auf dem iPad (768–1024 px) griff die Ausnahme nicht und der
 * Fehler war wieder da. Rasterzellen können sich grundsätzlich nicht
 * überlagern, egal wie lang ein Text wird; auto-fit wählt die Spaltenzahl
 * passend zur Breite.
 */
.row--options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
  align-items: end;
}

/* Umsteigezeit hat den längsten Text ("egal — kürzestmöglich") und bekommt
   deshalb zwei Spalten, solange welche da sind. */
.row--options .field--wide { grid-column: span 2; }
.field--check { justify-content: flex-end; padding-bottom: 0.5rem; }

label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

input[type="text"], input[type="date"], input[type="time"],
input[type="number"], select {
  width: 100%;
  min-width: 0;
  padding: 0.6rem 0.75rem;
  background: var(--field-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-main);
  font-size: 0.95rem;
  transition: var(--transition);
}

/* Das aufgeklappte Menü eines <select> wird vom System gezeichnet. Es erbt
   die Textfarbe vom Element, seinen Hintergrund malt es aber selbst — im
   dunklen Theme steht damit fast weißer Text auf einem hellen Menü und ist
   nicht lesbar. Beide Werte deshalb ausdrücklich setzen.
   color-scheme sorgt zusätzlich dafür, dass Scrollbalken und Rahmen des
   Menüs zum Theme passen. */
select { color-scheme: inherit; }

select option,
select optgroup {
  background-color: var(--field-bg);
  color: var(--text);
}

/* Auch die markierte Zeile muss deckend bleiben: eine transparente Tönung
   ließe den Grund des Systemmenüs wieder durchscheinen — genau der Fehler,
   den die Regeln darüber beheben. */
select option:checked {
  background-color: var(--field-bg-hover);
  font-weight: 500;
}

input::placeholder { color: var(--text-muted); }

input:hover, select:hover { border-color: var(--accent); background: var(--field-bg-hover); }

input:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Datums-/Zeit-Icons: im dunklen Theme invertiert, im hellen nur
   leicht abgedimmt — siehe --calendar-icon-filter. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  filter: var(--calendar-icon-filter);
  opacity: 0.65;
  cursor: pointer;
}

.check {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-main);
  font-size: 0.88rem;
  font-weight: 400;
  color: var(--text-dim);
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
  white-space: nowrap;
}

input[type="checkbox"] { accent-color: var(--accent); cursor: pointer; }

.swap {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  margin-bottom: 0.05rem;
  /* Auf dem Desktop stehen "Von" und "Nach" nebeneinander — der Pfeil muss
     also waagerecht zeigen. Auf dem Telefon stehen sie übereinander, dort
     wird die Drehung wieder aufgehoben. */
  transform: rotate(90deg);
  background: var(--surface-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  font-size: 1.05rem;
  cursor: pointer;
  transition: var(--transition);
}

.swap:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* --- Autocomplete -------------------------------------------------- */

.ac {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 60;
  margin: 0.3rem 0 0;
  padding: 0.25rem;
  list-style: none;
  max-height: 270px;
  overflow-y: auto;
  background: var(--surface-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}

.ac__item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius-xs);
  font-size: 0.92rem;
  cursor: pointer;
  transition: background var(--transition);
}

.ac__item:hover, .ac__item.is-active { background: var(--accent-soft); color: var(--accent); }

.ac__country {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  color: var(--text-muted);
  padding: 0.1rem 0.35rem;
  border: 1px solid var(--border);
  border-radius: 3px;
}

/* --- Ausklappbereiche ---------------------------------------------- */

.section {
  border-top: 1px solid var(--border);
  padding-top: 0.9rem;
  margin-top: 0.9rem;
}

.section > summary {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--text-dim);
  cursor: pointer;
  padding: 0.2rem 0;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  transition: color var(--transition);
}

.section > summary:hover { color: var(--accent); }

.hint {
  font-size: 0.83rem;
  color: var(--text-muted);
  margin: 0.5rem 0;
  line-height: 1.5;
}

.nerd-only { display: none; }
body[data-mode="nerd"] .nerd-only { display: block; }

/* --- Abos ---------------------------------------------------------- */

.abos { display: flex; flex-wrap: wrap; gap: 0.7rem; }

.abo-group {
  flex: 1 1 230px;
  margin: 0;
  padding: 0.6rem 0.8rem 0.7rem;
  background: var(--surface-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.abo-group legend {
  padding: 0 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.abo {
  display: flex;
  /* Ohne wrap sprengt die Notiz mit flex-basis:100% die Zeilenbreite
     und erzeugt einen horizontalen Überlauf der ganzen Seite. */
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  padding: 0.28rem 0;
  font-size: 0.9rem;
  color: var(--text-dim);
  cursor: pointer;
  transition: color var(--transition);
}

.abo:hover { color: var(--text); }

.abo__tag {
  margin-left: auto;
  padding: 0.08rem 0.35rem;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 500;
  white-space: nowrap;
}

.abo__tag--free { color: var(--green); background: var(--green-soft); }
.abo__tag--limited { color: var(--amber); background: var(--amber-soft); }
.abo__tag--real { color: var(--accent); background: var(--accent-soft); }

.abo__note {
  flex-basis: 100%;
  padding-left: 1.45rem;
  font-size: 0.74rem;
  color: var(--text-muted);
  line-height: 1.4;
}

/* --- Regler -------------------------------------------------------- */

.slider { margin: 1rem 0; }
.slider label { display: block; margin-bottom: 0.4rem; }

/*
 * Schieberegler komplett selbst gezeichnet.
 *
 * Mit bloßem `accent-color` zeichnet jedes Betriebssystem seinen eigenen
 * Regler — unter Windows einen flachen grauen Balken mit rechteckigem
 * Griff, der neben den runden Feldern und Knöpfen hier wie aus einem
 * anderen Programm aussieht. Ab hier gilt überall dasselbe: dünne
 * abgerundete Schiene, runder Griff in Akzentfarbe, Fokusring aus
 * derselben Variablen wie bei den Eingabefeldern.
 *
 * Die Regeln stehen doppelt, weil sich die Pseudo-Elemente von WebKit und
 * Firefox nicht in einer Selektorliste zusammenfassen lassen: ein
 * unbekannter Selektor macht bei beiden die ganze Regel ungültig.
 */
input[type="range"] {
  --track-h: 6px;
  --thumb: 18px;

  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  /* Die Höhe ist die Trefferfläche, nicht die Optik: die Schiene ist nur
     --track-h hoch und wird darin senkrecht zentriert. */
  height: 28px;
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
}

/* Schiene */
input[type="range"]::-webkit-slider-runnable-track {
  height: var(--track-h);
  border-radius: 999px;
  background: var(--slider-track);
}

input[type="range"]::-moz-range-track {
  height: var(--track-h);
  border-radius: 999px;
  background: var(--slider-track);
}

/* Griff */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: var(--thumb);
  height: var(--thumb);
  /* WebKit setzt den Griff auf die OBERKANTE der Schiene. Um die halbe
     Differenz nach oben geschoben liegt seine Mitte auf der Schiene. */
  margin-top: calc((var(--track-h) - var(--thumb)) / 2);
  border: 2px solid var(--accent);
  border-radius: 50%;
  background: var(--surface-solid);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition), border-color var(--transition);
}

input[type="range"]::-moz-range-thumb {
  width: var(--thumb);
  height: var(--thumb);
  border: 2px solid var(--accent);
  border-radius: 50%;
  background: var(--surface-solid);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition), border-color var(--transition);
}

/* Ein weicher Ring um den Griff statt des System-Fokusrahmens — dieselbe
   Sprache wie `input:focus` weiter oben. */
input[type="range"]:focus { outline: none; }

input[type="range"]:hover::-webkit-slider-thumb,
input[type="range"]:focus-visible::-webkit-slider-thumb,
input[type="range"]:active::-webkit-slider-thumb {
  box-shadow: 0 0 0 5px var(--accent-soft), var(--shadow-sm);
}

input[type="range"]:hover::-moz-range-thumb,
input[type="range"]:focus-visible::-moz-range-thumb,
input[type="range"]:active::-moz-range-thumb {
  box-shadow: 0 0 0 5px var(--accent-soft), var(--shadow-sm);
}

/* Firefox kann den zurückgelegten Teil der Schiene einfärben. WebKit kann
   das nicht, deshalb bleibt es ein Extra und keine tragende Information. */
input[type="range"]::-moz-range-progress {
  height: var(--track-h);
  border-radius: 999px;
  background: var(--accent);
}

/* Die Bewertungsregler laufen von -5 bis +5. Ein Strich in der Mitte zeigt,
   wo "egal" liegt — ohne ihn muss man den Griff hin und her schieben und
   die Beschriftung lesen, um die Null zu treffen. Der Regler für das Tempo
   unbenannter Strecken geht dagegen von 0 bis 5 und bekommt keinen. */
.model__ctl input[type="range"]::-webkit-slider-runnable-track {
  background:
    linear-gradient(var(--border-strong), var(--border-strong)) 50% / 2px 100% no-repeat,
    var(--slider-track);
}

.model__ctl input[type="range"]::-moz-range-track {
  background:
    linear-gradient(var(--border-strong), var(--border-strong)) 50% / 2px 100% no-repeat,
    var(--slider-track);
}

/* Bei bewerteten Strecken/Zügen wäre eine von links gefüllte Schiene
   irreführend — die Null liegt in der Mitte, nicht am Anfang. */
.model__ctl input[type="range"]::-moz-range-progress { background: transparent; }

.slider output {
  display: inline-block;
  margin-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--accent);
}

.slider .hint { margin-top: 0.25rem; }

/* --- Verkehrsmittel ------------------------------------------------- */

.products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 0.35rem;
  margin-bottom: 0.7rem;
}

.product {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 40px;
  padding: 0.3rem 0.5rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  color: var(--text-dim);
  cursor: pointer;
  transition: var(--transition);
}

.product:hover { background: var(--surface-inset); color: var(--text); }

.product__hint {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-muted);
  text-align: right;
}

/* --- Fahrzeugmodelle ------------------------------------------------ */

.models {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 0.7rem;
  margin: 0.8rem 0;
}

.model-group {
  margin: 0;
  padding: 0.5rem 0.75rem 0.7rem;
  background: var(--surface-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.model-group legend {
  padding: 0 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.model { padding: 0.4rem 0; }
.model + .model { border-top: 1px solid var(--border); }

.model__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
}

.model__name { font-size: 0.92rem; color: var(--text); }

.model__series {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-muted);
}

.model__tag {
  margin-left: auto;
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
  background: var(--green-soft);
  color: var(--green);
  font-family: var(--font-mono);
  font-size: 0.62rem;
}

.model__ctl {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.25rem;
}

.model__ctl input[type="range"] { flex: 1; }

.model__value {
  flex: 0 0 auto;
  min-width: 88px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-align: right;
  color: var(--text-muted);
}

.model__value[data-sign="plus"] { color: var(--green); }
.model__value[data-sign="minus"] { color: var(--rose); }

.model__note {
  margin: 0.2rem 0 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--text-muted);
}

/* --- Buttons ------------------------------------------------------- */

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
  margin-top: 1.1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

.btn {
  padding: 0.65rem 1.3rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.86rem;
  font-weight: 500;
  cursor: pointer;
  transition: var(--transition);
}

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
  box-shadow: 0 1px 2px rgba(2, 132, 199, 0.15), 0 4px 12px rgba(2, 132, 199, 0.20);
}

.btn--primary:hover {
  background: #0369a1;
  border-color: #0369a1;
  box-shadow: var(--glow-accent);
}

.btn--ghost {
  background: var(--surface-card);
  border-color: var(--border);
  color: var(--text-dim);
  font-size: 0.8rem;
  padding: 0.55rem 0.9rem;
}

.btn--ghost:hover { border-color: var(--border-strong); color: var(--text); }

button:focus-visible, a:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --- Status und Hinweise ------------------------------------------- */

.status { font-family: var(--font-mono); font-size: 0.82rem; color: var(--text-muted); }
.status--busy { color: var(--accent); }
.status--error { color: var(--rose); }

.notices { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 1rem; }

.notice {
  padding: 0.65rem 0.85rem;
  border-left: 2px solid var(--border-strong);
  border-radius: var(--radius-xs);
  background: var(--surface-inset);
  font-size: 0.84rem;
  color: var(--text-dim);
}

.notice--warn {
  border-left-color: var(--amber);
  background: var(--amber-soft);
  color: var(--amber);
}

/* --- Karte --------------------------------------------------------- */

.map-wrap { margin-top: 1rem; }

.map-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0 0.2rem 0.5rem;
}

/* --- Filtermenü für die Live-Züge ------------------------------------ */

.live-filter { position: relative; }

.live-filter__summary {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-card);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.live-filter__summary::-webkit-details-marker { display: none; }
.live-filter__summary::after { content: '▾'; opacity: 0.6; }
.live-filter[open] .live-filter__summary { border-color: var(--accent); color: var(--accent); }
.live-filter__summary:hover { border-color: var(--accent); }

.live-filter__body {
  position: absolute;
  top: calc(100% + 0.3rem);
  left: 0;
  z-index: 70;
  min-width: 200px;
  padding: 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-card);
  box-shadow: var(--shadow-lg);
}

.live-filter__presets {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  padding-bottom: 0.4rem;
  margin-bottom: 0.4rem;
  border-bottom: 1px solid var(--border);
}

.live-filter__preset {
  padding: 0.2rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  cursor: pointer;
}

.live-filter__preset:hover { border-color: var(--accent); color: var(--accent); }

.live-filter__list { display: flex; flex-direction: column; gap: 0.1rem; }

.live-filter__item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 30px;
  padding: 0 0.15rem;
  font-family: var(--font-main);
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--text-dim);
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}

@media (max-width: 640px) {
  /* Auf dem Telefon volle Breite statt eines schmalen Popovers. */
  .live-filter { flex: 1 1 100%; }
  .live-filter__summary { width: 100%; justify-content: space-between; min-height: 40px; }
  .live-filter__body { right: 0; min-width: 0; }
  .live-filter__item { min-height: 40px; }
}

.map-bar__note {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
}

.map {
  padding: 0.5rem;
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

/* Die Karte bleibt immer sichtbar; ohne Ergebnisse zeigt sie den Überblick. */

/* Der Ausschnitt, in dem Kacheln und Overlay liegen. */
.map__viewport {
  position: relative;
  width: 100%;
  height: 420px;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--bg-deep);
  cursor: grab;
  touch-action: none;          /* eigene Gestensteuerung */
  /* Nur Layout und Paint eindämmen - "strict" würde auch die Größe
     eindämmen und das Nachladen der Kacheln verhindern. */
  contain: layout paint;
}

.map__viewport.is-dragging { cursor: grabbing; }

.map__tiles { position: absolute; inset: 0; }
.map__tiles.is-off { display: none; }

/* --- Die Karte ist schwarzweiß ------------------------------------
   Der Hintergrund ist Hintergrund. Farbe gehört den Routen, den Zügen und
   den Baustellen darüber; eine Karte mit grünen Wäldern, gelben Straßen
   und blauen Flüssen nimmt ihnen die Aufmerksamkeit und macht das Bild
   unruhig. Entsättigt bleibt die Orientierung erhalten — Siedlung, Wasser
   und Wald unterscheiden sich weiter in der Helligkeit — und die farbigen
   Linien stechen wieder heraus.

   Die Werte sind an der alten Kachelquelle geeicht, die vorher hier stand.
   Nachgemessen an derselben Kachel (Zürich, Zoomstufe 13) liegt CARTO
   „positron" bei einer mittleren Helligkeit von 0,92 und „dark matter" bei
   0,05. Ein erster Versuch mit bloßem Entsättigen landete im dunklen
   Layout bei 0,22 — ein flaues Mittelgrau statt einer dunklen Karte, und
   genau das sah schlechter aus als vorher. Mit diesen Werten: 0,91 hell,
   0,051 dunkel.

   Der Filter liegt nur auf den Kacheln. Das SVG mit Routen, Zügen und
   Baustellen liegt daneben und behält seine Farben. */
.map__tiles {
  filter: grayscale(1) contrast(0.5) brightness(1.42);
}

/* Dunkles Layout aus denselben Kacheln: `invert` dreht Hell und Dunkel um.
   Einen `hue-rotate` braucht es hier nicht mehr — es ist ohnehin nichts
   Farbiges mehr da, das sich verdrehen könnte.

   Die REIHENFOLGE zählt: `brightness` kommt nach `invert` und skaliert die
   umgedrehten Werte nach unten, macht die Karte also dunkel. Umgekehrt hätte
   es sie aufgehellt. Und `contrast` steht über 1, nicht darunter: ein Wert
   unter 1 zieht alles zur Mitte, und genau das war der Fehler zuvor — die
   Karte wurde ein flaues Mittelgrau statt dunkel. */
.map__tiles.is-dark {
  filter: grayscale(1) invert(1) contrast(1.2) brightness(0.34);
}

.map__tile {
  position: absolute;
  user-select: none;
  -webkit-user-drag: none;
  /* Kachelraster ohne Haarlinien dazwischen */
  outline: 1px solid transparent;
  opacity: 0;
  transition: opacity 220ms ease;
}
.map__tile.is-loaded { opacity: 1; }

.map__tile.is-error { display: none; }

.map__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;        /* nur die Routen fangen Klicks */
}

.map__route { pointer-events: auto; }

/* --- Verfolgte Verbindung auf der Karte ------------------------------ */

/* Liegt über den Suchergebnissen und fängt keine Klicks ab — sie ist eine
   Anzeige, keine Auswahl. Grün statt Akzentblau, damit sie sich von der
   ausgewählten Route unterscheidet. */
.map__tracked { pointer-events: none; }

.map__tracked-casing {
  fill: none;
  stroke: var(--map-casing);
  stroke-width: 8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.map__tracked-line {
  fill: none;
  stroke: var(--green);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.map__tracked-end {
  fill: var(--map-stop-fill);
  stroke: var(--green);
  stroke-width: 3;
}

.map__tracked-end.is-end { fill: var(--green); }

/* Die Zugposition hat hier KEINEN eigenen Marker mehr. Der verfolgte Zug
   wird in der Live-Ebene gezeichnet und dort rot eingefärbt — siehe
   `.map__train.is-tracked`. Zwei Punkte für einen Zug waren einer zu viel. */

.map__hit {
  fill: none;
  stroke: transparent;
  stroke-width: 18;
  cursor: pointer;
  /* Ohne "stroke" greift der Standardwert visiblePainted - der ignoriert
     durchsichtige Striche, und die unsichtbare Klickfläche fängt nichts. */
  pointer-events: stroke;
}

/* Basislinie einer Route — auf hellen Kacheln dunkel-slate, auf dunklen
   Kacheln hell-slate. Die aktive Route setzt die Werte weiter unten
   nochmal auf akzent-blau + Casing. */
.map__line {
  fill: none;
  stroke: var(--map-line);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: var(--map-line-opacity);
  transition: var(--transition);
  pointer-events: none;
}

/* Weißer/dunkler Casing-Strich unter der aktiven Route — sorgt für
   Trennung von der Kachel und bleibt auf jeder Bodenfarbe lesbar. */
.map__casing {
  fill: none;
  stroke: var(--map-casing);
  stroke-width: 6;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

/* Die aktive Route wird zuletzt gezeichnet und liegt damit obenauf. Würde
   sie auch Klicks fangen, ließe sich auf gemeinsamen Abschnitten keine
   andere Route mehr auswählen - sie ist bereits gewählt, also durchlassen. */
.map__route.is-active .map__hit { pointer-events: none; }

.map__route:hover .map__line { stroke: var(--text); opacity: 0.8; }

.map__route.is-active .map__line {
  stroke: var(--accent);
  stroke-width: 3.4;
  opacity: 1;
  filter: drop-shadow(0 0 5px var(--accent-soft));
}

/* Beim Klicken keinen Rahmen zeichnen - der Browser umrandet sonst die
   gesamte Bounding-Box der Route mit einem Kasten. Für Tastaturbedienung
   bleibt die Hervorhebung über die Linienfarbe erhalten. */
.map__route:focus { outline: none; }
.map__train:focus { outline: none; }

.map__route:focus-visible .map__line {
  stroke: var(--purple);
  opacity: 1;
  stroke-width: 4;
}

.map__train:focus-visible .map__train-dot {
  fill: var(--purple);
  stroke: #ffffff;
}

.map__stop {
  fill: var(--map-stop-fill);
  stroke: var(--accent);
  stroke-width: 1.5;
}

.map__stop.is-major {
  fill: var(--accent);
  stroke: var(--map-stop-ring);
  stroke-width: 2;
}

/* Kartenschrift: Text mit Halo in Kontrastfarbe, damit die Labels
   sowohl auf OSM-Kacheln als auch auf farbigen Routen lesbar bleiben. */
.map__label {
  fill: var(--map-label);
  font-family: var(--font-mono);
  font-size: 10px;
  paint-order: stroke;
  stroke: var(--map-label-halo);
  stroke-width: 3.5px;
  stroke-linejoin: round;
}

.map__label.is-major { fill: var(--map-label); font-weight: 600; }

/* --- Live-Züge ------------------------------------------------------ */

.map__train { pointer-events: auto; cursor: pointer; }

.map__train-hit { fill: transparent; pointer-events: fill; }

.map__train:hover .map__train-dot,
.map__train:focus-visible .map__train-dot {
  fill: #ffffff;
  stroke: var(--green);
  stroke-width: 2;
}

.map__train-halo {
  fill: var(--green);
  opacity: 0.22;
  animation: trainPulse 2.4s ease-in-out infinite;
}

.map__train-dot {
  fill: var(--green);
  stroke: var(--map-stop-ring);
  stroke-width: 1.4;
}

/* Der gerade verfolgte Zug ist auch ein Live-Zug und wird deshalb ein
   zweites Mal gezeichnet — diese Ebene liegt über der verfolgten Route.
   Ohne eigene Farbe hätte der grüne Punkt den roten Positionsmarker
   darunter wieder zugedeckt. */
.map__train.is-tracked .map__train-dot {
  fill: var(--rose);
  stroke-width: 2;
}

.map__train.is-tracked .map__train-halo { fill: var(--rose); }

/* Hochgerechnete Position: derselbe Punkt, nur hohl. Kommt vor, wenn der Zug
   nicht in der Positionsantwort steht und seine Stelle aus dem Fahrplan
   geschätzt wurde — der Tooltip sagt es dann auch. */
.map__train.is-tracked.is-estimated .map__train-dot {
  fill: var(--map-stop-fill);
  stroke: var(--rose);
}

.map__train.is-tracked:hover .map__train-dot,
.map__train.is-tracked:focus-visible .map__train-dot {
  fill: var(--map-stop-fill);
  stroke: var(--rose);
}

@keyframes trainPulse {
  0%, 100% { opacity: 0.1; r: 6; }
  50%      { opacity: 0.28; r: 9; }
}

/* --- Eigener Standort ---------------------------------------------- */

.map__me { pointer-events: none; }

/* Genauigkeitskreis: aufgeblasen so groß wie die Geolocation-Genauigkeit
   in Metern, umgerechnet auf Pixel. Sanft blau, leicht durchscheinend. */
.map__me-acc {
  fill: #4285f4;
  fill-opacity: 0.12;
  stroke: #4285f4;
  stroke-opacity: 0.35;
  stroke-width: 1;
}

/* Zweites Halo pulsiert, damit der Marker auch bei stiller Karte lebt. */
.map__me-pulse {
  fill: #4285f4;
  opacity: 0.25;
  animation: mePulse 2s ease-in-out infinite;
}

/* Kern-Punkt: kräftig blau mit weißem Ring — der klassische
   "Ich bin hier"-Marker aus Google Maps. */
.map__me-dot {
  fill: #4285f4;
  stroke: #ffffff;
  stroke-width: 2.5;
}

[data-theme="dark"] .map__me-dot { stroke: #0d1220; }

@keyframes mePulse {
  0%, 100% { opacity: 0.30; r: 10; }
  50%      { opacity: 0.10; r: 16; }
}

/* Busy-Zustand des Standort-Buttons: leichte Pulsanimation der Farbe,
   damit klar ist, dass die Ortung läuft. */
.map__btn--locate.is-busy {
  color: var(--accent);
  border-color: var(--accent);
  animation: locateBusy 1.2s ease-in-out infinite;
}

@keyframes locateBusy {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

/* Hinweise unter der Karte färben sich bei Fehlern rötlich. */
.map__hint.is-error { color: var(--rose); }

/* --- Bedienelemente ------------------------------------------------- */

.map__controls {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  z-index: 5;
}

.map__btn {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-xs);
  background: var(--map-overlay-bg);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  transition: var(--transition);
}

.map__btn:hover { color: var(--accent); border-color: var(--accent); }

.map__attr {
  position: absolute;
  bottom: 0.3rem;
  right: 0.45rem;
  z-index: 5;
  padding: 0.1rem 0.35rem;
  border-radius: 3px;
  background: var(--map-overlay-bg-soft);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-decoration: none;
}

.map__attr:hover { color: var(--text-dim); }

/* Maßstabsleiste unten links: schmaler Balken plus Zahl.
   Der Text bekommt einen halben Halo für Lesbarkeit auf jeder Kachelfarbe. */
.map__scale {
  position: absolute;
  bottom: 0.3rem;
  left: 0.45rem;
  z-index: 5;
  display: flex;
  align-items: flex-end;
  gap: 0.35rem;
  pointer-events: none;
  user-select: none;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--text);
  text-shadow: 0 0 3px var(--map-label-halo), 0 0 4px var(--map-label-halo);
}
.map__scale-bar {
  display: block;
  height: 6px;
  min-width: 40px;
  background: var(--map-overlay-bg);
  border: 1px solid var(--border-strong);
  border-top: 0;
  border-radius: 0 0 3px 3px;
  box-shadow: var(--shadow-sm);
}
.map__scale-label {
  padding-bottom: 1px;
  line-height: 1;
}

.map__hint, .map__empty {
  margin: 0.45rem 0 0.1rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-muted);
  text-align: center;
}

/* --- Zugdetails ------------------------------------------------------ */

.train-panel {
  margin-top: 0.6rem;
  padding: 0.8rem 0.9rem;
  background: var(--surface-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

.train-panel[hidden] { display: none; }

.train-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

.train-panel__head strong {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  color: var(--db-red);
}

.train-panel__dir { font-size: 0.86rem; color: var(--text-dim); }

.train-panel__delay {
  margin-left: auto;
  padding: 0.15rem 0.5rem;
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 500;
  white-space: nowrap;
}

.train-panel__delay[data-state="good"]    { background: var(--green-soft); color: var(--green); }
.train-panel__delay[data-state="warn"]    { background: var(--amber-soft); color: var(--amber); }
.train-panel__delay[data-state="bad"]     { background: var(--rose-soft); color: var(--rose); }
.train-panel__delay[data-state="unknown"] { background: var(--surface-inset); color: var(--text-muted); }

.train-panel__close {
  width: 30px;
  height: 30px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text-dim);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.train-panel__close:hover { color: var(--rose); border-color: var(--rose); }

.train-panel__status, .train-panel__msg {
  margin: 0.5rem 0 0;
  font-size: 0.82rem;
  color: var(--text-muted);
}

.train-panel__msg {
  padding: 0.4rem 0.55rem;
  border-left: 2px solid var(--amber);
  background: var(--amber-soft);
  border-radius: var(--radius-xs);
  color: var(--amber);
}

/* Der Abschnitt, für den eine Meldung gilt - eine Zeile darunter, leiser
   als die Meldung selbst: er beantwortet ein "wo?", nicht das "was?".

   Ein Knopf, aber keiner, der wie einer aussieht: er sitzt IN einem
   Fliesstext, und ein Rahmen darum machte aus der Meldung ein Formular.
   Erkennbar bleibt er über die gepunktete Unterlinie und den Zeiger. */
.train-panel__msg-scope {
  display: block;
  margin-top: 0.15rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 0.74rem;
  color: inherit;
  text-align: left;
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  opacity: 0.75;
  cursor: pointer;
}

.train-panel__msg-scope:hover { opacity: 1; }

/* Pünktlichkeit des Zuges. Dieselbe Farblogik wie das Verspätungsabzeichen
   im Kopf, aber als Zeile statt als Plakette: es ist eine Einordnung, keine
   Meldung über den Zustand von jetzt. */
.train-panel__history {
  margin: 0.5rem 0 0;
  padding: 0.4rem 0.55rem;
  border-radius: var(--radius-xs);
  background: var(--surface-inset);
  font-size: 0.78rem;
  color: var(--text-muted);
}

.train-panel__history strong { font-family: var(--font-mono); font-weight: 500; }
.train-panel__history[data-state="good"] strong { color: var(--green); }
.train-panel__history[data-state="warn"] strong { color: var(--amber); }
.train-panel__history[data-state="bad"]  strong { color: var(--rose); }

.train-panel__stops {
  list-style: none;
  margin: 0.6rem 0 0;
  padding: 0;
  max-height: 260px;
  overflow-y: auto;
}

.train-panel__stop {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.25rem 0;
  /* Für die Hervorhebung aus flagStops(): sie soll aufblitzen und wieder
     verschwinden, nicht als dauerhafte Markierung hängen bleiben. */
  transition: background-color 0.25s ease;
  font-size: 0.85rem;
  border-bottom: 1px solid var(--border);
}

.train-panel__stop.is-cancelled { opacity: 0.5; text-decoration: line-through; }

/* Der Abschnitt, auf den eine Meldung zeigt - gesetzt von flagStops().
   Negative Ränder, damit die Fläche über die volle Listenbreite geht und
   die Zeile dabei nicht springt. */
.train-panel__stop.is-flagged {
  margin: 0 -0.35rem;
  padding-left: 0.35rem;
  padding-right: 0.35rem;
  background: var(--amber-soft);
}

.train-panel__time {
  flex: 0 0 auto;
  min-width: 44px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* Weicht die Ist-Zeit ab, wird die Planzeit durchgestrichen daneben gezeigt. */
.train-panel__time.is-shifted { color: var(--text-muted); text-decoration: line-through; }

.train-panel__real {
  flex: 0 0 auto;
  min-width: 44px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--amber);
}

.train-panel__name { flex: 1 1 auto; color: var(--text-dim); }

.train-panel__platform {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-muted);
}

.train-panel__stop-delay {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--amber);
}

/* --- Ergebnisse ---------------------------------------------------- */

/* --- Sortierung der Trefferliste ------------------------------------- */

/* Dieselbe Sprache wie die Leiste über der Karte: schmale Zeile, Monoschrift,
   kein eigener Kasten. Sie steht direkt über der Liste, die sie ordnet. */
.results-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.1rem;
  padding: 0 0.2rem;
}

/* Schmaler als die Formularfelder — hier wird nichts eingegeben, sondern
   nur umgeschaltet. Die Breite richtet sich nach dem Inhalt. */
.results-bar select {
  width: auto;
  min-height: 34px;
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
}

.results-bar__note {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
}

.results { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 1rem; }

.empty { padding: 2.5rem 0; text-align: center; color: var(--text-muted); }

/* --- Live-Verfolgung ------------------------------------------------ */

/* Knopf auf der Verbindungskarte. Zurückhaltend, solange nichts läuft —
   eingeschaltet trägt er die Akzentfarbe, damit man die verfolgte
   Verbindung in der Liste sofort wiederfindet. */
.live-btn {
  align-self: flex-start;
  margin-top: 0.6rem;
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  cursor: pointer;
  transition: var(--transition);
}

.live-btn:hover { border-color: var(--accent); color: var(--accent); }

.live-btn.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 500;
}

/* Panel unter der Karte. */
.live {
  margin-top: 0.6rem;
  padding: 0.8rem 0.9rem;
  background: var(--surface-card);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.live__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

.live__title { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.live__title strong { color: var(--accent); font-family: var(--font-mono); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; }
.live__route { font-size: 0.88rem; color: var(--text-dim); }

.live__ctl { display: flex; align-items: center; gap: 0.5rem; }

.live__gps {
  padding: 0.28rem 0.65rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  cursor: pointer;
}

.live__gps.is-on { border-color: var(--green); background: var(--green-soft); color: var(--green); }

.live__stamp { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-muted); }

.live__close {
  width: 26px; height: 26px;
  border: 0; border-radius: 50%;
  background: var(--surface-inset);
  color: var(--text-dim);
  font-size: 1rem; line-height: 1;
  cursor: pointer;
}

.live__error { margin: 0.5rem 0 0; color: var(--rose); font-size: 0.8rem; }
.live__note { margin: 0.5rem 0 0; color: var(--text-muted); font-size: 0.8rem; }

/* Wo bin ich gerade — die Antwort der GPS-Mitfahrt. */
.live__progress {
  margin: 0.55rem 0 0;
  padding: 0.4rem 0.6rem;
  background: var(--green-soft);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text);
}

.live__progress--wait { background: var(--surface-inset); color: var(--text-muted); }
.live__progress-rest { color: var(--text-dim); }

/* --- Gefährdeter Anschluss ----------------------------------------- */

.live__risk {
  margin-top: 0.6rem;
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--amber);
  background: var(--amber-soft);
}

/* Ein ausgefallener Zug ist keine Verspätung, sondern das Ende der
   Verbindung - deshalb dieselbe kräftige Farbe wie beim verpassten
   Anschluss, und in der Trefferliste ganz vorn. */
.badge--cancelled {
  border-color: var(--rose);
  background: var(--rose-soft);
  color: var(--rose);
  font-weight: 600;
}

.leg--cancelled { opacity: 0.75; }

.leg__cancelled {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--rose);
  margin-bottom: 0.2rem;
}

.live__risk--missed,
.live__risk--cancelled { border-left-color: var(--rose); background: var(--rose-soft); }

.live__risk-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.45rem; }
.live__risk-head strong { font-family: var(--font-mono); font-size: 0.8rem; }
.live__risk--risky .live__risk-head strong { color: var(--amber); }
.live__risk--missed .live__risk-head strong,
.live__risk--cancelled .live__risk-head strong { color: var(--rose); }

/* Meldungen füllen höchstens vier Zeilen. Was nicht hineinpasst, endet mit
   "…"; der ganze Text hängt am Titel und im aufgeklappten Kasten. */
.live__leg-msg {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.live__msgs { margin: 0.2rem 0 0; }

.live__msgs > summary {
  cursor: pointer;
  list-style: none;
  font-size: 0.74rem;
  color: var(--text-dim);
  padding: 0.1rem 0;
}

.live__msgs > summary::-webkit-details-marker { display: none; }
.live__msgs > summary::before { content: '▸ '; }
.live__msgs[open] > summary::before { content: '▾ '; }
.live__msgs > summary:hover { color: var(--accent); }
.live__risk-text { font-size: 0.8rem; color: var(--text-dim); }

.live__risk-note {
  margin: 0.45rem 0 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
}

.live__options { display: flex; flex-direction: column; gap: 0.35rem; }

/* Jede Alternative ist ein Vorschlag zum Antippen, kein Fließtext. */
.live__option {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.45rem;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-solid);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  text-align: left;
  cursor: pointer;
  transition: var(--transition);
}

.live__option:hover { border-color: var(--accent); background: var(--field-bg-hover); }
.live__option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.live__option-times { font-variant-numeric: tabular-nums; font-weight: 500; color: var(--text); }
.live__option-meta { min-width: 0; }
.live__option-lost { color: var(--amber); }

.live__option-take {
  margin-left: auto;
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-xs);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.68rem;
}

.live__rerouted {
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-xs);
  background: var(--amber-soft);
  color: var(--amber);
  font-family: var(--font-mono);
  font-size: 0.68rem;
}

.live__leg { margin-top: 0.7rem; }

.live__leg-head { display: flex; align-items: baseline; gap: 0.5rem; }

.live__leg-name {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 500;
}

.live__delay {
  padding: 0.1rem 0.45rem;
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.72rem;
}

.live__delay[data-state="good"]    { background: var(--green-soft); color: var(--green); }
.live__delay[data-state="warn"]    { background: var(--amber-soft); color: var(--amber); }
.live__delay[data-state="bad"]     { background: var(--rose-soft); color: var(--rose); }
.live__delay[data-state="unknown"] { background: var(--surface-inset); color: var(--text-muted); }

.live__leg-msg, .live__msg {
  margin: 0.35rem 0 0;
  padding: 0.35rem 0.55rem;
  background: var(--amber-soft);
  border-radius: var(--radius-xs);
  font-size: 0.76rem;
  color: var(--text-dim);
  /* Die Meldungen sind meist dreiteilig ("Was ist los", "Grund", "Was heißt
     das"). Text.php erhält die Absätze als Umbrüche — ohne pre-line würden
     sie hier wieder zu einem Klumpen zusammenfallen. */
  white-space: pre-line;
}

.live__msg-text { color: var(--text-muted); }

.live__stops { margin: 0.4rem 0 0; padding: 0; list-style: none; }

.live__stop {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  padding: 0.12rem 0;
  font-family: var(--font-mono);
  font-size: 0.76rem;
}

.live__stop.is-past { opacity: 0.45; }
.live__stop.is-cancelled { text-decoration: line-through; color: var(--rose); }

.live__stop-time { font-variant-numeric: tabular-nums; color: var(--text-dim); }
.live__stop-time.is-shifted { text-decoration: line-through; opacity: 0.6; }
.live__stop-real { font-variant-numeric: tabular-nums; color: var(--rose); }
.live__stop-name { color: var(--text); }
.live__stop-platform { margin-left: auto; color: var(--text-muted); font-size: 0.7rem; }

/* Verfolgte Verbindung, die nicht in der Trefferliste steht. */
.tracked-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  font-family: var(--font-mono);
  font-size: 0.78rem;
}

.tracked-bar__label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
}

.tracked-bar__text { color: var(--text); font-variant-numeric: tabular-nums; }

.tracked-bar__tag {
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-xs);
  background: var(--amber-soft);
  color: var(--amber);
  font-size: 0.68rem;
}

.tracked-bar__stop {
  margin-left: auto;
  padding: 0.2rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-xs);
  background: var(--surface-solid);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 0.72rem;
  cursor: pointer;
}

.tracked-bar__stop:hover { border-color: var(--accent); color: var(--accent); }

/* --- Routenvarianten (Nerd-Mode) ------------------------------------ */

/* Trennt die Gruppen der Ergebnisliste. Bewusst kein Kasten: die Zeile
   gliedert, sie soll nicht mit den Verbindungskarten konkurrieren. */
.group-head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin: 0.6rem 0 -0.1rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid var(--border);
}

.group-head:first-child { margin-top: 0; }

.group-head__label {
  font-family: var(--font-mono);
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--accent);
}

.group-head__count { font-size: 0.75rem; color: var(--text-muted); }

/* Befahrene Strecken am Fuß der Detailansicht. */
.route-hits {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem;
  margin-top: 0.5rem;
}

.route-hits__label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
}

.route-hits__item {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  padding: 0.12rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--accent-soft);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
}

.route-hits__speed { color: var(--text-muted); font-size: 0.66rem; }

/* Geschätzte statt gepflegte Strecke: gestrichelter Rand, keine Akzentfarbe.
   Der Unterschied muss sichtbar sein, weil die Tempoangabe eine andere
   Bedeutung hat. */
.route-hits__item--auto {
  background: transparent;
  border-style: dashed;
  color: var(--text-muted);
}

/* Knopfreihe innerhalb eines Abschnitts. */
.actions--inline { margin-bottom: 0.6rem; }

/* Aufklappen der restlichen Verbindungen. Bewusst so breit wie eine Karte,
   damit klar ist, dass die Liste hier weitergeht. */
.more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  padding: 0.75rem 1rem;
  background: var(--surface-card);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.more:hover { border-color: var(--accent); background: var(--surface-card-hover); }
.more:disabled { cursor: default; opacity: 0.6; border-style: solid; }
.more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.more__label { font-weight: 500; }
.more__hint { font-size: 0.78rem; color: var(--text-dim); }

.journey {
  padding: 1rem 1.1rem;
  background: var(--surface-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: var(--transition);
}

.journey:hover {
  border-color: var(--border-strong);
  background: var(--surface-card-hover);
  box-shadow: var(--shadow-md);
}

.journey--best {
  border-color: rgba(2, 132, 199, 0.45);
  box-shadow: var(--glow-accent);
}

.journey.is-selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), var(--glow-accent);
}

.journey__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  align-items: flex-start;
  justify-content: space-between;
}

/* Der linke Block darf schrumpfen (min-width:0), der Preis rechts nicht —
   sonst schieben sich Zeiten und Preis auf schmalen Bildschirmen ineinander. */
.journey__main { flex: 1 1 auto; min-width: 0; }

.journey__times {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.55rem;
}

.journey__time {
  font-family: var(--font-mono);
  font-size: 1.4rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.journey__arrow { color: var(--text-muted); }

.journey__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-dim);
}

.journey__price-box { flex: 0 0 auto; margin-left: auto; text-align: right; }

.journey__price {
  font-family: var(--font-mono);
  font-size: 1.22rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--text);
}

.journey__price--est { color: var(--text-dim); font-weight: 500; }
.journey__price--covered { color: var(--green); }
.journey__price--none { color: var(--text-muted); }

/* Gegenwert in der anderen Währung: deutlich kleiner als der Preis, damit
   klar bleibt, was der verbindliche Wert ist. */
.journey__price-alt {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  cursor: help;
}

.journey__price-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* --- Badges -------------------------------------------------------- */

.badges { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.7rem; }

.badge {
  padding: 0.14rem 0.45rem;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  white-space: nowrap;
  background: var(--surface-inset);
  color: var(--text-muted);
}

.badge--price { background: var(--green-soft); color: var(--green); }
.badge--fast { background: var(--accent-soft); color: var(--accent); }
.badge--comfort { background: var(--purple-soft); color: var(--purple); }
.badge--direct { background: var(--amber-soft); color: var(--amber); }
.badge--rule { background: var(--accent-soft); color: var(--accent); }
.badge--score { background: var(--purple-soft); color: var(--purple); }
.badge--variant { background: var(--surface-inset); color: var(--text-dim); }
.badge--rerouted { background: var(--amber-soft); color: var(--amber); }

/* Die Kennzeichnung ist zugleich der Weg zurück. */
.badge--undo {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  border: 1px solid transparent;
  font: inherit;
  cursor: pointer;
}

.badge--undo:hover { border-color: var(--amber); }

.badge__undo-hint {
  padding-left: 0.35rem;
  border-left: 1px solid currentColor;
  opacity: 0.75;
}

.live__undo {
  margin-left: 0.4rem;
  padding: 0.05rem 0.45rem;
  border: 1px solid var(--amber);
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--amber);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  cursor: pointer;
}

.live__undo:hover { background: var(--amber-soft); }
.badge--dticket { background: var(--db-red-soft); color: var(--db-red); }
.badge--risky { background: var(--rose-soft); color: var(--rose); }
.badge--tight { background: var(--amber-soft); color: var(--amber); }
.badge--occ1 { background: var(--green-soft); color: var(--green); }
.badge--occ2 { background: var(--amber-soft); color: var(--amber); }
.badge--occ3 { background: var(--rose-soft); color: var(--rose); }
.badge--occ4 { background: var(--rose-soft); color: var(--rose); font-weight: 700; }

/* --- Bestpreise über den Tag ---------------------------------------- */

.bp {
  margin-top: 1rem;
  padding: 0.85rem 1rem;
  background: var(--surface-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.bp[hidden] { display: none; }

.bp__head {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--text-dim);
  margin-bottom: 0.6rem;
}

.bp__bars {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 0.35rem;
  align-items: end;
}

.bp__bar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  padding: 0.45rem 0.2rem 0.35rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  /* Je günstiger das Fenster, desto kräftiger die Füllung. */
  background: linear-gradient(to top,
    rgba(2, 132, 199, calc(0.32 * var(--fill, 0.5))) 0%,
    transparent 100%);
  color: var(--text-dim);
  font-family: var(--font-mono);
  cursor: pointer;
  transition: var(--transition);
}

.bp__bar:hover { border-color: var(--accent); color: var(--text); }

.bp__bar.is-best {
  border-color: rgba(5, 150, 105, 0.55);
  color: var(--green);
}

.bp__price { font-size: 0.85rem; font-weight: 600; }
.bp__time { font-size: 0.66rem; opacity: 0.75; }

/* --- Umstiegswarnung und Auslastung im Detail ------------------------ */

.leg__transfer {
  margin: 0 0 0.25rem;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.74rem;
}

/* --- Echtzeit in der Trefferliste ------------------------------------ */

/* Weicht die Ist-Zeit ab, steht der Fahrplanwert durchgestrichen daneben.
   Beides zu zeigen ist wichtiger als Platz zu sparen: sonst weiß man nicht,
   ob man die alte oder die neue Zeit vor sich hat. */
.journey__time--planned,
.leg__time--planned {
  text-decoration: line-through;
  opacity: 0.55;
  font-weight: 400;
}

.journey__time--real { color: var(--rose); }
.leg__time--real { color: var(--rose); font-variant-numeric: tabular-nums; }

.badge--ontime { background: var(--green-soft); color: var(--green); }

.leg__remark {
  margin: 0.2rem 0 0;
  padding: 0.25rem 0.5rem;
  border-radius: var(--radius-xs);
  background: var(--amber-soft);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
}

.leg__transfer--risky { background: var(--rose-soft); color: var(--rose); }
.leg__transfer--tight { background: var(--amber-soft); color: var(--amber); }

/* Rückfallebene: sitzt direkt unter der Umstiegswarnung und ist bewusst
   ruhiger gehalten - eine Information, keine zweite Warnung. */
.leg__fallback {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  margin: -0.1rem 0 0.35rem;
  padding: 0.3rem 0.5rem;
  border-left: 2px solid var(--border-strong);
  background: var(--surface-inset);
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
}

.leg__fallback { flex-direction: column; align-items: stretch; }

.leg__fallback-label {
  font-weight: 500;
  color: var(--text-muted);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.leg__fallback-list { display: flex; flex-direction: column; gap: 0.25rem; }

/* Jede Alternative ist ein Vorschlag zum Antippen, nicht nur eine Notiz. */
.leg__alt {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  width: 100%;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--surface-card);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-align: left;
  cursor: pointer;
  transition: var(--transition);
}

.leg__alt:hover { border-color: var(--accent); background: var(--surface-card-hover); }
.leg__alt:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.leg__alt-times { font-variant-numeric: tabular-nums; color: var(--text); font-weight: 500; }
.leg__alt-meta { min-width: 0; }
.leg__alt-lost { color: var(--amber); }

/* --- Umstiegsplan ----------------------------------------------------- */

.xfer {
  margin: 0.2rem 0 0.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--surface-card);
}

.xfer__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.3rem 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
  cursor: pointer;
  list-style: none;
  min-height: 30px;
}

.xfer__summary::-webkit-details-marker { display: none; }
.xfer__summary::after { content: '▾'; margin-left: auto; opacity: 0.6; }
.xfer[open] .xfer__summary::after { content: '▴'; }
.xfer__summary:hover { color: var(--accent); }

.xfer__tracks { color: var(--text); font-weight: 500; }
.xfer__hint { color: var(--text-muted); font-size: 0.68rem; }

.xfer__body { padding: 0.1rem 0.5rem 0.5rem; }

.xfer__note {
  margin: 0 0 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
}

.xfer__level { color: var(--amber); }

.xfer__source {
  margin: 0.3rem 0 0;
  font-size: 0.66rem;
  color: var(--text-muted);
}

/* --- Die Karte im Umstiegsplan --------------------------------------
   Dieselbe Karte wie überall sonst, nur im Bahnhofsmodus: Kacheln als
   Untergrund, ziehen und zoomen, dazu ein Umschalter für die Ebene. Flacher
   als die Routenkarte — sie sitzt in einem aufklappbaren Kasten.
   ------------------------------------------------------------------- */
.xfer__map {
  margin: 0.5rem 0 0.4rem;
  padding: 0.3rem;
  box-shadow: none;
}

.xfer__map .map__viewport { height: 280px; }

@media (max-width: 640px) {
  .xfer__map .map__viewport { height: 230px; }
}

/* --- Gleise auf der Karte -------------------------------------------
   Nur Punkte. Umrisse standen hier einmal als Linien; sie sagten, wo der
   Bahnsteig liegt, nicht wo der Zug hält, und gingen mit den Gleisflächen
   aus OSM zu einem Liniengewirr zusammen.
   ------------------------------------------------------------------- */

.map__track {
  fill: var(--surface-card);
  stroke: var(--text-muted);
  stroke-width: 2;
  opacity: 0.75;
}

.map__track.is-from {
  fill: var(--surface-card);
  stroke: var(--accent);
  stroke-width: 3.5;
  opacity: 1;
}

.map__track.is-to {
  fill: var(--green);
  stroke: var(--green);
  stroke-width: 3.5;
  opacity: 1;
}

.map__track-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  fill: var(--text);
  paint-order: stroke;
  stroke: var(--map-casing);
  stroke-width: 3px;
  stroke-linejoin: round;
}

.map__track-tag.is-from { fill: var(--accent); }
.map__track-tag.is-to   { fill: var(--green); }

/* Was auf einer anderen Ebene liegt, bleibt sichtbar, tritt aber zurück —
   sonst verliert man beim Umschalten die Orientierung, weil das halbe Bild
   verschwindet. */
.map__track.is-other-level,
.map__track-tag.is-other-level { opacity: 0.16; }

/* --- Ebenenumschalter ------------------------------------------------
   Unten links, gegenüber den Zoomknöpfen — wie in den Apps der Bahnen, wo
   man ihn dort erwartet.
   ------------------------------------------------------------------- */
.map__levels {
  position: absolute;
  left: 0.5rem;
  top: 0.5rem;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--border-strong);
  background: var(--surface-card);
  box-shadow: var(--shadow-sm);
}

.map__level-btn {
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 0.7rem;
  line-height: 1;
  padding: 0.35rem 0.5rem;
  cursor: pointer;
  transition: var(--transition);
}

.map__level-btn:hover:not(:disabled) { background: var(--accent-soft); color: var(--accent); }
.map__level-btn:disabled { opacity: 0.3; cursor: default; }

.map__level-value {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
  padding: 0.1rem 0.45rem;
  border-block: 1px solid var(--border);
  color: var(--accent);
}

.leg__alt-take {
  margin-left: auto;
  padding: 0.02rem 0.35rem;
  border-radius: var(--radius-xs);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.66rem;
}

.leg__fallback--pending,
.leg__fallback--none { color: var(--text-muted); font-style: italic; }

.leg__occ { font-family: var(--font-mono); font-size: 0.74rem; }
.leg__occ--1 { color: var(--green); }
.leg__occ--2 { color: var(--amber); }
.leg__occ--3, .leg__occ--4 { color: var(--rose); }

/* --- Zugkette (DB-Navigator-Anleihe) -------------------------------- */

.chain { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.6rem; }

.chip {
  padding: 0.18rem 0.5rem;
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: help;
}

.chip--fern { background: var(--db-red-soft); color: var(--db-red); }
.chip--nah { background: var(--surface-inset); color: var(--text-dim); }
.chip--night { background: var(--purple-soft); color: var(--purple); }

.chip__series {
  margin-left: 0.3rem;
  padding-left: 0.3rem;
  border-left: 1px solid currentColor;
  opacity: 0.75;
  font-size: 0.7rem;
}

/* --- Details / Zeitachse -------------------------------------------- */

.journey__details { margin-top: 0.8rem; }

.journey__details > summary {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0.2rem 0;
  transition: color var(--transition);
}

.journey__details > summary:hover { color: var(--accent); }

.legs {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  margin-top: 0.7rem;
  padding-left: 0.9rem;
  border-left: 1px solid var(--border-strong);
}

.leg { display: flex; flex-direction: column; gap: 0.22rem; }

.leg--walk {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-muted);
}

/* Ein Fußweg zwischen zwei verschiedenen Halten ist etwas anderes als ein
   Umstieg am selben Bahnsteig — das soll man auseinanderhalten können. */
.leg--walk-between {
  padding: 0.3rem 0.5rem;
  border-left: 2px solid var(--purple);
  border-radius: var(--radius-xs);
  background: var(--purple-soft);
  color: var(--purple);
}

.badge--walk { background: var(--purple-soft); color: var(--purple); }

.leg__line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; }

.leg__time {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.leg__station { font-size: 0.9rem; color: var(--text-dim); }

.leg__platform {
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--border);
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-muted);
}

.leg__train {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.15rem 0 0.15rem 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-muted);
}

.leg__cat { color: var(--db-red); font-weight: 500; }
.leg__comfort { color: var(--purple); }
.leg__series { color: var(--accent); }

.leg__stops { display: flex; flex-wrap: wrap; gap: 0.25rem; padding-left: 0.3rem; }

.leg__stop {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25rem;
  padding: 0.08rem 0.35rem;
  border-radius: 3px;
  background: var(--surface-inset);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-muted);
}

/* Uhrzeit vor dem Namen, damit die Halte zeitlich lesbar bleiben. */
.leg__stop-time {
  font-variant-numeric: tabular-nums;
  color: var(--text);
  opacity: 0.75;
}

.leg__stops-count {
  padding-left: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--text-muted);
}

.estimate-note {
  margin: 0.3rem 0 0;
  padding: 0.55rem 0.7rem;
  background: var(--surface-inset);
  border-radius: var(--radius-sm);
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* --- Ticketshops ---------------------------------------------------- */

.shops {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.85rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
}

.shops__label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.shops__link {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0.25rem 0.7rem;
  border: 1px solid rgba(2, 132, 199, 0.3);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 500;
  text-decoration: none;
  transition: var(--transition);
}

.shops__link:hover { background: rgba(2, 132, 199, 0.18); box-shadow: var(--glow-accent); }

.shops__link--manual {
  border-color: var(--border);
  background: var(--surface-inset);
  color: var(--text-dim);
}

.shops__link--manual:hover { box-shadow: none; border-color: var(--border-strong); }

.shops__hint { margin-left: 0.15rem; opacity: 0.8; }

.shops__note {
  flex-basis: 100%;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-muted);
}

.leg__model { color: var(--accent); font-weight: 500; }
.leg__model--inferred { opacity: 0.85; }

/* --- Fuß ----------------------------------------------------------- */

.page-foot {
  margin-top: 2.5rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--border);
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--text-muted);
}

/* --- MVG-Störungsticker (nur München, per JS eingeblendet) ------- */

.mvg-ticker-mount {
  margin-top: 1.5rem;
}
.mvg-ticker {
  border: 1px solid var(--border);
  border-radius: 0.7rem;
  background: var(--surface-card);
  box-shadow: var(--shadow-sm);
  padding: 0.5rem 0.8rem;
  font-size: 0.82rem;
}
.mvg-ticker__summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  list-style: none;
  color: var(--text-dim);
}
.mvg-ticker__summary::-webkit-details-marker { display: none; }
.mvg-ticker__summary::before {
  content: "▸";
  display: inline-block;
  transition: transform 120ms ease;
  color: var(--text-dim);
}
.mvg-ticker[open] .mvg-ticker__summary::before { transform: rotate(90deg); }
.mvg-ticker__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.4rem;
  height: 1.4rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  background: var(--amber-soft);
  color: var(--amber);
  font-weight: 500;
  font-size: 0.75rem;
}
.mvg-ticker__list {
  list-style: none;
  margin: 0.6rem 0 0.2rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.mvg-ticker__item {
  display: grid;
  grid-template-columns: auto auto 1fr;
  gap: 0.5rem;
  align-items: center;
  padding: 0.4rem 0;
  border-top: 1px dashed var(--border);
}
.mvg-ticker__item:first-child { border-top: 0; }
.mvg-ticker__type {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-dim);
}
.mvg-ticker__lines {
  display: inline-flex;
  gap: 0.25rem;
  flex-wrap: wrap;
}
.mvg-ticker__line {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 0.72rem;
  padding: 0.05rem 0.4rem;
  border-radius: 0.35rem;
  background: var(--surface-inset);
  color: var(--text-dim);
  border: 1px solid var(--border);
}
/* --- Bauarbeiten im Netz --------------------------------------------- */

.works__note {
  margin: 0.2rem 0 0.3rem;
  font-size: 0.7rem;
  color: var(--text-muted);
}

/* Drei Spalten: Abschnitt, Meldung, Restdauer. Die Restdauer ist die Zahl,
   die entscheidet, ob einen das noch betrifft — deshalb rechts und farbig.

   `minmax(0, …)` bei den ersten beiden: ohne die Null als Untergrenze ist die
   Spaltenbreite die INHALTSBREITE, und ein 300 Zeichen langer Meldungstext
   zog die Zeile weit über den Rand der Seite hinaus. Mit ihr bleibt das
   Raster in seinen Grenzen und der Text bricht um. */
/* Die Baustellenzeile ist ein aufklappbarer Kasten. Das Raster sitzt
   deshalb an der Kopfzeile, nicht mehr am Listenelement. */
.works__list .mvg-ticker__item {
  display: block;
  padding: 0;
}

.works__summary {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto;
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.45rem 0 0.45rem 1rem;
  cursor: pointer;
  list-style: none;
  position: relative;
}

.works__summary::-webkit-details-marker { display: none; }

/* Dasselbe Dreieck wie an den Ländergruppen — hier eine Ebene tiefer. */
.works__summary::before {
  content: '▸';
  position: absolute;
  left: 0;
  color: var(--text-dim);
  font-size: 0.7rem;
  transition: transform 0.15s;
}

.works__detail[open] > .works__summary::before { transform: rotate(90deg); }

.works__summary:hover { color: var(--accent); }

.works__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
  padding: 0 0 0.6rem 1rem;
}

.works__text {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--text);
  overflow-wrap: anywhere;
}

.works__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-dim);
}

/* --- Baustellen nach Land ------------------------------------------- */

.works__land { list-style: none; }

.works__land-box { border-top: 1px solid var(--border); }
.works__land:first-child .works__land-box { border-top: 0; }

.works__land-summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  list-style: none;
  padding: 0.4rem 0;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-dim);
}

.works__land-summary::-webkit-details-marker { display: none; }
.works__land-summary::before {
  content: "▸";
  display: inline-block;
  transition: transform 120ms ease;
}
.works__land-box[open] > .works__land-summary::before { transform: rotate(90deg); }

.works__land-count {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  padding: 0.02rem 0.4rem;
  border-radius: 999px;
  background: var(--surface-inset);
  color: var(--text-muted);
}

/* Nachschieben statt alles auf einmal — hundert Zeilen unter der Karte
   liest niemand, und unerreichbar sollen sie trotzdem nicht sein. */
.works__more {
  margin: 0.2rem 0 0.5rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 0.72rem;
  cursor: pointer;
  transition: var(--transition);
}

.works__more:hover { border-color: var(--accent); color: var(--accent); }

/* Der Meldungskopf füllt in der Kopfzeile höchstens zwei Zeilen. Was nicht
   hineinpasst, endet mit "…"; der ganze Text steht im aufgeklappten Kasten. */
.works__title {
  min-width: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  /* Lange Bahnhofs- und Streckennamen ohne Leerzeichen notfalls trennen,
     statt sie aus dem Kasten laufen zu lassen. */
  overflow-wrap: anywhere;
}

/* --- Die Baustellenkarte --------------------------------------------
   Flacher als die Routenkarte: sie ist ein Überblick, keine Arbeitsfläche,
   und sitzt in einem aufklappbaren Kasten, der nicht den halben Bildschirm
   einnehmen soll.
   ------------------------------------------------------------------- */
.works__map {
  margin: 0.6rem 0 0.2rem;
  padding: 0.3rem;
  box-shadow: none;
}

.works__map .map__viewport { height: 300px; }

@media (max-width: 640px) {
  .works__map .map__viewport { height: 220px; }
}

/* Springt auf der Karte zum Abschnitt. Steht im aufgeklappten Kasten - in
   der Kopfzeile wäre er ein Knopf im Knopf und würde beim Aufklappen
   mitgetroffen. */
.works__jump {
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: var(--transition);
}

.works__jump:hover { border-color: var(--accent); color: var(--accent); }

.works__section {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  /* Auf breiten Schirmen in einer Zeile, auf schmalen lieber umbrechen als
     die Nachbarspalte wegdrücken. */
  white-space: nowrap;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .works__section { white-space: normal; }

  /* Auf dem Telefon untereinander statt in drei Spalten: nebeneinander
     blieben für den Abschnitt keine dreißig Pixel. */
  .works__summary {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.25rem;
  }

}

.mvg-ticker__until {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--amber);
  white-space: nowrap;
}

.mvg-ticker__line--more { color: var(--text-muted); }

/* Bauarbeiten auf der Karte: gestrichelt, weil die gerade Linie den
   BETROFFENEN ABSCHNITT zeigt und nicht den Verlauf der Schiene. */
.map__works { pointer-events: none; }

.map__work-line {
  stroke: var(--amber);
  stroke-width: 3;
  stroke-dasharray: 6 4;
  opacity: 0.8;
  pointer-events: stroke;
  fill: none;
}

/* Wo der tatsächliche Streckenverlauf bekannt ist, wird die Linie
   durchgezogen: sie zeigt dann die Schiene und nicht mehr bloß, welche
   beiden Betriebsstellen betroffen sind. */
.map__work-line.is-exact {
  stroke-dasharray: none;
  stroke-width: 3.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.map__work-dot { fill: var(--amber); opacity: 0.9; }

.mvg-ticker__line[data-transport="UBAHN"] { color: #fff; background: #1f6bb6; border-color: #1f6bb6; }
.mvg-ticker__line[data-transport="SBAHN"] { color: #fff; background: #128f4c; border-color: #128f4c; }
.mvg-ticker__line[data-transport="TRAM"]  { color: #fff; background: #cc0018; border-color: #cc0018; }
.mvg-ticker__line[data-transport="BUS"]   { color: #fff; background: #0d3d80; border-color: #0d3d80; }
.mvg-ticker__title {
  color: var(--text);
  line-height: 1.35;
}

/* --- Tablets -------------------------------------------------------- */

@media (max-width: 1024px) {
  /* 16 px verhindert, dass iOS beim Antippen eines Feldes hineinzoomt. Die
     Regel stand bisher nur in der Telefon-Abfrage — auf dem iPad sprang die
     Seite deshalb bei jedem Fokus. */
  input[type="text"], input[type="date"], input[type="time"],
  input[type="number"], select {
    font-size: 16px;
  }

  /* Etwas mehr Grundbreite je Spalte: bei 161 px wird es für ein
     Datumsfeld eng, und lieber eine Spalte weniger als vier zu enge. */
  .row--options { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
}

@media (max-width: 820px) {
  .wrap { padding: 1.5rem 0.9rem 4rem; }
  .models { grid-template-columns: 1fr; }
}

/* --- Datum und Uhrzeit: das Systemsteuerelement bändigen ---------
 *
 * iOS und Android zeichnen diese Felder als SYSTEMSTEUERELEMENT und geben
 * ihm die Breite seines INHALTS. `width: 100%`, `max-width` und
 * `min-width: 0` prallen daran ab: das Element ist schlicht nicht bereit,
 * schmaler zu werden als der Text darin, und schiebt sich über das
 * Nachbarfeld und über den Rand des Panels.
 *
 * FÜR ALLE BREITEN, nicht nur fürs Telefon. Zuerst stand das hier in der
 * Telefon-Abfrage — und prompt kam dieselbe Meldung fürs iPad: dort sind die
 * Spalten 161 px breit, ein natives Datumsfeld will 165, und schon
 * überlappen Datum, Uhrzeit und Klasse. Dieselbe Ursache, nur eine
 * Bildschirmgrösse weiter. Auf dem Schreibtisch schadet die Regel nichts,
 * dort ist ohnehin Platz.
 *
 * Es hilft nur `appearance: none` — damit gilt wieder die Rasterbreite.
 * Was dabei verloren geht, wird hier einzeln zurückgeholt, denn genau das
 * war der Einwand beim ersten Versuch:
 *
 *   - der Wert saß oben links statt mittig -> `display: flex` mit
 *     `align-items: center` stellt ihn wieder mittig auf die Zeilenhöhe;
 *   - das Kalender- bzw. Uhrsymbol fehlte -> es kommt als eingebettetes
 *     SVG zurück, gezeichnet in der Textfarbe des Feldes;
 *   - das Feld wirkte leer -> es trägt jetzt sichtbar seinen Wert, weil
 *     `::-webkit-date-and-time-value` links ausgerichtet ist statt in
 *     einem nullbreiten Kasten zu stecken.
 */
.row--options input[type="date"],
.row--options input[type="time"] {
  -webkit-appearance: none;
  appearance: none;
  display: flex;
  align-items: center;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
  /* Als Kurzschreibweise, damit die allgemeine `padding`-Regel weiter
     unten sie nicht teilweise überschreibt. Rechts Platz fürs Symbol. */
  padding: 0.5rem 2rem 0.5rem 0.6rem;
  background-repeat: no-repeat;
  /* Vier Werte, nicht drei: `right 0.6rem center` ist die
     Dreiwert-Schreibweise, und die ist ungültig - der Browser wirft die
     Zeile weg und setzt das Symbol nach oben links. */
  background-position: right 0.6rem top 50%;
  background-size: 1.05rem 1.05rem;
}

/* Der Wert steckt in einem eigenen Schattenknoten. Ohne diese Regel behält
   er seine Inhaltsbreite und läuft aus dem geschrumpften Feld heraus. */
.row--options input[type="date"]::-webkit-date-and-time-value,
.row--options input[type="time"]::-webkit-date-and-time-value {
  text-align: left;
  margin: 0;
  min-width: 0;
}

.row--options input[type="date"]::-webkit-datetime-edit,
.row--options input[type="time"]::-webkit-datetime-edit {
  padding: 0;
  /* Bei sehr großer Systemschrift lieber die Jahreszahl anschneiden als
     das Nachbarfeld überdecken. */
  overflow: hidden;
}

/* Das System-Symbol weg — es bringt seine eigene Breite mit. Das Feld
   bleibt antippbar, der Picker öffnet sich weiterhin auf Tippen. */
.row--options input[type="date"]::-webkit-calendar-picker-indicator,
.row--options input[type="time"]::-webkit-calendar-picker-indicator {
  position: absolute;
  right: 0;
  width: 2rem;
  height: 100%;
  padding: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.row--options .field--date,
.row--options .field { position: relative; }

/* Kalender und Uhr als eingebettetes SVG, in der Farbe des Feldtextes.
   Zwei Varianten, weil die Farbe im Datei-URI steht und sich nicht per
   `currentColor` steuern lässt. */
.row--options input[type="date"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b93a7' stroke-width='2' stroke-linecap='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M3 10h18M8 3v4M16 3v4'/%3E%3C/svg%3E");
}

.row--options input[type="time"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b93a7' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E");
}

/* --- Telefone -------------------------------------------------------
   Ziele: keine horizontale Scrollleiste, Touch-Flächen ab 44 px und
   Eingabefelder mit mindestens 16 px, damit iOS beim Fokus nicht
   hineinzoomt.
   ------------------------------------------------------------------- */

@media (max-width: 640px) {
  .wrap { padding: 1rem 0.75rem 3rem; }

  /* position: relative als Anker für den Design-Umschalter, siehe unten. */
  .page-head { position: relative; flex-direction: column; gap: 0.75rem; margin-bottom: 1rem; }
  .page-head h1 { font-size: 1.35rem; }
  .sub { font-size: 0.85rem; }

  .modes { width: 100%; }
  .mode-btn { flex: 1; align-items: center; min-height: 48px; justify-content: center; }
  .mode-btn small { font-size: 0.64rem; }

  .page-head__ctl { width: 100%; }

  /* Der Design-Umschalter gehört auf dem Telefon nach oben rechts, auf die
     Höhe des "Hauptseite"-Knopfes - die beiden bilden dann zusammen die
     Kopfzeile. Im DOM steht er bei den Modus-Knöpfen, weil er auf dem
     Desktop dorthin gehört; hier wird er deshalb aus dem Fluss genommen.

     Der Anker ist die obere rechte Ecke der Kopfzeile, also genau die Zeile
     des Zurück-Knopfes - keine zusammengerechnete Position. Damit beide
     bündig stehen, ist der Knopf so hoch wie dessen `min-height`. */
  .theme-toggle {
    --size: 44px;
    position: absolute;
    top: 0;
    right: 0;
  }

  /* Ohne den Umschalter im Fluss bekommen die Modus-Knöpfe die volle
     Breite der Zeile. */
  .page-head__ctl .modes { flex: 1 1 100%; }

  .panel { padding: 0.9rem; border-radius: var(--radius-sm); }

  /* Eingaben untereinander statt gequetscht nebeneinander */
  .row { gap: 0.6rem; margin-bottom: 0.7rem; }

  .field--grow { flex: 1 1 100%; }

  /* Die Optionszeile als festes Zweispalten-Raster statt Flexbox mit
     Inhaltsbreite. Vorher bestimmte der längste Optionstext die Feldbreite;
     bei größerer Schrift oder ausgefallener Systemschrift schoben sich
     Beschriftung und Nachbarfeld dadurch ineinander. Feste Spalten können
     das nicht, egal wie lang der Text wird. */
  /*
   * Datum und Uhrzeit nebeneinander — das Datum etwas breiter.
   *
   * Sie gehören zusammen und werden zusammen gelesen ("Montag um acht"),
   * deshalb stehen sie in einer Zeile. Gleich breit dürfen sie dabei nicht
   * sein: ein natives Datumsfeld will bei 16 px Schrift rund 165 px,
   * die Uhrzeit kommt mit 127 aus. Zwei gleiche Spalten geben beiden 154 px
   * — das Datum lief über, die Uhrzeit stand halb leer da.
   *
   * Die Spalten sind ausdrücklich als `minmax(0, …)` geschrieben. Ein bloßes
   * `1.3fr` heißt in Wahrheit `minmax(auto, 1.3fr)`, und dieses `auto` ist
   * die INHALTSBREITE: ein Systemsteuerelement, das breiter sein will, zieht
   * seine Spalte auf und schiebt das Raster über den Panelrand. Mit der
   * Null als Untergrenze kann das nicht passieren.
   */
  .row--options {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: 0.7rem 0.5rem;
  }

  /* Etwas flacher und links ausgerichtet — die Felder wirkten sonst wie
     halbleere Kacheln. 44 px bleiben als Touch-Fläche erhalten. */
  .row--options select {
    min-height: 44px;
    padding: 0.5rem 0.55rem;
    text-align: left;
  }

  /* Datum und Uhrzeit behalten ihren rechten Rand fürs Symbol — sonst
     überschriebe die Kurzschreibweise oben ihn wieder weg. */
  .row--options input[type="date"],
  .row--options input[type="time"] {
    min-height: 44px;
    padding: 0.5rem 2rem 0.5rem 0.55rem;
    text-align: left;
  }

  /* Ganze Breite für alles, was sonst zu eng wird. */
  .row--options .field--wide { grid-column: 1 / -1; }

  /* Im Raster richtet align-items die Zeilen aus - der Ausgleich, der die
     Checkbox in der Flexbox auf die Höhe der Eingabefelder gezogen hat,
     würde sie hier nach unten verschieben. */
  .row--options .field--check { padding-bottom: 0; }

  /* "als Ankunftszeit" bekommt ebenfalls die ganze Breite: als Kästchen mit
     Beschriftung braucht es keine Spalte für sich, und in der halben lief
     der Text je nach Schrift um. */
  .row--options .field--check { grid-column: 1 / -1; }
  .row--options .check { white-space: normal; align-items: center; }

  input[type="text"], input[type="date"], input[type="time"],
  input[type="number"], select {
    font-size: 16px;      /* verhindert den Auto-Zoom in Safari */
    padding: 0.7rem 0.75rem;
    min-height: 46px;
  }



  /* Der Umkehrknopf steht auf dem Telefon rechts neben den beiden
     Eingabefeldern, auf Höhe der Lücke dazwischen.

     Vorher lag er absolut positioniert über dem Feld, mit einer aus
     Beschriftungs- und Feldhöhe zusammengerechneten Position
     (`top: calc(50% + 0.55rem)`). Diese Rechnung stimmt nur bei genau
     einer Schriftgröße — bei größerer Systemschrift oder umgebrochenem
     Label saß der Knopf schief im Feld. Als eigene Rasterspalte, die
     über beide Zeilen geht, ergibt sich die Mitte von selbst und kann
     nicht mehr verrutschen. */
  .row--stations {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "from swap"
      "to   swap";
    align-items: end;
    column-gap: 0.5rem;
  }

  .row--stations > .field:nth-of-type(1) { grid-area: from; }
  .row--stations > .field:nth-of-type(2) { grid-area: to; }

  .swap {
    grid-area: swap;
    /* Über beide Zeilen zentriert = genau in der Lücke zwischen "Von" und
       "Nach", unabhängig davon, wie hoch die Felder tatsächlich sind. */
    align-self: center;
    width: 44px;
    height: 44px;
    margin: 0;
    /* Felder stehen übereinander: der Pfeil zeigt auf und ab, die Drehung
       aus der Desktop-Regel wird zurückgenommen. */
    transform: none;
    box-shadow: var(--shadow-sm);
  }

  .check { min-height: 44px; }
  input[type="checkbox"] { width: 20px; height: 20px; }
  .back { min-height: 44px; padding: 0.5rem 0.8rem; font-size: 0.82rem; }

  .btn { min-height: 48px; width: 100%; justify-content: center; }
  .actions { flex-direction: column; align-items: stretch; gap: 0.6rem; }
  .status { text-align: center; }

  .ac { max-height: 240px; }
  .ac__item { min-height: 44px; }

  /* Abos und Verkehrsmittel einspaltig */
  .abos { flex-direction: column; gap: 0.5rem; }
  .abo-group { flex: 1 1 auto; }
  .abo { min-height: 44px; }
  .abo__note { padding-left: 1.6rem; }
  .products { grid-template-columns: 1fr; }
  .product { min-height: 44px; }
  .product__hint { display: none; }   /* Platz sparen, steht im Titel */

  .model__ctl { gap: 0.5rem; }
  .model__value { min-width: 74px; font-size: 0.66rem; }
  .model__ctl input[type="range"] { min-height: 40px; }

  /* Ergebnisse */
  .results-bar { gap: 0.35rem; }
  /* Volle Zeilenbreite statt Inhaltsbreite: als Touch-Ziel darf das Menü
     nicht auf die Länge von "Empfehlung" zusammenschrumpfen. 16 px, weil
     Safari sonst beim Antippen in das Feld hineinzoomt - dieselbe Regel wie
     bei den Formularfeldern, die die spezifischere Auswahl hier sonst
     überschreiben würde. */
  .results-bar select { width: 100%; min-height: 44px; font-size: 16px; }
  .results-bar__note { flex-basis: 100%; }

  .journey { padding: 0.85rem; }
  /* Auf dem Telefon Zeiten und Preis strikt untereinander. Nebeneinander
     wird es bei langen Preisen ("ca. 85,87–156,12 €") zu eng und die
     Blöcke schieben sich ineinander. */
  .journey__head { flex-direction: column; align-items: stretch; gap: 0.5rem; }
  .journey__main { flex: 1 1 auto; width: 100%; }
  .journey__time { font-size: 1.3rem; }
  .journey__times { gap: 0.5rem; }
  .journey__meta { gap: 0.7rem; font-size: 0.78rem; }

  .journey__price-box {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    width: 100%;
    margin-left: 0;
    padding-top: 0.4rem;
    border-top: 1px solid var(--border);
    text-align: left;
  }

  .journey__price { font-size: 1.05rem; }
  /* Gegenwert in der anderen Währung: deutlich kleiner als der Preis, damit
   klar bleibt, was der verbindliche Wert ist. */
.journey__price-alt {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  cursor: help;
}

.journey__price-label { margin-left: auto; text-align: right; }

  .chain { gap: 0.25rem; }
  .chip { font-size: 0.72rem; padding: 0.15rem 0.4rem; }

  .legs { padding-left: 0.7rem; }
  .leg__stops { gap: 0.2rem; }

  .shops__link { flex: 1 1 auto; justify-content: center; min-height: 44px; }

  /* Karte höher, weil auf dem Telefon vertikal mehr Platz ist */
  .map { padding: 0.4rem; }
  .map__viewport { height: 380px; }
  .map__label { font-size: 9px; }
  .map__btn { width: 40px; height: 40px; }
  .map-bar { gap: 0.5rem; }

  /* Bestpreis-Balken bleiben nebeneinander, werden aber schmaler */
  .bp { padding: 0.7rem; }
  .bp__bars { gap: 0.2rem; }
  .bp__price { font-size: 0.72rem; }
  .bp__time { font-size: 0.6rem; }
  .bp__bar { padding: 0.4rem 0.1rem 0.3rem; }
}

@media (max-width: 380px) {
  .journey__time { font-size: 1.05rem; }
  .journey__times { gap: 0.35rem; }
  .badge { font-size: 0.64rem; }
}

/* --- Sehr schmale Telefone ------------------------------------------
   Ab hier ist für Datum und Uhrzeit nebeneinander kein Platz mehr: das
   Panel ist innen keine 300 px breit, und schon das Datumsfeld allein
   braucht bei 16 px Schrift rund 165 davon. Es bekommt deshalb eine eigene
   Zeile — dort kann es nicht überlaufen, egal wie groß die Systemschrift
   eingestellt ist. Uhrzeit und Klasse rücken zusammen.

   360 px und nicht 380: die verbreiteten Telefongrössen liegen bei 375 und
   390 px, und dort passen beide Felder nebeneinander noch bequem. Bei 380
   als Grenze hätte ausgerechnet das iPhone die Ausnahme bekommen.
   ------------------------------------------------------------------- */
@media (max-width: 360px) {
  .row--options { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .row--options .field--date { grid-column: 1 / -1; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
