/*
 * Design-System von verkehrslage.de
 *
 * Handgeschrieben und ohne Build-Schritt. Der Grund ist eine
 * Abhängigkeitsentscheidung: das Aussehen der Seiten darf nicht davon
 * abhängen, dass jemand vorher npm ausgeführt hat. Die Templates liegen in Go,
 * und ein Utility-Framework würde bei jeder Templateänderung einen
 * CSS-Neubau erfordern – sonst fehlen Klassen stillschweigend.
 *
 * Mobile-first: alle Grundregeln gelten für kleine Bildschirme, Erweiterungen
 * stehen in Media-Queries. Es gibt genau zwei Sprungpunkte, und sie sind an
 * den Inhalt gebunden, nicht an Gerätenamen:
 *
 *   ab 62rem  Inhalt und Kontextspalte liegen nebeneinander (zwei Spalten),
 *             der Schnellzugriff bleibt ein Streifen über beiden.
 *   ab 82rem  der Schnellzugriff wird zur linken Spalte (drei Spalten).
 *
 * Unter 62rem ist alles eine Spalte, und der Schnellzugriff ist ein waagrecht
 * schiebbarer Streifen – auf einem Telefon die einzige Form, in der neun
 * Meldungsarten erreichbar bleiben, ohne die Seite zu verlängern.
 *
 * Aufbau: 1. Tokens  2. Grundlagen  3. Kopf und Fuß  4. Dreispaltiges Gerüst
 *         5. Bausteine  6. Die Bildsprache  7. Karte  8. Betrieb
 *         9. Bewegung und Druck
 *
 * Das Farbbild: Schiefer (D-096). Grundton Graphit, Handlung Kiefer, dazu
 * die Statusfarben der Meldungsarten und eine vierstufige Reihe für den
 * Lagewert. Alle Werte stehen in den Tokens; kein Farbwert steht weiter unten
 * im Stylesheet, und keiner steht in einer Vorlage.
 */

/* ------------------------------------------------------------ 1. Tokens */

:root {
  /* Farben. Schiefer: Graphit ist die Website, Kiefer die Handlung, Kupfer
     die Ausnahme. Rot, Bernstein, Braun und leuchtendes Blau bleiben den
     Meldungsarten. Die Bedienung darf mit einer Meldung nicht verwechselt
     werden (D-096, docs/design.md).

     Grün heißt nicht frei. Kiefer ist nur Interaktion – Link, aktiver
     Schalter, Lupe – und grauer als die Panne. Die Rolle „ruhig" trägt
     Graphit, die Markenfarbe selbst. */
  --c-bg: #f3f4f2;
  --c-surface: #ffffff;
  --c-surface-2: #eaeeeb;
  --c-surface-3: #dde3df;
  --c-text: #1a1f1c;
  --c-muted: #5c6560;
  --c-border: #d8ddd9;
  --c-border-strong: #b4bcb6;

  --c-primary: #2c3545;
  --c-primary-strong: #1a212c;
  --c-primary-soft: #e8ecf0;
  --c-accent: #1f6b63;
  --c-accent-strong: #15564f;
  --c-accent-soft: #e3f2ef;

  /* Der Fokusring liegt bewusst außerhalb der Marke. Gold sitzt wegen
     outline-offset immer auf der Seitenfläche und nie auf dem Bedienelement.
     Mit einer Meldungsart ist es nicht zu verwechseln – die bernsteinfarbene
     Baustelle ist dunkler und steht nie als Ring um einen Schalter. */
  --c-focus: #d97706;

  /* Statusfarben je Meldungsart. Sie sind die einzige Stelle, an der die
     Zuordnung von Meldungsart zu Farbe festgelegt ist. Die Töne sind über den
     Farbkreis verteilt und nicht nur nach Helligkeit gestuft, damit sie auch
     bei Farbfehlsichtigkeit auseinandergehalten werden können.

     Geisterfahrer ist Wein, nicht mehr Magenta. Die Panne ist See, nicht
     Kiefer. Blitzer bleibt klares Blau, VWD Stahl – beide weg vom Graphit. */
  --c-tailback: #c81e1e;
  --c-roadworks: #c26a12;
  --c-accident: #b01040;
  --c-slippery: #8b7310;
  --c-view: #64748b;
  --c-objects: #8b5e34;
  --c-wrongway: #9d174d;
  --c-closure: #7f1d1d;
  --c-camera: #1864ab;
  --c-cluster: #475569;
  --c-vwd: #3d4f6f;

  /* Pannenfahrzeuge. Seeblau, damit die Handlung (Kiefer) und die Störung
     auseinanderliegen. Dunkel gehalten, damit es nicht als „freie Fahrt"
     gelesen wird. */
  --c-breakdown: #0e7490;

  /* Die vier Stufen des Lagewerts. Eigene Reihe, keine Meldungsfarbe als
     „ruhig". Kühl nach warm: Graphit, Stahl, Kupfer, Karmin. */
  --c-level-good: #2c3545;
  --c-level-normal: #3d5a80;
  --c-level-busy: #c45c26;
  --c-level-bad: #c0272d;

  /* Vorläufiger Ländertacho, solange zwei Vergleichswochen fehlen:
     Anteil am Höchststand, drei Bänder. */
  --c-peak-low: #2f8a4e;
  --c-peak-mid: #c9a227;
  --c-peak-high: #c0272d;

  /* Verläufe. Stein nach Kiefer, auf den wenigen Flächen der Marke:
     Markenzeichen, Kopfband, aktive Schalter. Der Schimmer und die Aurora
     bleiben so schwach, dass Text darauf seinen Kontrast behält. */
  --grad-brand: linear-gradient(118deg, #1a212c 0%, #2c3545 48%, #1f6b63 100%);
  --grad-tint: linear-gradient(150deg, rgb(44 53 69 / 7%) 0%, rgb(31 107 99 / 6%) 55%, rgb(255 255 255 / 0%) 100%);
  --grad-aurora:
    radial-gradient(62rem 24rem at 10% -8rem, rgb(31 107 99 / 10%), transparent 70%),
    radial-gradient(48rem 20rem at 88% -6rem, rgb(196 92 38 / 7%), transparent 70%);

  /* Abstände auf einer Vierer-Stufung. */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;

  /* Schriftgrößen wachsen mit dem Viewport, bleiben aber begrenzt. */
  --t-small: 0.8125rem;
  --t-body: 1rem;
  --t-lead: clamp(1.0625rem, 1rem + 0.4vw, 1.1875rem);
  --t-h3: clamp(1.0625rem, 1rem + 0.5vw, 1.25rem);
  --t-h2: clamp(1.1875rem, 1.05rem + 0.9vw, 1.5rem);
  --t-h1: clamp(1.5rem, 1.2rem + 2.2vw, 2.375rem);

  --radius: 0.875rem;
  --radius-sm: 0.5rem;
  --radius-lg: 1.375rem;
  --radius-pill: 999px;

  /* Schatten mit Farbstich statt reinem Schwarz: reines Schwarz wirkt auf
     dem steingrauen Grund schmutzig. Der Stich folgt der Tinte.

     Der Markenschatten liegt unter den Schaltflächen: eine Kiefer-Pille
     wirft kiefernes Licht. Ohne ihn sieht ein farbiger Knopf auf hellem Grund
     ausgeschnitten aus. */
  --shadow-sm: 0 1px 2px rgb(26 31 28 / 6%);
  --shadow: 0 1px 2px rgb(26 31 28 / 5%), 0 6px 18px -6px rgb(26 31 28 / 14%);
  --shadow-lg: 0 2px 4px rgb(26 31 28 / 7%), 0 18px 40px -12px rgb(26 31 28 / 22%);
  --shadow-brand: 0 8px 20px -8px rgb(31 107 99 / 40%);

  /* Breiten. Die Hülle ist so bemessen, dass bei drei Spalten die Mittelspalte
     noch etwa 50rem behält – die Breite, in der Meldungslisten lesbar sind. */
  --w-shell: 92rem;
  --w-prose: 44rem;
  --w-rail: 15rem;
  --w-aside: 20rem;
  --w-admin-nav: 15.25rem;

  /* Höhe der Kopfzeile. Die klebenden Seitenspalten brauchen sie als Abstand
     nach oben; ohne diesen Wert verschwinden ihre Überschriften darunter. */
  --h-header: 3.75rem;

  /* Systemschrift statt einer nachgeladenen Datei. Keine Einbindung von
     Google Fonts: das überträgt bei jedem Seitenaufruf die IP-Adresse des
     Besuchers an einen Dritten. */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
}

/* Dunkelmodus. Von Anfang an vorgesehen, weil die Karte ohnehin zwei
   Kachelvarianten braucht. Die Statusfarben werden nicht nur aufgehellt,
   sondern entsättigt: volle Sättigung flimmert auf dunklem Grund. */
@media (prefers-color-scheme: dark) {
  :root {
    --c-bg: #0e1110;
    --c-surface: #161a19;
    --c-surface-2: #1c2220;
    --c-surface-3: #262d2a;
    --c-text: #e7ebe8;
    --c-muted: #9aa39d;
    --c-border: #2a322f;
    --c-border-strong: #3d4843;

    --c-primary: #8eb8b2;
    --c-primary-strong: #c5ddd9;
    --c-primary-soft: #1a2e2c;
    --c-accent: #e08a58;
    --c-accent-strong: #f0b08a;
    --c-accent-soft: #3a2418;
    --c-focus: #fbbf24;

    --c-tailback: #f87171;
    --c-roadworks: #f0a850;
    --c-accident: #fb7185;
    --c-slippery: #dcbb4d;
    --c-view: #a7b0cd;
    --c-objects: #d0a476;
    --c-wrongway: #e879a9;
    --c-closure: #f87171;
    --c-camera: #6aa8f5;
    --c-cluster: #aab2d0;
    --c-vwd: #9aa4cf;
    --c-breakdown: #5ccfe0;

    --c-level-good: #c5cdd6;
    --c-level-normal: #8eadd4;
    --c-level-busy: #f0a070;
    --c-level-bad: #f87171;

    --c-peak-low: #4ade80;
    --c-peak-mid: #fbbf24;
    --c-peak-high: #f87171;

    /* Der Verlauf wird dunkler, nicht heller: Auf schwarzem Grund ist ein
       Markenzeichen in den hellen Tönen des Tagmodus ein Scheinwerfer. */
    --grad-brand: linear-gradient(118deg, #12171a 0%, #243038 48%, #15564f 100%);
    --grad-tint: linear-gradient(150deg, rgb(142 184 178 / 12%) 0%, rgb(224 138 88 / 8%) 55%, rgb(255 255 255 / 0%) 100%);
    --grad-aurora:
      radial-gradient(62rem 24rem at 10% -8rem, rgb(31 107 99 / 22%), transparent 70%),
      radial-gradient(48rem 20rem at 88% -6rem, rgb(196 92 38 / 16%), transparent 70%);

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 30%);
    --shadow: 0 1px 2px rgb(0 0 0 / 28%), 0 6px 18px -6px rgb(0 0 0 / 45%);
    --shadow-lg: 0 2px 4px rgb(0 0 0 / 30%), 0 18px 40px -12px rgb(0 0 0 / 55%);
    --shadow-brand: 0 8px 22px -10px rgb(31 107 99 / 55%);
  }
}

/* ------------------------------------------------------------ 2. Grundlagen */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font);
  font-size: var(--t-body);
  line-height: 1.6;
  text-wrap: pretty;
  /* Zwei weiche Farbwolken am oberen Rand, eine kiefer, eine kupfer. Sie
     binden die Kopfzeile an den Seitenkörper und geben der Seite ihre Farbe,
     ohne eine Fläche zu setzen, die den Inhalt verdrängt: Sie enden vor dem
     ersten Absatz, und jede Karte darüber liegt in ihrer eigenen weißen
     Fläche. */
  background-image: var(--grad-aurora);
  background-repeat: no-repeat;
  background-size: 100% 34rem;
}

h1,
h2,
h3 {
  margin: 0 0 var(--s-3);
  line-height: 1.2;
  text-wrap: balance;
  font-weight: 650;
}

h1 {
  font-size: var(--t-h1);
  letter-spacing: -0.02em;
}

h2 {
  font-size: var(--t-h2);
  letter-spacing: -0.01em;
}

h3 {
  font-size: var(--t-h3);
}

p {
  margin: 0 0 var(--s-4);
}

a {
  color: var(--c-primary);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

a:hover {
  color: var(--c-primary-strong);
}

/* Ein sichtbarer Fokusring in einer Kontrastfarbe. Das alte Theme entfernte
   den Fokus per outline: none, was Tastaturbedienung unmöglich machte. */
:focus-visible {
  outline: 3px solid var(--c-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

code {
  font-family: var(--font-num);
  font-size: 0.9em;
  padding: 0.1em 0.35em;
  border-radius: var(--radius-sm);
  background: var(--c-surface-2);
  overflow-wrap: anywhere;
}

time {
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
}

ul,
ol {
  margin: 0 0 var(--s-4);
  padding-left: var(--s-5);
}

.skiplink {
  position: absolute;
  left: -9999px;
  z-index: 100;
  padding: var(--s-2) var(--s-4);
  background: var(--c-primary);
  color: #fff;
  border-radius: 0 0 var(--radius) 0;
}

.skiplink:focus {
  left: 0;
  top: 0;
}

/* Text nur für Screenreader. Nicht display:none, weil der Inhalt dann auch
   dort verschwindet: die Beschriftung der Kartenlegende ist für Sehende durch
   die Anordnung erkennbar, für andere nur durch diesen Text. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.hint,
.meta {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.lead {
  font-size: var(--t-lead);
  color: var(--c-muted);
  max-width: var(--w-prose);
}

.button {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  border-radius: var(--radius-pill);
  background-image: var(--grad-brand);
  color: #fff;
  font-weight: 600;
  text-decoration: none;
  box-shadow: var(--shadow-brand);
  transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease;
}

.button:hover {
  color: #fff;
  filter: saturate(1.08) brightness(1.06);
  transform: translateY(-1px);
}

/* ------------------------------------------------------------ 3. Kopf und Fuß */

.site-header {
  position: relative;
  /* Nebelgraphit, nicht das Weiß der Karten. Kiefer sitzt in Wortmarke,
     Navigation und Band – nicht noch einmal als Flächenstich, sonst wird
     der Kopf nachts kupferbraun. */
  background-color: color-mix(in srgb, var(--c-primary-soft) 82%, var(--c-surface));
  background-image: var(--grad-tint);
  border-bottom: 1px solid var(--c-border);
  z-index: 30;
}

/* Die Kopfzeile klebt erst, wenn sie nur eine Zeile hoch ist. Auf dem Telefon
   steht das Suchfeld unter der Marke; klebend nähme das zwei Zeilen Höhe
   dauerhaft vom Bildschirm. */
@media (min-width: 62rem) {
  .site-header {
    position: sticky;
    top: 0;
    background-color: color-mix(in srgb, var(--c-primary-soft) 55%, transparent);
    background-image: var(--grad-tint);
    backdrop-filter: blur(14px) saturate(140%);
  }
}

/* Das Verlaufsband trägt Graphit nach Kiefer. Drei Pixel, volle Deckkraft:
   eine Haarlinie verschluckt den Kieferanteil. */
.site-header::after {
  content: "";
  position: absolute;
  inset: auto 0 -1px;
  height: 3px;
  background-image: var(--grad-brand);
}

/* Marke, Suche und Navigation liegen in benannten Feldern. Damit bestimmt das
   Raster die Anordnung, und die Dokumentreihenfolge kann der Leserichtung auf
   dem großen Bildschirm folgen: Marke, Suche, Navigation. */
.site-header__inner {
  max-width: var(--w-shell);
  margin: 0 auto;
  padding: var(--s-3) var(--s-4);
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "brand nav"
    "search search";
  gap: var(--s-3) var(--s-5);
  align-items: center;
}

.brand {
  grid-area: brand;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 700;
  font-size: 1.125rem;
  color: var(--c-primary);
  text-decoration: none;
  letter-spacing: -0.02em;
}

.brand:hover {
  color: var(--c-primary-strong);
}

.brand__mark {
  width: 2rem;
  height: 2rem;
  padding: 0.25rem;
  flex: none;
  border-radius: 0.55rem;
  background-image: var(--grad-brand);
  color: #fff;
  box-shadow: var(--shadow-brand);
}

.brand__tld {
  color: var(--c-accent);
  font-weight: 600;
}

.mainnav {
  grid-area: nav;
}

.mainnav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.mainnav a {
  display: block;
  padding: var(--s-1) 0;
  color: var(--c-muted);
  text-decoration: none;
  font-weight: 550;
  font-size: var(--t-small);
  border-bottom: 2px solid transparent;
}

.mainnav a:hover {
  color: var(--c-primary);
}

.mainnav a[aria-current="page"] {
  color: var(--c-accent);
  border-bottom-color: var(--c-accent);
}

/* „Mein Radar" ist der einzige Eintrag, der nicht ins Lagebild führt, sondern
   in den persönlichen Bereich. Er steht deshalb abgesetzt am Ende – die
   Navigation soll die beiden Adressräume zeigen und nicht verwischen. */
.mainnav__radar {
  color: var(--c-accent);
}

.mainnav__radar:hover {
  color: var(--c-accent-strong);
}

@media (min-width: 62rem) {
  .mainnav li:last-child {
    margin-left: auto;
    padding-left: var(--s-4);
    border-left: 1px solid var(--c-border);
  }
}

/* Die Suche im Kopf ist auf jeder Seite erreichbar. Sie ersetzt damit die
   Suchblöcke, die vorher in den Seitenkörper eingestreut waren – und die es
   in mehrfacher Ausführung auf einer Seite gab. */
.site-header__search {
  grid-area: search;
  min-width: 0;
}

.site-header__search .search {
  margin: 0;
  max-width: none;
}

.site-header__search .search__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (min-width: 62rem) {
  .site-header__inner {
    grid-template-columns: auto minmax(12rem, 26rem) 1fr;
    grid-template-areas: "brand search nav";
  }

  .mainnav {
    justify-self: end;
  }

  .mainnav a {
    font-size: var(--t-body);
  }
}

/* Der Fuß trägt oben dasselbe Verlaufsband wie die Kopfzeile unten. Damit ist
   der Seitenkörper zwischen zwei Markenkanten eingespannt, und der Fuß ist
   nicht bloß der Ort, an dem die Seite aufhört. */
.site-footer {
  position: relative;
  border-top: 1px solid var(--c-border);
  background: var(--c-surface);
  margin-top: var(--s-7);
}

.site-footer::before {
  content: "";
  position: absolute;
  inset: -1px 0 auto;
  height: 2px;
  background-image: var(--grad-brand);
  opacity: 0.85;
}

.site-footer__inner {
  max-width: var(--w-shell);
  margin: 0 auto;
  padding: var(--s-6) var(--s-4);
  display: grid;
  gap: var(--s-4);
  color: var(--c-muted);
  font-size: var(--t-small);
}

.site-footer__note {
  max-width: var(--w-prose);
  margin: 0;
}

.site-footer__nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__places {
  display: grid;
  gap: var(--s-2);
}

.site-footer__title {
  margin: var(--s-2) 0 0;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-muted);
}

.site-footer__meta {
  margin: 0;
}

/* Hinweis auf veraltete oder unvollständige Daten. Das Altsystem lieferte in
   diesem Fall stillschweigend eine lückenhafte Seite. */
.notice {
  max-width: var(--w-shell);
  margin: var(--s-4) auto 0;
  padding: var(--s-3) var(--s-4);
  border: 1px solid color-mix(in srgb, var(--c-roadworks) 35%, var(--c-border));
  border-left: 4px solid var(--c-roadworks);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-text);
  font-size: var(--t-small);
  box-shadow: var(--shadow-sm);
}

@media (min-width: 62rem) {
  .notice {
    margin-inline: var(--s-5);
    max-width: calc(var(--w-shell) - 2 * var(--s-5));
  }
}

.notice--inline {
  margin: 0 0 var(--s-5);
  max-width: none;
}

/* ------------------------------------------------------- 4. Dreispaltiges Gerüst */

/* Die Seite hat genau einen Scrollbalken, den des Dokuments.
 *
 * Die beiden Seitenspalten klebten zuvor am Kopf und brachten je einen eigenen
 * Scrollbereich mit. Das las sich in der Beschreibung gut – der Schnellzugriff
 * bleibt in Reichweite – und wirkte im Gebrauch unruhig: Drei Flächen, die
 * unterschiedlich schnell laufen, zerlegen die Seite optisch in drei Seiten,
 * und wo der Zeiger gerade steht, entscheidet darüber, was das Mausrad bewegt.
 *
 * Die Spalten sind deshalb gewöhnliche Rasterfelder. Sie laufen mit, enden wo
 * ihr Inhalt endet, und die verbleibende Fläche bleibt leer. Das kostet in der
 * dreispaltigen Ansicht etwas Weißraum unter den kürzeren Spalten und ist der
 * Preis dafür, dass sich die Seite als ein Stück bewegt. */
.layout {
  max-width: var(--w-shell);
  margin: 0 auto;
  padding: var(--s-4) var(--s-4) var(--s-7);
  display: grid;
  gap: var(--s-5);
  align-items: start;
}

.layout__main {
  min-width: 0;
}

.layout__rail,
.layout__aside {
  min-width: 0;
}

@media (min-width: 62rem) {
  .layout {
    padding-inline: var(--s-5);
    grid-template-columns: minmax(0, 1fr) var(--w-aside);
  }

  /* Zwei Spalten: der Schnellzugriff bleibt ein Streifen über beiden, damit
     die Kontextspalte neben dem Inhalt die volle Höhe behält. */
  .layout__rail {
    grid-column: 1 / -1;
  }
}

@media (min-width: 82rem) {
  .layout {
    grid-template-columns: var(--w-rail) minmax(0, 1fr) var(--w-aside);
  }

  .layout__rail {
    grid-column: auto;
  }
}

/* Schnellzugriff. Unter 82rem ein waagrechter Streifen, darüber eine Spalte.
   Der Streifen ist die einzige Form, in der neun Meldungsarten auf einem
   Telefon erreichbar bleiben, ohne die Seite um einen Block zu verlängern. */
.rail {
  display: grid;
  gap: var(--s-4);
}

.rail__group {
  min-width: 0;
}

.rail__title {
  margin: 0 0 var(--s-2);
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-muted);
}

.rail__title:has(+ .rail__scope) {
  margin-bottom: 0.15em;
}

.rail__scope {
  margin: 0 0 var(--s-2);
  font-size: var(--t-small);
  font-weight: 450;
  line-height: 1.35;
  color: var(--c-muted);
}

.rail__list {
  display: flex;
  gap: var(--s-2);
  margin: 0;
  padding: 0 0 var(--s-1);
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  /* Die Kanten sollen sichtbar anreißen, dass es weitergeht. */
  scroll-snap-type: x proximity;
}

.rail__list > li {
  flex: none;
  scroll-snap-align: start;
}

/* Gruppen, die nur als Spalte Sinn haben: als Streifen wären es drei
   Schiebeleisten übereinander. Ihre Ziele stehen auf den Seiten selbst und im
   Fuß, es geht kein Weg verloren. */
.rail__group--wide {
  display: none;
}

@media (min-width: 82rem) {
  .rail__group--wide {
    display: block;
  }

  .rail__title {
    margin-bottom: var(--s-1);
  }

  .rail__scope {
    margin-bottom: var(--s-1);
  }

  .rail__list {
    display: grid;
    gap: var(--s-1);
    overflow: visible;
  }

  .rail__list > li {
    scroll-snap-align: none;
  }

  /* In der Spalte werden aus Pillen Zeilen: eine senkrechte Liste ist auf
     einen Blick zu überfliegen, gestapelte Pillen sind es nicht. */
  .rail__list .chip {
    width: 100%;
    justify-content: flex-start;
    border-color: transparent;
    background: none;
    border-radius: var(--radius-sm);
    /* Enger als eine Pille: die Spalte soll ohne eigenen Rollbalken in ein
       Fenster von 900 Pixeln Höhe passen. Ein Mauszeiger braucht nicht die
       44 Pixel, die eine Fingerspitze braucht. */
    padding: 0.375rem var(--s-2);
    box-shadow: none;
  }

  .rail__list .chip:hover {
    background: var(--c-surface);
    border-color: var(--c-border);
  }

  /* In der Spalte ist der aktive Eintrag eine getönte Zeile in der Farbe
     seiner Meldungsart. Der Verlauf der Pillenform bleibt dem Streifen
     überlassen: neun eingefärbte Zeilen mit weißer Schrift übereinander wären
     eine Farbtafel und keine Liste. */
  .rail__list .chip--active {
    background: color-mix(in srgb, var(--c-type, var(--c-primary)) 12%, var(--c-surface));
    border-color: transparent;
    color: var(--c-type, var(--c-primary-strong));
  }

  .rail__list .chip--active .icon {
    color: var(--c-type, var(--c-primary-strong));
  }

  /* Ohne diese Zeilen gewinnt .chip--active:hover (weiße Schrift) über die
     Spaltenfarbe, während .rail__list .chip:hover den Grund auf die Fläche
     setzt – weiße Schrift auf hellem Grund, die Zeile ist weg. */
  .rail__list .chip--active:hover {
    background: color-mix(in srgb, var(--c-type, var(--c-primary)) 18%, var(--c-surface));
    border-color: transparent;
    color: var(--c-type, var(--c-primary-strong));
  }

  .rail__list .chip--active:hover .icon {
    color: var(--c-type, var(--c-primary-strong));
  }
}

/* Kontextspalte. Sie trägt, was zur Seite gehört, aber nicht ihr Gegenstand
   ist: Staustufen neben der Karte, Nachbarorte, Angaben zur Meldung. */
.aside {
  display: grid;
  gap: var(--s-4);
}

.panel {
  padding: var(--s-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.panel__title {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-3);
  font-size: var(--t-body);
  font-weight: 650;
}

.panel__title::before {
  content: "";
  width: 0.25rem;
  align-self: stretch;
  min-height: 1.1em;
  border-radius: var(--radius-pill);
  background-image: var(--grad-brand);
}

.panel__title:has(+ .panel__scope) {
  margin-bottom: 0.15em;
}

.panel__scope {
  margin: 0 0 var(--s-3);
  font-size: var(--t-small);
  font-weight: 450;
  color: var(--c-muted);
}

.panel > :last-child {
  margin-bottom: 0;
}

/* ------------------------------------------------------------ 5. Bausteine */

/* Die Farbe einer Meldungsart.
 *
 * Sie erscheint an fünf Stellen: als Kante der Meldungskarte, als Balken in
 * der Aufteilung nach Art, als Symbol im Schnellzugriff, als Pille der
 * Kartenlegende und als Linie eines Stauverlaufs.
 *
 * Die Marker der Karte stehen nicht mehr darunter: sie sind Zeichnungen mit
 * eigenen Farben (D-063). Die Pille der Legende trägt beides – die Zeichnung
 * als Bild und die Farbe der Art als Rand und Grund.
 *
 * Die Zuordnung steht deshalb genau einmal hier und wird von dort über
 * --c-type weitergegeben. Vorher stand sie je Darstellung erneut, und jede
 * neue Darstellung war eine weitere Liste von zehn Farbwerten, die man beim
 * Ändern übersehen kann.
 *
 * Die Namen sind die Symbolnamen der Typtabelle in Go (LegendIcon). Damit
 * benutzen Vorlage, Island und Stylesheet denselben Bezeichner, und ein Typ,
 * der dazukommt, braucht hier eine Zeile statt fünf. */
.card--tailback,
.bar--tailback,
.chip--tailback,
.map__legend-item--tailback,
.stretch--tailback { --c-type: var(--c-tailback); }

.card--roadworks,
.bar--roadworks,
.chip--roadworks,
.map__legend-item--roadworks,
.stretch--roadworks { --c-type: var(--c-roadworks); }

.card--accident,
.bar--accident,
.chip--accident,
.map__legend-item--accident,
.stretch--accident { --c-type: var(--c-accident); }

.card--slippery,
.bar--slippery,
.chip--slippery,
.map__legend-item--slippery,
.stretch--slippery { --c-type: var(--c-slippery); }

.card--view,
.bar--view,
.chip--view,
.map__legend-item--view,
.stretch--view { --c-type: var(--c-view); }

.card--objects,
.bar--objects,
.chip--objects,
.map__legend-item--objects,
.stretch--objects { --c-type: var(--c-objects); }

.card--breakdown,
.bar--breakdown,
.chip--breakdown,
.map__legend-item--breakdown,
.stretch--breakdown { --c-type: var(--c-breakdown); }

.card--wrongway,
.bar--wrongway,
.chip--wrongway,
.map__legend-item--wrongway,
.stretch--wrongway { --c-type: var(--c-wrongway); }

.card--closure,
.bar--closure,
.chip--closure,
.map__legend-item--closure,
.stretch--closure { --c-type: var(--c-closure); }

/* Alle drei Blitzerarten teilen eine Farbe: Wer nach einem Blitzer sucht, sucht
   nach einem Blitzer, und die Unterscheidung mobil, teilstationär oder fest
   liegt im Symbol und in der Beschriftung.

   Bei den teilstationären wäre eine eigene Farbe sogar irreführend – sie sind
   die Zwischenstufe zwischen den beiden anderen, und in der Leiste der
   Meldungsarten stehen sie unmittelbar neben den mobilen. Ein dritter Ton dort
   hieße: eine andere Sache. */
.card--mobile,
.card--fixed,
.card--semifixed,
.bar--mobile,
.bar--fixed,
.bar--semifixed,
.chip--mobile,
.chip--fixed,
.chip--semifixed,
.map__legend-item--mobile,
.map__legend-item--fixed,
.map__legend-item--semifixed,
.map__rail-item--fixed { --c-type: var(--c-camera); }

.card--vwd,
.map__rail-item--vwd,
.stretch--vwd { --c-type: var(--c-vwd); }

.map__rail-item--closure { --c-type: var(--c-closure); }

.map__rail-item--traffic { --c-type: var(--c-accent); }

.card--cluster { --c-type: var(--c-cluster); }

/* Symbole kommen aus einem SVG-Sprite und werden über <use> eingesetzt.
   Wichtig: hier darf keine fill-Regel stehen. Ein externes Sprite lässt sich
   vom Dokument nicht durchgestalten, wohl aber über vererbte Eigenschaften –
   die Symbole malen mit currentColor, und nur color wird hier gesetzt. Eine
   fill-Regel würde die Angaben im Sprite überstimmen und Konturzeichnungen
   ausfüllen. */
.icon {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  vertical-align: -0.2em;
}

.block {
  margin-top: var(--s-6);
}

.block > h2,
.block > h3 {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.block > h2::before {
  content: "";
  width: 0.25rem;
  align-self: stretch;
  min-height: 1.1em;
  border-radius: var(--radius-pill);
  background-image: var(--grad-brand);
}

/* Aufmacher. Der Schimmer und die Kante darüber sind der größte Farbeinsatz
   einer Seite. */
.hero {
  position: relative;
  margin-bottom: var(--s-5);
  padding: var(--s-5);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  background: var(--c-surface);
  background-image: var(--grad-tint);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 4px;
  background-image: var(--grad-brand);
}

.hero h1 {
  margin-bottom: var(--s-2);
}

.hero > :last-child {
  margin-bottom: 0;
}

/* Die Fehlseite: ein Aufmacher und ein Weg zurück. Suche und Einstiege
   liegen schon im Kopf und im Schnellzugriff. */
.hero--miss {
  padding: var(--s-7) var(--s-6);
}

.miss__actions {
  margin-top: var(--s-5);
}

/* Meldungskarten */

.cards {
  display: grid;
  gap: var(--s-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Die Farbe der Karte kommt aus der Meldungsart: Kante, Überschrift und
   Symbolkachel aus einem Wert. Ohne Art bleibt die neutrale Sammelfarbe. */
.card {
  position: relative;
  padding: var(--s-3) var(--s-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-left: 4px solid var(--c-type, var(--c-cluster));
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 120ms ease, transform 120ms ease, border-color 120ms ease;
}

.card:hover {
  box-shadow: var(--shadow);
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--c-type, var(--c-primary)) 30%, var(--c-border));
  border-left-color: var(--c-type, var(--c-cluster));
}

.card__title {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  color: var(--c-type, var(--c-text));
  font-weight: 600;
}

/* Das Symbol sitzt in einer eingefärbten Kachel: heller Grund in der Farbe der
   Meldungsart, Zeichnung in der Vollfarbe, ein Haarring in derselben Farbe.
   Sie gibt der Art einen Ankerpunkt, der auch beim Überfliegen einer langen
   Liste greift. Gemischt wird aus currentColor, damit je Art nur ein Farbwert
   gepflegt werden muss. */
.card__title .icon {
  width: 1.75rem;
  height: 1.75rem;
  padding: 0.3125rem;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, currentColor 13%, var(--c-surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 22%, transparent);
  color: inherit;
  vertical-align: middle;
}

.card__reason {
  margin: var(--s-2) 0 0;
  color: var(--c-muted);
}

.card__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-1) var(--s-3);
  margin: var(--s-2) 0 0;
  font-size: var(--t-small);
}

.card__facts:empty {
  display: none;
}

.card__facts dt {
  color: var(--c-muted);
}

.card__facts dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

/* Redaktionelle Meldungen */

.messages {
  display: grid;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.message {
  padding: var(--s-3) var(--s-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.message:hover {
  border-color: var(--c-border-strong);
}

.message__title {
  margin: 0;
  font-size: var(--t-body);
  font-weight: 600;
  line-height: 1.4;
}

.message__title a {
  text-decoration: none;
}

.message__title a:hover {
  text-decoration: underline;
}

.message__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-3);
  margin: var(--s-2) 0 0;
  font-size: var(--t-small);
  color: var(--c-muted);
}

.message__text {
  margin: var(--s-2) 0 0;
  line-height: 1.55;
}

/* Die Gültigkeit. Sie ist das, was der Bestand von Blitzer.de nicht hat, und
   unterscheidet den Zwischenfall von heute Abend von der Dauerbaustelle. */
.message__valid {
  margin: var(--s-2) 0 0;
  font-size: var(--t-small);
  color: var(--c-muted);
}

/* Die Kennung einer Meldung. Sie trägt die Gegenfarbe und nicht den Grundton:
   In derselben Zeile stehen Verweise, und ein graphitfarbenes Etikett zwischen
   graphitfarbenen Verweisen sähe aus wie ein Knopf, der nicht reagiert. */
.tag {
  padding: 0.1em 0.6em;
  border-radius: var(--radius-pill);
  background: var(--c-accent-soft);
  color: var(--c-accent-strong);
  font-weight: 600;
}

.tag--fresh {
  background: var(--c-accent-soft);
  color: var(--c-accent-strong);
}

.tag--stale {
  background: var(--c-surface-3);
  color: var(--c-muted);
}

/* Die Schwere einer amtlichen Meldung.

   Der Farbverlauf ist derselbe wie beim Lagewert – kühl nach warm –, damit
   dieselbe Aussage auf einer Seite nicht zweimal verschieden aussieht. Getragen
   wird sie doppelt: als Etikett am Text und als Kante am Eintrag. Die Kante
   allein wäre für Farbenblinde keine Auskunft, das Etikett allein macht eine
   Liste von hundert Meldungen nicht überfliegbar. */
.message--closure,
.message--disruption,
.message--restriction {
  border-left-width: 3px;
}

.message--closure {
  border-left-color: var(--c-level-bad);
}

.message--disruption {
  border-left-color: var(--c-level-busy);
}

.message--restriction {
  border-left-color: var(--c-level-normal);
}

.tag--closure {
  background: color-mix(in oklab, var(--c-level-bad) 14%, transparent);
  color: var(--c-level-bad);
}

.tag--disruption {
  background: color-mix(in oklab, var(--c-level-busy) 16%, transparent);
  color: var(--c-level-busy);
}

.tag--restriction {
  background: color-mix(in oklab, var(--c-level-normal) 14%, transparent);
  color: var(--c-level-normal);
}

.tag--notice {
  background: var(--c-primary-soft);
  color: var(--c-primary-strong);
}

/* Stau-Stufen */

.tier + .tier {
  margin-top: var(--s-4);
}

.tier__title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--c-muted);
}

.tier__count {
  padding: 0 0.5em;
  border-radius: var(--radius-pill);
  background: var(--c-surface-2);
  color: var(--c-text);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-small);
  text-transform: none;
}

/* In der Kontextspalte stehen die Staukarten enger: dort zählt der Überblick,
   nicht die Einzelangabe. */
.aside .cards {
  gap: var(--s-2);
}

/* Die Stauliste einer Stufe: eine Zeile je Stau, Zeitverlust rechtsbündig.
   Karten wären hier eine Bildlaufstrecke. Die untere Stufe endet nach zwanzig
   Zeilen mit der Restzahl. */
.tailbacks {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-small);
}

.tailbacks__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-1) var(--s-2);
  padding: var(--s-2) 0;
  border-top: 1px solid var(--c-border);
}

.tailbacks__item:first-child {
  border-top: 0;
}

/* Rechts am Rand, auch wenn die Zeile umbricht: „1 Std. 24 Min." passt neben
   einem langen Ortsnamen nicht mehr in die Spalte, und linksbündig unter dem
   Text sähe es wie ein zweiter Satzteil aus. */
.tailbacks__delay {
  margin-inline-start: auto;
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tailbacks__more {
  padding: var(--s-2) 0;
  border-top: 1px solid var(--c-border);
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
}

.aside .card {
  padding: var(--s-2) var(--s-3);
  font-size: var(--t-small);
}

.aside .card__title .icon {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0.25rem;
}

/* Verweisketten: Meldungsarten und Nachbarorte */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  text-decoration: none;
  font-size: var(--t-small);
  font-weight: 550;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
}

.chip:hover {
  border-color: color-mix(in srgb, var(--c-type, var(--c-primary)) 60%, var(--c-border));
  color: var(--c-type, var(--c-primary));
}

/* Trägt der Schalter eine Meldungsart, zeichnet ihr Symbol in ihrer Farbe.
   Der Schnellzugriff ist damit ohne Beschriftung lesbar, und die neun Arten
   sind dieselben neun Farben wie auf der Karte und in den Meldungslisten.
   Vorher waren alle neun Symbole grau – eine Liste, die man lesen musste. */
.chip .icon {
  width: 1rem;
  height: 1rem;
  color: var(--c-type, var(--c-muted));
}

.chip--active {
  background-image: var(--grad-brand);
  border-color: transparent;
  color: #fff;
}

.chip--active:hover {
  color: #fff;
}

.chip--active .icon,
.chip--active:hover .icon {
  color: #fff;
}

.chips--plain .chip {
  border-radius: var(--radius-sm);
}

/* Blätterung */

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-border);
}

.pagination__link {
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  font-weight: 600;
  font-size: var(--t-small);
  text-decoration: none;
}

a.pagination__link:hover {
  border-color: var(--c-primary);
}

.pagination__link--off {
  color: var(--c-muted);
  opacity: 0.55;
  box-shadow: none;
}

.pagination__page {
  color: var(--c-muted);
  font-size: var(--t-small);
  font-variant-numeric: tabular-nums;
}

/* Brotkrümelpfad */

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  margin: 0 0 var(--s-2);
  padding: 0;
  list-style: none;
  font-size: var(--t-small);
  color: var(--c-muted);
}

.breadcrumb li + li::before {
  content: "›";
  margin-right: var(--s-2);
  color: var(--c-border-strong);
}

/* Leerzustand */

.emptystate {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-3);
  align-items: baseline;
  padding: var(--s-4);
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-muted);
}

.emptystate__time {
  font-size: var(--t-small);
}

/* Suche */

.search {
  max-width: 34rem;
  margin: var(--s-4) 0 0;
}

.search__label {
  display: block;
  margin-bottom: var(--s-1);
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--c-muted);
}

.search__row {
  position: relative;
}

.search__input {
  display: block;
  width: 100%;
  min-width: 0;
  padding: var(--s-3) 2.75rem var(--s-3) var(--s-4);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  font: inherit;
  /* 16 px verhindert, dass iOS beim Fokussieren hineinzoomt. */
  font-size: max(1rem, var(--t-body));
  box-shadow: var(--shadow-sm);
}

.search__input::placeholder {
  color: var(--c-muted);
}

.search__input::-webkit-search-decoration {
  -webkit-appearance: none;
}

.search__submit {
  position: absolute;
  top: 50%;
  right: 0.2rem;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--c-muted);
  cursor: pointer;
}

.search__submit:hover,
.search__submit:focus-visible {
  color: var(--c-primary);
  background: var(--c-primary-soft);
}

.search__submit .icon {
  width: 1.15rem;
  height: 1.15rem;
  vertical-align: 0;
}

/* Vorschlagsliste der Island. Ohne JavaScript existiert sie nicht, und das
   Formular bleibt trotzdem benutzbar. */
.search__suggestions {
  position: absolute;
  top: calc(100% + var(--s-2));
  left: 0;
  right: 0;
  z-index: 40;
  margin: 0;
  padding: var(--s-1);
  list-style: none;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  max-height: 18rem;
  overflow-y: auto;
}

.search__suggestion {
  display: block;
  width: 100%;
  padding: var(--s-2) var(--s-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.search__suggestion[aria-selected="true"],
.search__suggestion:hover {
  background: var(--c-primary-soft);
  color: var(--c-primary-strong);
}

.search__suggestion small {
  color: var(--c-muted);
  margin-left: var(--s-2);
}

/* Fließtext */

.prose {
  max-width: var(--w-prose);
}

.prose h2 {
  margin-top: var(--s-6);
}

/* Eine Anschrift ist im Impressum eine Anschrift und keine Hervorhebung; die
   Kursivstellung der Browser hilft dort nichts. Der Abstand darunter ist der
   eines Absatzes, den address von sich aus nicht hat – sonst klebte die
   Vertretungsangabe an der Hausnummer. */
.prose address {
  margin: 0 0 var(--s-4);
  font-style: normal;
}

.facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-2) var(--s-4);
  margin: 0;
  padding: 0;
}

.facts dt {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.facts dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* Kacheln „Neueste Meldungen nach Art" */

.grid {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}

.grid__item {
  padding: var(--s-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.grid__title {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-body);
  margin-bottom: var(--s-2);
}

.grid__title .icon {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0.25rem;
  border-radius: var(--radius-sm);
  background: var(--c-surface-2);
  color: var(--c-muted);
}

.minilist {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-small);
}

.minilist li {
  padding: var(--s-2) 0;
  border-top: 1px solid var(--c-border);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  justify-content: space-between;
}

.minilist li:first-child {
  border-top: 0;
}

.minilist__empty {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--t-small);
}

/* Seitenköpfe. Alle Seitenarten tragen denselben Aufbau – Brotkrümel, Kicker,
   Überschrift, Lead –, deshalb steht die Regel einmal und nicht siebenmal. */

.situation__head,
.directory__head,
.ranking__head,
.knowledge__head,
.article__head,
.message-page__head,
.event__head,
.radar__head {
  margin-bottom: var(--s-5);
}

.situation__head h1 {
  font-size: clamp(1.75rem, 1.35rem + 2.8vw, 2.75rem);
  font-weight: 750;
}

.message-page__head h1 {
  max-width: 28ch;
}

.message-page__text {
  margin: var(--s-3) 0 0;
  max-width: var(--w-prose);
  font-size: var(--t-lead);
  line-height: 1.55;
}

/* Die Angaben der Landesmeldestelle: Kacheln wie die Kennzahlen im Lagebild,
   mit Stahlkante statt Graphit, damit die Seite nicht wie eine Störungskarte
   der Gemeinschaft wirkt. */
.message-facts {
  margin: 0 0 var(--s-5);
  padding: var(--s-4);
  border: 1px solid var(--c-border);
  border-left: 4px solid var(--c-vwd);
  border-radius: var(--radius);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.message-facts__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2) var(--s-4);
  margin-bottom: var(--s-4);
}

.message-facts__kicker {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  color: var(--c-vwd);
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.message-facts__kicker .icon {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
}

.message-facts__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0;
}

.message-facts__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-3);
  margin: 0;
}

@media (min-width: 36rem) {
  .message-facts__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.message-facts__item {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--radius);
  background: var(--c-surface-2);
}

.message-facts__item--wide {
  grid-column: 1 / -1;
}

.message-facts__item dt {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.message-facts__item dd {
  margin: 0;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.message-facts__item .hint {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--t-small);
  font-weight: 500;
  color: var(--c-muted);
}

/* Die Zeile über der Überschrift sagt, was für eine Seite das ist – „Stadt
   oder Gemeinde", „Bundesland", „Meldungsart". Sie steht in der Markenfarbe,
   weil sie zur Einordnung der Website gehört und nicht zum Ort: Grau gelesen
   wirkte sie wie eine Fußnote zur Überschrift. */
.kicker {
  margin: 0 0 var(--s-1);
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-primary);
}

/* Brotkrümel. Es gab sie im Altsystem nicht, weil die Adressen flach waren und
   es nichts zu zeigen gab. */

.crumbs {
  margin: 0 0 var(--s-3);
  font-size: var(--t-small);
  color: var(--c-muted);
}

.crumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.crumbs li + li::before {
  content: "›";
  margin-right: var(--s-2);
  color: var(--c-border-strong);
}

.crumbs a {
  color: inherit;
}

/* --------------------------------------------------------- Der Kopfstreifen

   Nur auf /stau, fest offen. Tacho, Kennzahlen und Tagesverlauf als
   drei Flächen unter einer Zeile aus Titel und Merken. */

.gauge {
  margin: 0 0 var(--s-5);
  padding: var(--s-5);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  background-color: var(--c-surface);
  background-image: var(--grad-brand), var(--grad-tint);
  background-repeat: no-repeat;
  background-size: 100% 4px, auto;
  background-position: top, top;
  box-shadow: var(--shadow);
  overflow: hidden;
}

.gauge__heading {
  margin-bottom: var(--s-5);
}

.gauge__kicker {
  margin: 0 0 var(--s-1);
  color: var(--c-accent);
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.gauge__title {
  margin: 0;
  font-size: var(--t-h2);
  font-weight: 700;
  color: var(--c-primary);
  letter-spacing: -0.02em;
}

.gauge__note {
  margin: var(--s-2) 0 0;
  max-width: 36rem;
  color: var(--c-muted);
  font-size: var(--t-small);
}

.gauge__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

/* Oben die Mini-Karten, unten der Verlauf über die volle Breite. */
.gauge__minis {
  display: grid;
  gap: var(--s-3);
  grid-template-columns: 1fr;
  align-items: stretch;
}

@media (min-width: 40rem) {
  .gauge__minis {
    grid-template-columns: auto minmax(0, 1fr);
  }
}

.gauge__arc {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  padding: var(--s-5) var(--s-6);
  border-radius: var(--radius);
  background: var(--c-surface-2);
}

.gauge__arc svg {
  display: block;
  width: 11rem;
  height: auto;
}

/* Das Wort zum Wert als getönte Pille unter dem Bogen. Dieselbe Farbe
   wie der Bogen: die Stufe wird in Zahl und Wort gesagt. */
.gauge__tone {
  margin: 0;
  padding: 0.2em 0.8em;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, currentColor 14%, var(--c-surface));
  font-size: var(--t-small);
  font-weight: 650;
}

.gauge__tone--good {
  color: var(--c-level-good);
}
.gauge__tone--normal {
  color: var(--c-level-normal);
}
.gauge__tone--busy {
  color: var(--c-level-busy);
}
.gauge__tone--bad {
  color: var(--c-level-bad);
}
.gauge__tone--peak-low {
  color: var(--c-peak-low);
}
.gauge__tone--peak-mid {
  color: var(--c-peak-mid);
}
.gauge__tone--peak-high {
  color: var(--c-peak-high);
}
.gauge__tone--unknown {
  color: var(--c-muted);
  font-weight: 500;
}

.gauge__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-2) var(--s-4);
  margin: 0;
  padding: 0;
}

.gauge__facts dt {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.gauge__facts dd {
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.gauge .gauge__facts {
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: var(--s-3);
}

.gauge__stat {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--radius);
  background: var(--c-surface-2);
}

.gauge .gauge__facts dd {
  font-size: var(--t-lead);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.gauge .gauge__facts .hint {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--t-small);
  font-weight: 500;
  color: var(--c-muted);
}

.gauge__spark {
  min-width: 0;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--radius);
  background: var(--c-surface-2);
}

.gauge__spark .spark {
  width: 100%;
  height: 11.5rem;
}

@media (min-width: 48rem) {
  .gauge__spark .spark {
    height: 13.5rem;
  }
}

.gauge__spark svg {
  display: block;
  width: 100%;
}

.gauge__sparktitle {
  margin: 0 0 var(--s-2);
  font-size: var(--t-small);
  font-weight: 650;
  color: var(--c-muted);
}

.gauge__trend {
  margin: var(--s-2) 0 0;
  font-size: var(--t-small);
  font-weight: 600;
}

.gauge__trend--rising {
  color: var(--c-level-bad);
}
.gauge__trend--falling {
  color: var(--c-level-good);
}
.gauge__trend--flat,
.gauge__trend--unknown {
  color: var(--c-muted);
  font-weight: 500;
}

.save {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  margin: 0;
}

.save__link {
  font-size: var(--t-small);
}

/* Gemerkt heißt gemerkt: die Schaltfläche behält ihre Form und wechselt nur
   Farbe und Beschriftung. Ein Wechsel der Größe verschöbe den Kopfstreifen
   unter dem Zeigefinger. */
.save .button[aria-pressed="true"] {
  border-color: var(--c-primary);
  color: var(--c-primary-strong);
  background: var(--c-primary-soft);
}

.button--ghost {
  background: var(--c-surface);
  background-image: none;
  border: 1px solid var(--c-border-strong);
  color: var(--c-text);
}

.button--ghost:hover {
  border-color: var(--c-primary);
  color: var(--c-primary);
  filter: none;
}

/* ------------------------------------------------------------------ Kacheln

   Bundesländer und Verzeichniseinträge. Eine Kachel ist die kleinste Form, in
   der Name, Anzahl und Zeitverlust nebeneinander noch lesbar sind. */

.tiles {
  display: grid;
  gap: var(--s-3);
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.tile__link {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "arc name"
    "arc count"
    "arc delay";
  gap: 0 var(--s-3);
  align-items: center;
  height: 100%;
  padding: var(--s-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: inherit;
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 120ms ease, transform 120ms ease, border-color 120ms ease;
}

.tile__link:hover {
  border-color: color-mix(in srgb, var(--c-primary) 55%, var(--c-border));
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}

.tile__arc {
  grid-area: arc;
}

.tile__arc svg {
  display: block;
  width: 3rem;
  height: auto;
}

.tile__name {
  grid-area: name;
  font-weight: 650;
}

.tile__count {
  grid-area: count;
  font-size: var(--t-small);
  color: var(--c-muted);
}

.tile__delay {
  grid-area: delay;
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--c-roadworks);
}

/* ------------------------------------------------------------------- Ebenen

   Der Einstieg zu den dauerhaften Anlagen, direkt unter der Karte. Eine Zeile
   und kein Abschnitt: Die Auskunft ist eine Randbemerkung zur Karte darüber,
   und ein eigener Block mit Überschrift stellte sie neben die Aufteilung nach
   Meldungsart – genau dort, wo sie nicht hingehört. */

.layers {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
  /* Näher an die Karte als an den nächsten Abschnitt: Der Satz gehört zu ihr. */
  margin: calc(-1 * var(--s-3)) 0 var(--s-5);
  font-size: var(--t-small);
}

.layers__text {
  flex: 1 1 14rem;
  color: var(--c-muted);
  text-wrap: pretty;
}

/* ------------------------------------------------------------------- Balken

   Die Aufteilung nach Meldungsart. Der Balken trägt keine eigene Aussage – die
   Zahl daneben tut es –, aber er macht die Verhältnisse in einem Blick
   erfassbar, und darum geht es auf einer Übersichtsseite. */

.bars {
  margin: 0;
  padding: 0;
  list-style: none;
}

.bar + .bar {
  border-top: 1px solid var(--c-border);
}

.bar__link {
  display: grid;
  grid-template-columns: auto minmax(6rem, 9rem) 1fr auto;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-1);
  color: inherit;
  text-decoration: none;
}

.bar__link:hover {
  background: color-mix(in srgb, var(--c-type, var(--c-primary)) 7%, var(--c-surface));
}

/* Symbol und Balken tragen die Farbe der Meldungsart. Vorher war die Liste
   neunmal grau mit neun violetten Balken: sie zeigte die Verhältnisse und
   verschwieg, wovon. Jetzt ist die Aufteilung nach Art eine Farbtafel, die zu
   Karte, Legende und Meldungsliste passt – dieselben neun Farben, dieselbe
   Reihenfolge. */
.bar__link .icon {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0.25rem;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--c-type, var(--c-primary)) 12%, var(--c-surface));
  color: var(--c-type, var(--c-primary));
}

.bar__label {
  font-size: var(--t-small);
}

.bar__track {
  height: 0.5rem;
  border-radius: var(--radius-pill);
  background: var(--c-surface-3);
  overflow: hidden;
}

.bar__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background-image: linear-gradient(
    90deg,
    color-mix(in srgb, var(--c-type, var(--c-primary)) 55%, var(--c-surface)),
    var(--c-type, var(--c-primary))
  );
}

.bar__value {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* --------------------------------------------------------------- Ranglisten

   In der Kontextspalte als kompakte Liste, auf der eigenen Seite als Tabelle.
   Zwei Darstellungen, weil eine Rangliste mit vier Kennzahlen in einer 18rem
   breiten Spalte nicht lesbar ist. */

.ranks {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: rank;
}

.rank {
  display: grid;
  grid-template-columns: 1.5rem 1fr auto;
  align-items: baseline;
  gap: var(--s-2);
  padding: var(--s-2) 0;
  border-top: 1px solid var(--c-border);
  font-size: var(--t-small);
}

.rank:first-child {
  border-top: 0;
}

.rank__pos {
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
}

.rank__name {
  overflow-wrap: anywhere;
}

.rank__value {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-small);
}

.table th,
.table td {
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--c-border);
  text-align: left;
  vertical-align: middle;
}

.table th {
  color: var(--c-muted);
  font-weight: 600;
  white-space: nowrap;
}

.table__pos,
.table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.table__bar {
  width: 6rem;
  min-width: 4rem;
  height: 0.4rem;
  border-radius: var(--radius-pill);
  background: var(--c-surface-3);
  overflow: hidden;
}

.table__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background-image: var(--grad-brand);
}

/* ------------------------------------------------------------- Verzeichnis */

.alphabet {
  margin: 0 0 var(--s-4);
}

/* Der Reihenumbruch gehört auf die Liste und nicht auf das nav darüber: Dessen
   einziges Kind ist die Liste, und ein Flex-Behälter mit einem Kind bricht
   nichts um – die Buchstaben standen dadurch untereinander. */
.alphabet__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.alphabet__item {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1);
  min-width: 2.5rem;
  justify-content: center;
  padding: var(--s-2);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: inherit;
  text-decoration: none;
  font-weight: 650;
  text-transform: uppercase;
}

.alphabet__item:hover {
  border-color: var(--c-primary);
  color: var(--c-primary);
}

.alphabet__count {
  font-size: var(--t-small);
  font-weight: 400;
  color: var(--c-muted);
}

/* ------------------------------------------------------------- Vorgänge

   Die Liste gibt es nur, weil die Website ein Gedächtnis hat: „besteht seit
   zwei Stunden" und „wächst" stehen in keiner Quelle, sie entstehen aus der
   Reihe der Abrufe. */

.events {
  margin: 0;
  padding: 0;
  list-style: none;
}

.event-row + .event-row {
  border-top: 1px solid var(--c-border);
}

.event-row__link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-1) var(--s-3);
  padding: var(--s-3) var(--s-1);
  color: inherit;
  text-decoration: none;
}

.event-row__link:hover {
  background: var(--c-surface-2);
}

.event-row__title {
  font-weight: 600;
}

.event-row__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-3);
  font-size: var(--t-small);
  color: var(--c-muted);
}

.event-row__delay {
  font-weight: 600;
  color: var(--c-roadworks);
}

.event__facts {
  margin-bottom: var(--s-4);
}

.event__peak {
  margin: 0 0 var(--s-4);
  font-size: var(--t-small);
  color: var(--c-muted);
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  margin: var(--s-2) 0 0;
  font-size: var(--t-small);
  color: var(--c-muted);
}

.legend__km::before,
.legend__delay::before {
  content: "";
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  margin-right: var(--s-1);
  border-radius: 2px;
  vertical-align: baseline;
}

.legend__km::before {
  background: var(--c-primary);
}

.legend__delay::before {
  background: var(--c-roadworks);
}

/* ---------------------------------------------------------------- Wissen */

.articles {
  margin: 0;
  padding: 0;
  list-style: none;
}

.articles__item {
  padding: var(--s-4) 0;
  border-top: 1px solid var(--c-border);
}

.articles__item:first-child {
  border-top: 0;
}

.articles__title {
  margin: 0 0 var(--s-1);
  font-size: var(--t-h3);
}

.articles__summary {
  margin: 0;
  max-width: var(--w-prose);
  color: var(--c-muted);
}

.panel__list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-small);
}

.panel__list li {
  padding: var(--s-2) 0;
  border-top: 1px solid var(--c-border);
}

.panel__list li:first-child {
  border-top: 0;
}

.panel__more {
  margin: var(--s-3) 0 0;
  font-size: var(--t-small);
}

/* Der aufklappbare Rest einer Liste. Er hält die Kontextspalte kurz, ohne die
   Verweise aus dem Dokument zu nehmen: details ist im geschlossenen Zustand
   nur unsichtbar, der Inhalt steht im Quelltext und ist auffindbar. */
/* Der aufklappbare Rest, im Hauptstrang wie in der Spalte: Eine Ortsseite hat
   über hundert amtliche Meldungen, und zwölf davon sind die Auskunft. */
.block__rest {
  margin-top: var(--s-4);
}

.block__rest > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--c-primary);
}

.block__rest[open] > summary {
  margin-bottom: var(--s-3);
}

.panel__rest {
  margin-top: var(--s-3);
  border-top: 1px solid var(--c-border);
  padding-top: var(--s-3);
}

.panel__rest > summary {
  cursor: pointer;
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--c-primary);
}

.panel__rest[open] > summary {
  margin-bottom: var(--s-3);
}

/* --------------------------------------------------------------- Mein Radar

   Der einzige Teil der Website mit eigenem Zustand im Browser. Die Karten
   sehen aus wie die Kacheln der Länderübersicht, tragen aber mehr: Der Radar
   ist die Seite, die ein Besucher täglich öffnet, und darf deshalb dichter
   sein als eine, die er einmal über eine Suche findet. */

.radar__fallback,
.radar__empty {
  margin: 0 0 var(--s-4);
  padding: var(--s-3) var(--s-4);
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius);
  color: var(--c-muted);
  font-size: var(--t-small);
}

.radar__board {
  margin: 0 0 var(--s-5);
}

.radar__types {
  margin: 0 0 var(--s-4);
  padding: 0;
  border: 0;
}

.radar__types legend {
  padding: 0;
  margin-bottom: var(--s-2);
  font-size: var(--t-small);
  font-weight: 650;
  color: var(--c-muted);
}

/* Die Meldungsarten sind Schaltflächen und keine Verweise: sie ändern die
   Ansicht, sie führen nicht woandershin. aria-pressed trägt den Zustand, die
   Färbung folgt ihm. */
.radar__types .chip {
  cursor: pointer;
  font: inherit;
  font-size: var(--t-small);
  font-weight: 550;
}

/* Gewählt heißt: in der Farbe der Meldungsart. Es ist dieselbe Färbung wie bei
   der eingeschalteten Pille der Kartenlegende, und aus demselben Grund – neun
   Schalter in einer Markenfarbe zeigen, dass sie an sind, und verschweigen, wozu
   sie gehören. */
.radar__types .chip[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--c-type, var(--c-primary)) 45%, var(--c-border));
  background: color-mix(in srgb, var(--c-type, var(--c-primary)) 9%, var(--c-surface));
  color: var(--c-type, var(--c-primary-strong));
  font-weight: 650;
}

.radar__nationwide {
  margin: 0 0 var(--s-4);
  font-size: var(--t-small);
  color: var(--c-muted);
}

.radar__list {
  display: grid;
  gap: var(--s-3);
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.radar__card {
  position: relative;
  height: 100%;
  padding: var(--s-4);
  border: 1px solid var(--c-border);
  border-left: 4px solid var(--c-primary);
  border-radius: var(--radius);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.radar__card:hover {
  border-color: color-mix(in srgb, var(--c-primary) 40%, var(--c-border));
  box-shadow: var(--shadow);
}

.radar__card[data-tone="good"] {
  border-left-color: var(--c-level-good);
}
.radar__card[data-tone="normal"] {
  border-left-color: var(--c-level-normal);
}
.radar__card[data-tone="busy"] {
  border-left-color: var(--c-level-busy);
}
.radar__card[data-tone="bad"] {
  border-left-color: var(--c-level-bad);
}

.radar__cardhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}

.radar__cardhead h3 {
  margin: 0;
  min-width: 0;
  font-size: var(--t-body);
}

.radar__card-actions {
  position: relative;
  z-index: 1;
  display: flex;
  flex: none;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
}

.radar__card--edit .radar__card-link::after {
  content: none;
}

.radar__card--edit .radar__cardhead {
  flex-wrap: wrap;
}

.radar__rename {
  position: relative;
  z-index: 1;
  display: flex;
  flex: 1 1 12rem;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.radar__rename--view {
  flex: 1 1 100%;
}

.radar__rename-input {
  flex: 1 1 8rem;
  min-width: 0;
  padding: 0.35rem 0.65rem;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-text);
  font: inherit;
  font-size: max(1rem, var(--t-body));
}

.radar__rename-input:focus {
  outline: 2px solid var(--c-focus);
  outline-offset: 1px;
}

.radar__card-link {
  color: inherit;
  text-decoration: none;
}

.radar__card-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.radar__card-link:hover {
  color: var(--c-primary-strong);
}

.radar__meta {
  margin: 0 0 var(--s-2);
  color: var(--c-muted);
  font-size: var(--t-small);
}

.radar__kinds {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.radar__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin: 0 0 var(--s-4);
}

.radar__view-title {
  margin: 0;
  font-size: var(--t-lead);
  font-weight: 650;
}

.radar__toolbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.radar__remove {
  position: relative;
  z-index: 1;
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-muted);
  font: inherit;
  font-size: var(--t-small);
  text-decoration: underline;
  cursor: pointer;
}

.radar__remove:hover {
  color: var(--c-accident);
}

.radar__figures {
  margin: 0 0 var(--s-2);
  font-size: var(--t-small);
}

.radar__pois {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-small);
  color: var(--c-muted);
}

.radar__pois li {
  padding: var(--s-1) 0;
  border-top: 1px solid var(--c-border);
}

.radar__poitype {
  font-weight: 600;
  color: var(--c-text);
}

/* Ein Hinweis, der eine Störung meldet und keine Datenlücke: andere Farbe als
   .notice, sonst sähen „Daten sind alt" und „Abruf gescheitert" gleich aus. */
.notice--warn {
  border-color: color-mix(in srgb, var(--c-accident) 35%, var(--c-border));
  border-left-color: var(--c-accident);
}

/* ------------------------------------------------------ 6. Die Bildsprache
 *
 * Lagewert-Bogen, Tagesverlauf, Wochenraster und Streckenstreifen. Die vier
 * Zeichnungen entstehen serverseitig in internal/view/chart.go und tragen dort
 * ausschließlich Klassennamen – kein Farbwert, keine Schriftgröße.
 *
 * Das ist Absicht: Die Elemente sollen dem Farbschema folgen, und ein Bogen
 * mit eingebauten Farben wäre im Dunkelmodus ein weißer Fleck. Es hat aber
 * eine Kehrseite, die hier einmal eingetreten ist: Weil die Gegenstücke im
 * Stylesheet fehlten, wurde nichts gezeichnet. Ein Pfad ohne stroke ist
 * unsichtbar, und so fehlten Bogen, Verlauf, Raster und Streifen auf jeder
 * Seite – ohne Fehlermeldung, ohne Lücke im Aufbau, mit Beschriftung und
 * Zahl an ihrem Platz. Wer hier Klassen umbenennt, benennt sie in zwei
 * Dateien um.
 *
 * In den drei SVG-Zeichnungen stehen die Schriftgrößen in Nutzereinheiten des
 * viewBox und nicht in rem: Sie werden als Ganzes skaliert, und eine rem-Angabe
 * darin würde beim Verkleinern zur Überschrift. Der Streckenstreifen ist
 * deshalb kein SVG – bei ihm skaliert nichts außer den Abständen. */

.arc {
  display: block;
}

/* Die Bahn ist die Fläche, der Wert die Farbe seiner Stufe. Ist der Wert noch
   nicht bekannt, bleibt es bei der Bahn und einem Strich – eine erfundene
   Skala wäre schlechter als keine. */
.arc__track {
  stroke: var(--c-surface-3);
}

/* Die vier Stufen ausgeschrieben, auch die, die dem Standardwert entspricht:
   Die Zuordnung von Stufe zu Farbe soll hier als Tabelle lesbar sein, und ein
   Ton, der seine Farbe nur durch Weglassen bekommt, fehlt beim Lesen. */
.arc__value {
  stroke: var(--c-level-normal);
}

.arc--good .arc__value {
  stroke: var(--c-level-good);
}

.arc--normal .arc__value {
  stroke: var(--c-level-normal);
}

.arc--busy .arc__value {
  stroke: var(--c-level-busy);
}

.arc--bad .arc__value {
  stroke: var(--c-level-bad);
}

.arc--peak-low .arc__value {
  stroke: var(--c-peak-low);
}

.arc--peak-mid .arc__value {
  stroke: var(--c-peak-mid);
}

.arc--peak-high .arc__value {
  stroke: var(--c-peak-high);
}

/* Ohne Lagewert ist die Bahn heller. Sie trägt dann einen Strich statt einer
   Zahl, und eine Bahn in voller Stärke sähe aus wie ein Wert von null – also
   wie „nichts los" statt „noch nicht messbar". */
.arc--unknown .arc__track {
  stroke: color-mix(in srgb, var(--c-surface-3) 60%, var(--c-surface));
}

.arc__number {
  fill: var(--c-text);
  font-family: var(--font);
  font-size: 30px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.arc__number--empty {
  fill: var(--c-muted);
  font-weight: 500;
}

/* Der Tagesverlauf: eine Linie vom Zeitverlust, von 0 Uhr bis Mitternacht.
   Bekannte Messungen sind verbunden; „jetzt" ist der letzte Punkt. Die Schrift
   skaliert mit der viewBox – deshalb meet. */
.spark {
  display: block;
  width: 100%;
  height: auto;
}

.spark__grid {
  stroke: var(--c-border);
  stroke-width: 1;
}

.spark__ytick,
.spark__xtick,
.spark__daylabel {
  fill: var(--c-muted);
  font-family: var(--font);
  font-size: 9px;
  font-variant-numeric: tabular-nums;
}

.spark__ytick {
  text-anchor: end;
}

.spark__xtick {
  text-anchor: middle;
}

.spark__daylabel {
  font-weight: 650;
  fill: var(--c-text);
}

.spark__line {
  stroke: var(--c-primary);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.spark__now {
  fill: var(--c-accent);
}

/* Das Wochenraster. Die Sättigung eines Feldes kommt aus dem Zeitverlust und
   steht als opacity in der Zeichnung; die Farbe steht hier. Ein Feld ohne
   Aufzeichnung ist nicht „null Minuten", sondern leer, und deshalb grau. */
.week {
  display: block;
  max-width: 100%;
  height: auto;
}

.week__cell {
  fill: var(--c-primary);
}

.week__cell--empty {
  fill: var(--c-surface-3);
  opacity: 1;
}

.week__day,
.week__hour {
  fill: var(--c-muted);
  font-family: var(--font);
  font-size: 9px;
}

/* Der Streckenstreifen.
   Die Bahn ist eine ruhige Fläche, auf der zwei Formen liegen: Balken für
   Meldungen mit Ausdehnung, Punkte für punktuelle. Beide tragen die Farbe ihres
   Zeitverlusts und einen Rand in der Flächenfarbe, damit zwei Meldungen am
   selben Ort als zwei erkennbar bleiben.

   Das Element ist bewusst kein SVG: Nur die Positionen sind relativ, alle Maße
   stehen hier in Bildpunkten. Ein SVG hätte auf einem Telefon auch die Schrift
   und die Punkte mitverkleinert (siehe RoadStrip in chart.go). */
.strip {
  --strip-track: 12px;
  --strip-dot: 10px;
  --strip-row: 13px;

  margin-bottom: var(--s-4);
}

/* Platz über der Bahn, aber nur so viel, wie Reihen belegt sind. */
.strip--rows1 {
  padding-top: var(--strip-row);
}

.strip--rows2 {
  padding-top: calc(2 * var(--strip-row));
}

/* Die Bahn ist breiter als der Bereich der Meldungen: Ihre runden Kappen ragen
   um einen halben Punkt über die erste und die letzte Meldung hinaus, statt von
   ihnen überdeckt zu werden. */
.strip__band {
  padding: 0 calc(var(--strip-dot) / 2);
  background: var(--c-surface-3);
  border: 1px solid var(--c-border);
  border-radius: 999px;
}

.strip__marks {
  position: relative;
  height: var(--strip-track);
}

.strip__event,
.strip__stretch {
  position: absolute;
  border: 1.5px solid var(--c-surface);
  box-sizing: border-box;
}

.strip__event {
  top: calc(50% - var(--strip-dot) / 2 - var(--strip-lift, 0px));
  width: var(--strip-dot);
  height: var(--strip-dot);
  margin-left: calc(var(--strip-dot) / -2);
  border-radius: 50%;
}

.strip__stretch {
  top: calc(-1px - var(--strip-lift, 0px));
  height: calc(var(--strip-track) + 2px);
  min-width: var(--strip-dot);
  transform: translateX(-50%);
  border-radius: 999px;
}

/* Eine gestapelte Meldung steht über ihrer Stelle und ist über einen Halm mit
   ihr verbunden – ohne ihn schwebt sie über der Strecke, und die Zuordnung
   wäre geraten. Der Halm reicht von der Unterkante bis zur Mitte der Bahn,
   und die liegt bei einem Punkt und einem Balken unterschiedlich tief. */
.strip__row1 {
  --strip-lift: var(--strip-row);
}

.strip__row2 {
  --strip-lift: calc(2 * var(--strip-row));
}

.strip__row1::before,
.strip__row2::before {
  content: "";
  position: absolute;
  top: 100%;
  left: calc(50% - 1px);
  width: 2px;
  background: var(--c-border-strong);
}

.strip__event.strip__row1::before,
.strip__event.strip__row2::before {
  height: calc(var(--strip-lift) - var(--strip-dot) / 2);
}

.strip__stretch.strip__row1::before,
.strip__stretch.strip__row2::before {
  height: calc(var(--strip-lift) - var(--strip-track) / 2 - 1px);
}

/* Ohne Zeitangabe bleibt die Meldung neutral. Die Farbskala beginnt erst dort,
   wo eine Messung vorliegt (siehe delayTone in chart.go). */
.strip__event--none,
.strip__stretch--none {
  background: var(--c-cluster);
}

.strip__event--good,
.strip__stretch--good {
  background: var(--c-level-good);
}

.strip__event--normal,
.strip__stretch--normal {
  background: var(--c-level-normal);
}

.strip__event--busy,
.strip__stretch--busy {
  background: var(--c-level-busy);
}

.strip__event--bad,
.strip__stretch--bad {
  background: var(--c-level-bad);
}

/* Die Ortsnamen. Der Teilstrich steht an der genauen Stelle, der Name darunter
   mittig – außer an den Enden, wo er am Rand bleibt. */
.strip__names {
  position: relative;
  height: 24px;
  margin: 0 calc(var(--strip-dot) / 2);
}

.strip__tick {
  position: absolute;
  top: 3px;
  width: 1px;
  height: 5px;
  background: var(--c-border-strong);
}

/* Die Breite ist begrenzt, weil ein Landkreisname länger sein kann als die
   halbe Spalte. Die Schätzung in fitLabels hält die Namen auf einer breiten
   Spalte auseinander; auf einer schmalen bleiben nur die beiden Enden, und die
   dürfen sich auch dort nicht berühren. */
.strip__label {
  position: absolute;
  top: 11px;
  max-width: 46%;
  overflow: hidden;
  transform: translateX(-50%);
  color: var(--c-muted);
  font-size: 11px;
  line-height: 1.1;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.strip__label--first,
.strip__label--last {
  transform: none;
}

/* Auf schmalen Spalten reicht der Platz nur für die Enden der Strecke. Zwei
   lesbare Namen sind mehr wert als sechs, die sich überschreiben – die
   Schätzung in fitLabels rechnet mit einer Spalte von 620 Bildpunkten. */
@media (max-width: 620px) {
  .strip__label,
  .strip__tick {
    display: none;
  }

  .strip__label--first,
  .strip__label--last,
  .strip__tick--first,
  .strip__tick--last {
    display: block;
  }
}

/* Der senkrechte Autobahnverlauf: eine stilisierte Fahrbahn links, die
   Ereignisse rechts in der Reihenfolge der Strecke. */
.course {
  display: flex;
  gap: var(--s-3);
  margin-top: var(--s-2);
}

.course__lane {
  flex: 0 0 18px;
  min-height: 4rem;
  border-radius: 4px;
  background: var(--c-text);
  position: relative;
}

.course__lane::after {
  content: "";
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: 50%;
  width: 2px;
  transform: translateX(-50%);
  background: repeating-linear-gradient(
    to bottom,
    var(--c-surface) 0 7px,
    transparent 7px 14px
  );
}

.course__side {
  flex: 1;
  min-width: 0;
}

.course__end {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--t-small);
}

.course__list {
  margin: var(--s-2) 0;
  padding: 0;
  list-style: none;
}

.course__item {
  padding: var(--s-2) 0;
  border-top: 1px solid var(--c-border);
}

.course__item:first-child {
  border-top: 0;
  padding-top: 0;
}

.course__title {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  margin: 0;
  font-size: var(--t-small);
}

.course__title .icon {
  flex: 0 0 auto;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.1em;
}

.course__meta {
  margin: var(--s-1) 0 0 1.75rem;
  color: var(--c-muted);
  font-size: var(--t-small);
}

/* ------------------------------------------------------------ 7. Karte */

.map {
  --map-canvas-h: clamp(19rem, 48vh, 30rem);
  position: relative;
  display: flex;
  flex-direction: column;
  margin: 0 0 var(--s-5);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.map__canvas {
  /* Die Höhe wächst mit dem Viewport, bleibt aber in Grenzen: auf dem Telefon
     soll die Liste unter der Karte noch anreißen. Im dreispaltigen Layout hat
     die Mittelspalte mehr Platz, deshalb darf die Karte dort höher werden. */
  height: var(--map-canvas-h);
  background: var(--c-surface-2);
  z-index: 0;
}

@media (min-width: 62rem) {
  .map {
    --map-canvas-h: clamp(24rem, 56vh, 40rem);
  }
}

.map__fallback {
  margin: 0;
  padding: var(--s-4);
  color: var(--c-muted);
  font-size: var(--t-small);
  text-align: center;
}

/* Sobald die Island übernommen hat, verschwindet der Hinweis. */
.map[data-island-ready] .map__fallback {
  display: none;
}

/* Die Island hängt ihre Bedienung in einen eigenen Knoten unter der Karte.
   display: contents löst diesen Knoten aus dem Layout, damit seine Teile
   entweder über der Karte liegen (Werkzeuge, Statusfeld) oder unter ihr in der
   Reihe stehen (Filterleiste) – ohne dass React die Kartenfläche anfassen
   muss. */
.map__controls {
  display: contents;
}

/* Einstellungsleiste über der Karte, bündig am rechten Rand. Eine Fläche
   statt einzelner Pillen, damit die Karte ruhig bleibt. Zugeklappt nur das
   Symbol; an oder aus steht in Grund und Symbolfarbe. Der Anfasser oben
   schiebt die Namen dazu. */
.map__rail {
  --rail-icon: 1.35rem;
  --rail-pad: 0.55rem;
  --rail-gap: 0.55rem;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  width: calc(var(--rail-pad) * 2 + var(--rail-icon));
  max-height: 100%;
  overflow: hidden;
  border: 1px solid var(--c-border);
  border-top: 0;
  border-right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: color-mix(in srgb, var(--c-surface) 92%, transparent);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow);
  transition: width 180ms ease;
}

.map__rail--open {
  width: 12.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .map__rail {
    transition: none;
  }
}

.map__rail-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  width: 100%;
  min-height: 2.35rem;
  padding: 0.4rem var(--rail-pad);
  border: 0;
  border-bottom: 1px solid var(--c-border);
  border-radius: 0;
  background: transparent;
  color: var(--c-muted);
  font: inherit;
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
}

.map__rail--open .map__rail-handle {
  justify-content: flex-start;
  gap: var(--rail-gap);
}

.map__rail-handle .icon {
  flex: none;
  width: var(--rail-icon);
  height: var(--rail-icon);
  color: inherit;
}

.map__rail-handle:hover {
  color: var(--c-text);
  background: color-mix(in srgb, var(--c-surface-2) 70%, transparent);
}

.map__rail-list {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: auto;
  padding: 0.15rem 0;
}

.map__rail-item {
  display: grid;
  grid-template-columns: var(--rail-icon) minmax(0, 1fr);
  column-gap: var(--rail-gap);
  align-items: center;
  width: 100%;
  min-height: 2.25rem;
  padding: 0.4rem var(--rail-pad);
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--c-text);
  font: inherit;
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1.2;
  text-align: start;
  cursor: pointer;
}

.map__rail-item--action {
  border-top: 1px solid var(--c-border);
}

.map__rail-item--action + .map__rail-item--action {
  border-top: 0;
}

.map__rail-item .icon {
  width: var(--rail-icon);
  height: var(--rail-icon);
  justify-self: center;
  color: var(--c-muted);
}

.map__rail-item:hover {
  background: color-mix(in srgb, var(--c-surface-2) 80%, transparent);
}

.map__rail-item:hover .icon {
  color: var(--c-primary);
}

/* Eingeschaltet: die Zeile trägt die Farbe der Ebene, nicht nur das Symbol.
   Besonders Stahl (VWD) wäre als reine Symbolfarbe vom gedämpften Aus-Zustand
   kaum zu trennen. Ohne eigene Farbe (Verkehrsfluss) bleibt die Handlung.
   Vollbild hat keinen Dauerzustand. */
.map__rail-item--on,
.map__rail-item:has(input:checked) {
  background: color-mix(in srgb, var(--c-type, var(--c-primary)) 34%, var(--c-surface));
  box-shadow: inset 3px 0 0 var(--c-type, var(--c-primary));
  color: var(--c-type, var(--c-primary-strong));
}

.map__rail-item--on:hover,
.map__rail-item:has(input:checked):hover {
  background: color-mix(in srgb, var(--c-type, var(--c-primary)) 44%, var(--c-surface));
}

.map__rail-item--on .icon,
.map__rail-item:has(input:checked) .icon {
  color: var(--c-type, var(--c-primary));
}

.map__rail-item--on:hover .icon,
.map__rail-item:has(input:checked):hover .icon {
  color: var(--c-type, var(--c-primary-strong));
}

.map__rail-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  opacity: 0;
  transition: opacity 140ms ease;
}

.map__rail-handle .map__rail-name {
  flex: 0 1 0;
  width: 0;
  min-width: 0;
}

.map__rail--open .map__rail-handle .map__rail-name {
  flex: 1 1 auto;
  width: auto;
}

.map__rail--open .map__rail-name {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .map__rail-name {
    transition: none;
  }
}

/* Verkehrsfluss: echte Checkbox, sichtbar bleibt nur das Symbol. Die
   Pillen der Meldungsarten verstecken die Checkbox in der Pille selbst;
   hier sagt die Farbe des Symbols an oder aus. */
.map__rail-item input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.map__rail-item:has(input:focus-visible),
.map__rail-handle:focus-visible,
.map__rail-item:focus-visible {
  outline: 3px solid var(--c-focus);
  outline-offset: -3px;
}

/* Hinweis auf Orts- und Autobahnkarten: nur dieser Bestand, alles andere
   steht auf der Startseite. Eine Leiste oben auf der Fläche, bündig an der
   linken Kante und vor der Einstellungsleiste. */
.map__scope {
  position: absolute;
  top: 0;
  left: 0;
  right: 2.5rem;
  z-index: 11;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  padding: 0.55rem 0.85rem 0.55rem 0.95rem;
  background: color-mix(in srgb, var(--c-surface) 94%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--c-border);
  box-shadow: var(--shadow-sm);
  color: var(--c-text);
  font-size: var(--t-small);
  line-height: 1.35;
}

.map__scope::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--grad-brand);
}

.map__rail--open ~ .map__scope {
  right: 12.6rem;
}

.map__scope .icon {
  width: 1.15rem;
  height: 1.15rem;
  color: var(--c-primary);
}

.map__scope-copy {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.55rem;
  margin: 0;
}

.map__scope-link {
  font-weight: 650;
  color: var(--c-primary);
  text-decoration: none;
  white-space: nowrap;
}

.map__scope-link:hover {
  color: var(--c-primary-strong);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.map:has(.map__scope) .map__status {
  top: 3.35rem;
}

/* Statusfeld über der Karte, links oben: es beschreibt, was gerade zu sehen
   ist, und darf dafür keine Zeile im Layout beanspruchen.

   Links unten stand es einmal – und lag damit auf der Legende: Die Bedienung
   ist im Layout durchsichtig (display: contents), ihre absoluten Teile beziehen
   sich also auf die ganze Kartenkarte, und deren Unterkante ist die Unterkante
   der Legendenzeile, nicht die der Kartenfläche. Oben links gibt es diese
   Verwechslung nicht: dort ist die Oberkante beider dieselbe. */
.map__status {
  position: absolute;
  top: var(--s-2);
  left: var(--s-2);
  right: 3.25rem;
  z-index: 10;
  margin: 0;
  padding: var(--s-1) var(--s-3);
  width: fit-content;
  max-width: calc(100% - 3.25rem);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--c-surface) 92%, transparent);
  backdrop-filter: blur(8px);
  color: var(--c-muted);
  font-size: var(--t-small);
  box-shadow: var(--shadow-sm);
}

.map__status:empty {
  display: none;
}

/* Der Knopf, mit dem ein Ausschnitt ins Radar wandert. Er sitzt auf der
   Kartenfläche, unten links – unabhängig von der Legende darunter. */
.map__radar {
  position: absolute;
  left: var(--s-2);
  top: calc(var(--map-canvas-h) - 3.4rem);
  z-index: 20;
}

.map__radar-add {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.55rem 0.95rem;
  border: 0;
  border-radius: var(--radius-pill);
  background-image: var(--grad-brand);
  color: #fff;
  font: inherit;
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: var(--shadow-brand);
  cursor: pointer;
}

.map__radar-add .icon {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
}

.map__radar-add:hover {
  color: #fff;
  filter: saturate(1.08) brightness(1.06);
}

.map__radar-add--done {
  background-image: none;
  background: color-mix(in srgb, var(--c-surface) 92%, transparent);
  color: var(--c-primary-strong);
  border: 1px solid color-mix(in srgb, var(--c-primary) 35%, var(--c-border));
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(8px);
}

.map__radar-add--done:hover {
  color: var(--c-primary-strong);
  filter: none;
  border-color: var(--c-primary);
}

.map--full .map__radar {
  top: auto;
  bottom: 6.5rem;
}

/* Berührungsregel vor der Zuwendung: senkrecht scrollt die Seite, damit ein
   Wischen über die Karte nicht in ihr endet. Nach dem Antippen setzt Leaflets
   eigene Regel wieder, und der Finger schiebt die Karte in jede Richtung.

   Die Klassen der Kartenfläche stehen beide im Selektor, weil Leaflets Regel
   `touch-action: none` gleich viele Klassen zählt und später geladen wird – ein
   kürzerer Selektor würde stillschweigend verlieren. */
.map:not(.map--engaged) .map__canvas.leaflet-container {
  touch-action: pan-y;
}

/* Hinweis in der Mitte der Karte, wenn das Rad noch der Seite gehört. Er liegt
   über der Kartenfläche, nimmt aber keine Klicks an: der Klick, auf den er
   hinweist, muss durch ihn hindurch bei der Karte ankommen. */
.map__hint {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
  margin: 0;
  padding: var(--s-2) var(--s-4);
  max-width: calc(100% - 2 * var(--s-5));
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--c-text) 88%, transparent);
  color: var(--c-bg);
  font-size: var(--t-small);
  font-weight: 600;
  text-align: center;
  box-shadow: var(--shadow-lg);
  pointer-events: none;
  animation: fade-in 120ms ease-out;
}

/* Bewegliche Blitzer unter Zoom 11: keine Koordinaten, nur dieser Hinweis.
   Er sitzt am unteren Rand der Kartenfläche, nicht in der Mitte, und fängt
   keine Klicks, damit Zoomen weiter die Karte trifft (D-079). */
.map__zoom-banner {
  position: absolute;
  top: var(--map-canvas-h);
  left: 50%;
  transform: translate(-50%, calc(-100% - var(--s-3)));
  z-index: 10;
  margin: 0;
  padding: var(--s-2) var(--s-4);
  max-width: calc(100% - 2 * var(--s-5));
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--c-text) 88%, transparent);
  color: var(--c-bg);
  font-size: var(--t-small);
  font-weight: 600;
  text-align: center;
  box-shadow: var(--shadow-lg);
  pointer-events: none;
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

/* Filterleiste unter der Karte. Sie gehört in den Fluss: eine Auswahl, die
   den Kartengrund überdeckt, verdeckt genau das, worüber sie entscheidet. */
.map__bar {
  padding: var(--s-3);
  border-top: 1px solid var(--c-border);
  background: var(--c-surface);
}

.map__barhead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
  margin-bottom: var(--s-2);
}

.map__barlabel {
  font-size: var(--t-small);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-muted);
  margin-right: auto;
}

.map__link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-primary);
  font: inherit;
  font-size: var(--t-small);
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.map__link:hover {
  color: var(--c-primary-strong);
}

/* Auf dem Telefon steht die Auswahl in einer Zeile und wird waagrecht
   geschoben. Umgebrochen belegten die neun Schalter dort 200 Pixel – mehr, als
   die Karte darunter an Höhe gewinnt. Ab 45rem reicht die Breite für den
   Umbruch, und dann ist die vollständige Übersicht das Bessere. */
.map__legend {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--s-2);
  margin: 0;
  /* Senkrecht Platz für den Fokusring, waagrecht für die letzte Pille. */
  padding: 3px;
  border: 0;
  /* Ein fieldset schrumpft von sich aus nicht unter seinen Inhalt: ohne diese
     Zeile wird die Leiste 1067 Pixel breit und von der Karte abgeschnitten,
     statt sich schieben zu lassen. */
  min-inline-size: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

.map__legend::-webkit-scrollbar {
  display: none;
}

@media (min-width: 45rem) {
  .map__legend {
    flex-wrap: wrap;
    overflow-x: visible;
  }
}

/* Echte Checkboxen statt der klickbaren div-Elemente des Altsystems: damit
   funktioniert die Legende auch mit Tastatur und Screenreader. Sichtbar ist
   davon nur die Zeichnung – die Pille selbst zeigt den Zustand. */
.map__legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  font-size: var(--t-small);
  font-weight: 550;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}

.map__legend-item input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.map__legend-item:has(input:focus-visible) {
  outline: 3px solid var(--c-focus);
  outline-offset: 2px;
}

/* Eine eingeschaltete Pille trägt die Farbe ihrer Meldungsart, nicht die der
   Marke. Neun Schalter in einer Markenfarbe hätten gezeigt, dass sie an sind, und
   verschwiegen, wozu sie gehören.

   Die Farbe bleibt die des eigenen Token-Satzes und nicht die der Zeichnung
   daneben: Sie verbindet die Pille mit der Meldungskarte und dem Balken in der
   Aufteilung, wo dieselbe Art in derselben Farbe steht. Die Zeichnungen kennen
   diese Unterscheidung nicht – bei ihnen sind alle Ereignisarten orange. */
.map__legend-item:has(input:checked) {
  border-color: color-mix(in srgb, var(--c-type, var(--c-primary)) 45%, var(--c-border));
  background: color-mix(in srgb, var(--c-type, var(--c-primary)) 9%, var(--c-surface));
  color: var(--c-type, var(--c-primary-strong));
}

.map__legend-item:not(:has(input:checked)) {
  color: var(--c-muted);
}

/* Die Zeichnung ist die Verbindung zwischen Schalter und Marker: dasselbe Bild
   in der Pille wie auf der Kartenfläche. Vorher stand hier ein Farbpunkt, der
   die Farbe teilte, aber nicht die Form (D-063).

   Ausgeschaltet verliert sie ihre Farbe: Ein Fünftel Sättigung, etwas
   abgedunkelt, nimmt der Pille die Behauptung, ihre Art liege auf der Karte –
   und lässt die Form deutlich genug stehen, dass die Legende weiter erklärt,
   was sie erklären soll. */
.map__pin {
  width: 1.625rem;
  height: 1.625rem;
  flex: none;
  /* Der obere Rand der Zeichnung ist Luft, der untere die Spitze. Ein kleiner
     Ausgleich stellt sie auf die Schriftlinie. */
  margin-block: -2px;
}

.map__legend-item:not(:has(input:checked)) .map__pin {
  filter: saturate(0.2) brightness(0.85) opacity(0.7);
}

/* Hinweis, dass die Auswahl im weiten Ausschnitt noch nicht greift. Er
   beansprucht eine ganze Zeile, damit er nicht zwischen den Schaltern
   verschwindet. */
.map__note {
  margin: var(--s-2) 0 0;
  color: var(--c-muted);
  font-size: var(--t-small);
}

/* Vollbild. Kein Fullscreen-API, sondern eine feste Positionierung: die
   Browser-Vollbildschicht nimmt die Seite aus dem Dokumentfluss, und die
   Bedienleiste der Island hinge dann außerhalb. So bleibt alles zusammen, und
   Escape schließt es genauso. */
.map--full {
  position: fixed;
  inset: 0;
  z-index: 60;
  margin: 0;
  border: 0;
  border-radius: 0;
  padding-bottom: env(safe-area-inset-bottom);
}

.map--full .map__canvas {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
}

.map--full .map__zoom-banner {
  /* Im Vollbild ist die Kartenhöhe flexibel; die Filterleiste bleibt unten
     im Fluss. Der Hinweis sitzt knapp darüber, nicht in der Bildmitte. */
  top: auto;
  bottom: 6.5rem;
  transform: translate(-50%, 0);
}

.map--full .map__rail {
  top: 0;
  right: 0;
}

/* Solange die Karte den Bildschirm füllt, soll die Seite darunter nicht
   mitscrollen. */
html:has(.map--full) {
  overflow: hidden;
}

/* Kartenmarker einzelner Meldungen: die Pin-Zeichnungen von Blitzer.de, von
   Leaflet als divIcon eingesetzt (D-063). Die Maße stehen zusätzlich als
   Attribute am Bild, weil Leaflet den Ankerpunkt daraus rechnet – hier steht
   nur, was das Bild darüber hinaus braucht.

   Der Schatten kommt aus dem Stylesheet und nicht als zweite Zeichnung unter
   dem Pin, wie in der App: eine Datei weniger je Marker, und die Form folgt
   der Zeichnung statt einer Ellipse darunter. */
.pin {
  display: block;
  filter: drop-shadow(0 2px 3px rgb(26 20 64 / 35%));
}

/* Sammelmarker. Sie sind keine Meldung, sondern eine Anzahl – ein Kreis mit
   dieser Zahl sagt das, eine Zeichnung nicht. */
.marker--cluster {
  display: grid;
  place-items: center;
  width: 2.375rem;
  height: 2.375rem;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 2px 6px rgb(26 20 64 / 40%);
  background: var(--c-cluster);
  color: #fff;
  font-size: var(--t-small);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Bewegliche Blitzer: Zahlen auf dem 4×3-Raster, Blitzerblau statt Grau,
   etwas größer, damit sie neben den übrigen Sammelpunkten als eigene Auskunft
   lesbar bleibt (D-079). */
.marker--camera-cluster {
  width: 2.75rem;
  height: 2.75rem;
  background: var(--c-camera);
}

.popup {
  font-size: var(--t-small);
  min-width: 12rem;
}

.popup__title {
  margin: 0 0 var(--s-1);
  font-weight: 650;
}

.popup__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0 var(--s-2);
  margin: 0;
  font-size: var(--t-small);
}

.popup__facts dt {
  color: var(--c-muted);
}

.popup__facts dd {
  margin: 0;
}

.popup__link {
  display: inline-block;
  margin-top: var(--s-2);
  font-size: var(--t-small);
  font-weight: 600;
}

/* Hülle des Markers. Leaflet setzt hier sonst leaflet-div-icon mit weißem
   Kasten und Rahmen; die eigene Klasse verhindert das. */
.marker-host {
  background: none;
  border: 0;
}

/* Stauverläufe werden als gestrichelte, laufende Linie dargestellt – das
   visuelle Merkmal des Altsystems, dort über setInterval erzeugt, hier über
   eine CSS-Animation ohne Zeitgeber im JavaScript. */
/* Die Linienfarbe kommt aus derselben Zuordnung wie die Marker. Leaflet setzt
   stroke über ein Attribut, das von dieser Regel überschrieben wird. */
.stretch {
  stroke: var(--c-type, var(--c-cluster));
  stroke-dasharray: 10 8;
  animation: flow 1.2s linear infinite;
}

/* Sperrungen zeichnet Leaflet in drei Lagen (Rand, Bahn, Baken). Die
   laufende Stau-Strichelung gilt für sie nicht – auch falls noch eine
   .stretch--closure-Klasse anliegt. */
.stretch--closure {
  animation: none;
}

/* Zeichen 250: roter Kreis, weißer Balken. Die Maße setzt Leaflet am Host. */
.closure-sign {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: #f92241;
  box-shadow: 0 0 0 1px #111, 0 1px 2px rgb(0 0 0 / 35%);
  position: relative;
}

.closure-sign::after {
  content: "";
  position: absolute;
  left: 18%;
  right: 18%;
  top: 42%;
  height: 16%;
  border-radius: 1px;
  background: #fff;
}

@keyframes flow {
  to {
    stroke-dashoffset: -18;
  }
}

/* Leaflets eigene Bedienelemente an das Design angepasst. Ohne diese Regeln
   sitzen quadratische Kästen mit 1px-Rahmen aus dem Jahr 2011 auf einer
   ansonsten runden Oberfläche. */
.leaflet-container {
  font-family: var(--font);
  background: var(--c-surface-2);
}

/* Die Wärmekarte fängt keine Zeiger: Zoomen und Verschieben gehören der Karte. */
.leaflet-heatmap-layer {
  pointer-events: none;
}

.leaflet-bar,
.leaflet-control-attribution {
  border: 1px solid var(--c-border) !important;
  border-radius: var(--radius-pill) !important;
  box-shadow: var(--shadow) !important;
  overflow: hidden;
}

.leaflet-bar a,
.leaflet-bar a:hover {
  width: 2.25rem;
  height: 2.25rem;
  line-height: 2.25rem;
  background: color-mix(in srgb, var(--c-surface) 92%, transparent);
  color: var(--c-text);
  border-bottom-color: var(--c-border);
  font-size: 1.25rem;
}

.leaflet-bar a:hover {
  color: var(--c-primary);
}

.leaflet-control-attribution {
  padding: 0 var(--s-2);
  background: color-mix(in srgb, var(--c-surface) 88%, transparent) !important;
  color: var(--c-muted);
  font-size: 0.6875rem;
}

.leaflet-control-attribution a {
  color: var(--c-muted);
}

.map-zoom-level {
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
}

.leaflet-popup-content-wrapper {
  border-radius: var(--radius) !important;
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--shadow-lg);
}

.leaflet-popup-content {
  margin: var(--s-3);
  line-height: 1.5;
}

.leaflet-popup-tip {
  background: var(--c-surface);
}

.leaflet-popup-close-button {
  color: var(--c-muted) !important;
  padding: var(--s-2) var(--s-2) 0 0 !important;
}

/* ------------------------------------------------------------ 8. Betrieb */

/* Der Betriebsbereich hat ein eigenes Gerüst und ein eigenes Farbbild.
   Lagebild-Tokens gelten hier nicht: kein Graphit-Verlauf, keine Kiefer,
   keine Aurora. Grund ist eigenes Schiefer, die Aktion ein Cyan – flache Flächen,
   engerer Radius, neutrale Schatten.

   Unter 62rem stapelt sich das: erst die Navigation als Streifen, dann der
   Inhalt. Die Einträge schieben waagrecht, damit sieben Punkte auf einem
   Telefon erreichbar bleiben, ohne die Seite zu verlängern. */
.admin-body {
  min-height: 100vh;
  --c-bg: #eef0f3;
  --c-surface: #ffffff;
  --c-surface-2: #e6e9ee;
  --c-surface-3: #d6dbe2;
  --c-text: #12171c;
  --c-muted: #5b6570;
  --c-border: #d3d8de;
  --c-border-strong: #b4bcc6;
  --c-primary: #0c6a82;
  --c-primary-strong: #084e60;
  --c-primary-soft: #e4f1f5;
  --c-accent: #0c6a82;
  --c-accent-strong: #084e60;
  --c-accent-soft: #e4f1f5;
  --c-focus: #0e7490;
  --c-action: #0b6474;
  --c-action-hover: #084e5b;
  --c-action-ink: #ffffff;
  --grad-brand: none;
  --grad-tint: none;
  --grad-aurora: none;
  --shadow-sm: 0 1px 2px rgb(18 23 28 / 6%);
  --shadow: 0 1px 2px rgb(18 23 28 / 5%), 0 6px 16px -8px rgb(18 23 28 / 14%);
  --shadow-lg: 0 2px 4px rgb(18 23 28 / 7%), 0 16px 36px -12px rgb(18 23 28 / 20%);
  --shadow-brand: none;
  --radius: 0.5rem;
  --radius-sm: 0.375rem;
  --radius-lg: 0.75rem;
  --radius-pill: 0.5rem;
  background: var(--c-bg);
  background-image: none;
  color: var(--c-text);
}

@media (prefers-color-scheme: dark) {
  .admin-body {
    --c-bg: #0d1014;
    --c-surface: #161a20;
    --c-surface-2: #1e242c;
    --c-surface-3: #272e38;
    --c-text: #e8edf2;
    --c-muted: #93a0ad;
    --c-border: #2c343e;
    --c-border-strong: #3d4754;
    --c-primary: #5ecad6;
    --c-primary-strong: #9adbe4;
    --c-primary-soft: #14343a;
    --c-accent: #5ecad6;
    --c-accent-strong: #9adbe4;
    --c-accent-soft: #14343a;
    --c-focus: #22d3ee;
    --c-action: #0b6474;
    --c-action-hover: #0e7d8f;
    --c-action-ink: #ffffff;
  }
}

.admin-body .button {
  background-image: none;
  background-color: var(--c-action);
  color: var(--c-action-ink);
  border-radius: var(--radius-sm);
  box-shadow: none;
}

.admin-body .button:hover {
  color: var(--c-action-ink);
  background-color: var(--c-action-hover);
  filter: none;
  transform: none;
}

.admin {
  min-height: 100vh;
  display: grid;
  align-items: start;
}

.admin__nav {
  background: var(--c-surface);
  border-bottom: 1px solid var(--c-border);
  padding: var(--s-3);
  display: grid;
  gap: var(--s-3);
}

.admin-brand {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: inherit;
  text-decoration: none;
  min-width: 0;
}

.admin-brand:hover {
  color: inherit;
}

.admin-brand__mark {
  width: 1.85rem;
  height: 1.85rem;
  flex: none;
  padding: 0.28rem;
  border-radius: var(--radius-sm);
  background: var(--c-action);
  color: var(--c-action-ink);
}

.admin-brand__text {
  display: grid;
  line-height: 1.2;
  min-width: 0;
}

.admin-brand__kicker {
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-primary);
}

.admin-brand__name {
  font-weight: 700;
  letter-spacing: -0.02em;
}

.admin-brand__tld {
  color: var(--c-muted);
  font-weight: 550;
}

.admin-menu {
  display: grid;
  gap: var(--s-5);
  min-width: 0;
  align-content: start;
}

.admin-menu__group {
  display: grid;
  gap: var(--s-4);
  align-content: start;
}

.admin-menu__title {
  display: block;
  margin: 0;
  padding: 0 0.45rem;
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.08em;
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--c-muted);
}

.admin-menu__list {
  display: grid;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.admin-menu__list li {
  min-width: 0;
}

.admin-menu__link {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0.35rem 0.55rem;
  border-radius: var(--radius-sm);
  color: var(--c-text);
  text-decoration: none;
  background: var(--c-surface-2);
  border: 1px solid transparent;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}

.admin-menu__link:hover {
  color: var(--c-primary-strong);
  background: var(--c-primary-soft);
  border-color: color-mix(in srgb, var(--c-primary) 22%, transparent);
}

.admin-menu__link--active {
  color: var(--c-primary-strong);
  background: var(--c-primary-soft);
  border-color: color-mix(in srgb, var(--c-primary) 28%, transparent);
  box-shadow: var(--shadow-sm);
}

.admin-menu__icon {
  display: grid;
  place-items: center;
  width: 1.35rem;
  height: 1.35rem;
  flex: none;
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-primary);
}

.admin-menu__icon .icon {
  width: 0.9rem;
  height: 0.9rem;
}

.admin-menu__link--active .admin-menu__icon {
  background: var(--c-action);
  color: var(--c-action-ink);
}

.admin-menu__copy {
  display: grid;
  gap: 0;
  min-width: 0;
}

.admin-menu__label {
  font-weight: 650;
  line-height: 1.15;
}

.admin-menu__hint {
  display: none;
  font-size: 0.6875rem;
  color: var(--c-muted);
  line-height: 1.2;
}

@media (max-width: 61.98rem) {
  .admin-menu {
    display: flex;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: var(--s-2);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    padding-bottom: var(--s-1);
  }

  .admin-menu__group {
    display: contents;
  }

  .admin-menu__title {
    display: none;
  }

  .admin-menu__list {
    display: flex;
    gap: var(--s-1);
  }

  .admin-menu__list li {
    flex: none;
  }
}

.admin__stage {
  min-width: 0;
  padding: var(--s-5) var(--s-4) var(--s-7);
}

.admin-top {
  margin-bottom: var(--s-5);
}

.admin-top .lead {
  margin-bottom: 0;
}

.admin-empty {
  display: grid;
  justify-items: start;
  gap: var(--s-3);
  padding: var(--s-6);
  border-radius: var(--radius-lg);
  background: var(--c-surface);
  border: 1px dashed var(--c-border-strong);
  box-shadow: var(--shadow-sm);
  max-width: 40rem;
}

.admin-empty h2 {
  margin: 0;
}

.admin-empty p {
  margin: 0;
  color: var(--c-muted);
  max-width: 32rem;
}

.admin-empty__mark {
  display: flex;
  gap: 0.45rem;
  margin-bottom: var(--s-1);
}

.admin-empty__dot {
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  background: var(--c-action);
  opacity: 0.45;
}

.admin-empty__dot:nth-child(2) {
  opacity: 0.7;
  transform: translateY(-0.15rem);
}

.admin-empty__dot:nth-child(3) {
  opacity: 1;
}

.admin-panel {
  display: grid;
  gap: var(--s-5);
  max-width: 72rem;
}

.admin-panel__head h2 {
  margin: 0 0 var(--s-2);
}

.admin-panel__head p {
  margin: 0;
  color: var(--c-muted);
  max-width: 46rem;
}

.admin-flash,
.admin-note,
.admin-error,
.admin-path {
  margin: 0;
}

.admin-flash {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--radius);
  background: var(--c-primary-soft);
  border: 1px solid color-mix(in srgb, var(--c-primary) 28%, transparent);
}

.admin-note,
.admin-path {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.admin-error {
  color: #8b1e1e;
}

@keyframes admin-warn-blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0.12; }
}

.admin-anomaly {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  margin: 0.85rem 0 0;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius);
  background: #8b1e1e;
  color: #fff8f8;
  font-weight: 650;
  line-height: 1.35;
}

.admin-anomaly__icon,
.admin-import__warn {
  flex: none;
  width: 1.2rem;
  height: 1.2rem;
  animation: admin-warn-blink 0.9s step-end infinite;
}

.admin-menu__link--alert,
.admin-menu__link--alert:hover,
.admin-menu__link--alert.admin-menu__link--active {
  color: #fff8f8;
  background: #8b1e1e;
  border-color: #6d1515;
}

.admin-menu__link--alert .admin-menu__hint {
  color: #ffd4d4;
}

.admin-menu__link--alert .admin-menu__icon {
  background: #6d1515;
  color: #ffe08a;
}

.admin-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
}

button.button {
  border: 0;
  cursor: pointer;
  font: inherit;
}

button.button:disabled {
  opacity: 0.55;
  cursor: wait;
  transform: none;
  filter: none;
}

.admin-stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: var(--s-3);
  margin: 0;
}

.admin-stats > div {
  padding: var(--s-3);
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
}

.admin-stats dt {
  font-size: 0.75rem;
  color: var(--c-muted);
}

.admin-stats dd {
  margin: 0.2rem 0 0;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  overflow: hidden;
}

.admin-table caption {
  text-align: left;
  font-weight: 650;
  padding-bottom: var(--s-2);
}

.admin-table th,
.admin-table td {
  text-align: left;
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--c-border);
  font-variant-numeric: tabular-nums;
}

.admin-table th {
  font-size: 0.75rem;
  color: var(--c-muted);
  font-weight: 650;
}

.admin-table tr:last-child td {
  border-bottom: 0;
}

.admin-table__hot td {
  background: color-mix(in srgb, var(--c-danger, #b42318) 8%, transparent);
}

.admin-table__local {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.admin-table__ref {
  display: inline-block;
  max-width: 28rem;
  overflow-wrap: anywhere;
  font-size: var(--t-small);
}

.admin-table__ref--own {
  color: var(--c-muted);
  font-weight: 400;
}

.admin-panel--stats {
  max-width: 52rem;
}

.stat-card {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-5);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.stat-card--hour {
  gap: var(--s-3);
}

.stat-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
}

.stat-card__head h2 {
  margin: 0 0 0.2rem;
  font-size: 1.05rem;
}

.stat-card__head p {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--t-small);
}

.stat-card__sum {
  margin: 0;
  text-align: right;
  color: var(--c-muted);
  font-size: var(--t-small);
}

.stat-card__sum span {
  display: block;
  color: var(--c-text);
  font-size: 1.55rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.stat-card__plot {
  margin: 0 -0.25rem;
}

.stat-card__foot {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--t-small);
  font-variant-numeric: tabular-nums;
}

.stat-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.2rem;
  background: var(--c-surface-2);
  border-radius: var(--radius-pill);
}

.stat-pills__item {
  display: inline-flex;
  align-items: center;
  padding: 0.35rem 0.75rem;
  border-radius: calc(var(--radius-pill) - 0.1rem);
  color: var(--c-muted);
  font-size: 0.8125rem;
  font-weight: 650;
  text-decoration: none;
}

.stat-pills__item:hover {
  color: var(--c-text);
  background: color-mix(in srgb, var(--c-surface) 70%, transparent);
}

.stat-pills__item--on,
.stat-pills__item--on:hover {
  color: var(--c-text);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.stat-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.stat-legend__item {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  font-size: 0.875rem;
}

.stat-legend__swatch {
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 999px;
  background: var(--c-muted);
}

.stat-legend__name {
  color: var(--c-muted);
}

.stat-legend__num {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.stat-legend__item--verkehrslage .stat-legend__swatch {
  background: #0c6a82;
}

.stat-legend__item--map-atudo .stat-legend__swatch {
  background: #c45c26;
}

.stat-legend__item--maplibre .stat-legend__swatch {
  background: #5a4fcf;
}

.stat-chart {
  display: block;
  width: 100%;
  height: auto;
}

.stat-chart__grid {
  stroke: var(--c-border);
  stroke-width: 1;
}

.stat-chart__ytick {
  fill: var(--c-muted);
  font-size: 10px;
  text-anchor: end;
}

.stat-chart__xtick {
  fill: var(--c-muted);
  font-size: 10px;
  text-anchor: middle;
}

.stat-chart__bar--verkehrslage {
  fill: #0c6a82;
}

.stat-chart__bar--map-atudo {
  fill: #c45c26;
}

.stat-chart__bar--maplibre {
  fill: #5a4fcf;
}

.stat-chart__zero {
  fill: var(--c-surface-3);
}

@media (prefers-color-scheme: dark) {
  .stat-legend__item--verkehrslage .stat-legend__swatch,
  .stat-chart__bar--verkehrslage {
    background: #5ecad6;
    fill: #5ecad6;
  }

  .stat-legend__item--map-atudo .stat-legend__swatch,
  .stat-chart__bar--map-atudo {
    background: #f0a36a;
    fill: #f0a36a;
  }

  .stat-legend__item--maplibre .stat-legend__swatch,
  .stat-chart__bar--maplibre {
    background: #9b93f0;
    fill: #9b93f0;
  }
}

.admin-table--schema td:first-child code {
  font-size: 0.8125rem;
  word-break: break-all;
}

.admin-table--schema td:nth-child(2) {
  white-space: nowrap;
  color: var(--c-muted);
}

.admin-table--schema td:last-child {
  color: var(--c-muted);
}

.admin-services {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14.5rem, 1fr));
  gap: var(--s-3);
}

.admin-dash {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr));
  gap: var(--s-3);
}

.admin-dash__item {
  display: grid;
  gap: var(--s-2);
  align-content: start;
}

.admin-dash__card {
  display: grid;
  gap: 0.3rem;
  padding: var(--s-3);
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  text-decoration: none;
  color: inherit;
}

.admin-dash__card:hover {
  border-color: color-mix(in srgb, var(--c-primary) 40%, var(--c-border));
}

.admin-dash__name {
  font-weight: 650;
}

.admin-dash__path {
  font-size: var(--t-small);
  color: var(--c-muted);
  overflow-wrap: anywhere;
}

.admin-dash__state {
  margin-top: 0.2rem;
  font-size: var(--t-small);
  font-weight: 650;
}

.admin-dash__item--off {
  filter: grayscale(1);
  opacity: 0.55;
}

.admin-dash__item--off .admin-dash__card,
.admin-dash__item--off .admin-dash__card:hover {
  background: color-mix(in srgb, var(--c-muted) 14%, var(--c-surface));
  border-color: var(--c-border);
  color: var(--c-muted);
}

.admin-dash__item--off .admin-dash__path,
.admin-dash__item--off .admin-dash__state,
.admin-dash__item--off .admin-dash__num,
.admin-dash__item--off .admin-dash__unit {
  color: var(--c-muted);
}

.admin-dash__hits {
  margin: 0;
  padding: 0 var(--s-1);
}

.admin-dash__num {
  display: block;
  font-size: 1.45rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.admin-dash__unit {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.75rem;
  color: var(--c-muted);
}

.admin-service {
  display: grid;
  gap: var(--s-2);
  align-content: start;
  min-width: 0;
  padding: var(--s-3);
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
}

.admin-service:hover {
  border-color: color-mix(in srgb, var(--c-primary) 40%, var(--c-border));
}

.admin-service--off {
  filter: grayscale(1);
  opacity: 0.7;
  border-color: var(--c-border);
}

.admin-service__link {
  display: grid;
  gap: 0.2rem;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}

.admin-service__link:hover .admin-service__name {
  text-decoration: underline;
}

.admin-service__name {
  font-weight: 650;
}

.admin-service__path {
  font-size: var(--t-small);
  color: var(--c-muted);
  overflow-wrap: anywhere;
}

.admin-service__lead {
  font-size: var(--t-small);
  color: var(--c-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.admin-service__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin-top: 0.15rem;
}

.admin-service__meta {
  margin: 0;
  font-size: var(--t-small);
  color: var(--c-muted);
}

.admin-service__form .button {
  padding: 0.35rem 0.7rem;
  font-size: var(--t-small);
}

.admin-tokens {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-4);
}

.admin-panel--import {
  max-width: 80rem;
}

.admin-import {
  display: grid;
  gap: var(--s-5);
}

.admin-import__nav {
  display: grid;
  align-content: start;
  gap: 0.15rem;
  margin: 0;
  padding: 0.25rem;
  border-radius: var(--radius);
  background: var(--c-surface-2);
  border: 1px solid var(--c-border);
}

.admin-import__family {
  display: grid;
  gap: 0.1rem;
  margin-top: 0.2rem;
  padding-top: 0.2rem;
  border-top: 1px solid var(--c-border);
}

.admin-import__family-label {
  margin: 0;
  padding: 0.2rem 0.65rem 0.05rem;
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-muted);
}

.admin-import__link {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.2rem 0.75rem;
  align-items: baseline;
  padding: 0.45rem 0.65rem;
  border-radius: var(--radius-sm);
  color: var(--c-muted);
  text-decoration: none;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.25;
}

.admin-import__link--child {
  padding-left: 1.15rem;
}

.admin-import__link:hover {
  color: var(--c-primary-strong);
  background: var(--c-primary-soft);
}

.admin-import__link--active {
  color: var(--c-primary-strong);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.admin-import__name {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  overflow-wrap: anywhere;
}

.admin-import__meta {
  font-size: 0.75rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--c-muted);
}

.admin-import__link--active .admin-import__meta {
  color: var(--c-primary);
}

.admin-import__link--alert,
.admin-import__link--alert:hover,
.admin-import__link--alert.admin-import__link--active {
  color: #fff8f8;
  background: #8b1e1e;
}

.admin-import__link--alert .admin-import__meta,
.admin-import__link--alert.admin-import__link--active .admin-import__meta {
  color: #ffe08a;
}

.admin-import__link--alert .admin-import__warn {
  color: #ffe08a;
}

.admin-row--family td {
  padding-top: 0.7rem;
  padding-bottom: 0.35rem;
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--c-muted);
  background: var(--c-surface-2);
}

.admin-row--child td:first-child {
  padding-left: 1.5rem;
}

.admin-row--alert td {
  background: #8b1e1e;
  color: #fff8f8;
}

.admin-row--alert a {
  color: #fff8f8;
}

.admin-row--alert .admin-import__warn {
  vertical-align: -0.15em;
  margin-right: 0.35rem;
  color: #ffe08a;
}

.admin-source:has(.admin-anomaly) {
  border-color: #8b1e1e;
  box-shadow: 0 0 0 1px #8b1e1e;
}

@media (prefers-reduced-motion: reduce) {
  .admin-anomaly__icon,
  .admin-import__warn {
    animation: none;
  }
}

.admin-import__stage {
  min-width: 0;
}

@media (min-width: 48rem) {
  .admin-import {
    grid-template-columns: 13.5rem minmax(0, 1fr);
    align-items: start;
  }

  .admin-import__nav {
    position: sticky;
    top: var(--s-4);
  }
}

.admin-source {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-4);
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
}

.admin-source h3 {
  margin: 0 0 0.35rem;
  font-size: 0.95rem;
}

.admin-source p {
  margin: 0;
  color: var(--c-muted);
  max-width: 42rem;
}

.admin-source__related {
  margin-top: 0.55rem;
}

.admin-source__related a {
  font-weight: 650;
}

.admin-source .admin-anomaly {
  color: #fff8f8;
}

.admin-source .admin-error {
  color: #8b1e1e;
}

.admin-source__meta {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: 0.35rem 0.75rem;
  align-items: baseline;
  margin-top: 0.55rem;
  color: inherit;
}

.admin-source__meta span {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.admin-source__meta code {
  overflow-wrap: anywhere;
  font-size: var(--t-small);
}

.admin-panel--apis {
  max-width: 80rem;
}

.admin-api {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
}

.admin-api h2 {
  margin: 0 0 0.35rem;
  font-size: 0.95rem;
}

.admin-api .admin-panel__head {
  margin: 0;
}

.admin-api__url {
  display: inline-block;
  max-width: 36rem;
  overflow-wrap: anywhere;
  font-size: var(--t-small);
}

.admin-api__note {
  margin: 0.35rem 0 0;
  font-weight: 400;
  color: var(--c-muted);
  max-width: 36rem;
}

.admin-source__form {
  display: grid;
  gap: var(--s-3);
}

.admin-source__form label {
  display: grid;
  gap: 0.35rem;
}

.admin-source__label {
  font-size: var(--t-small);
  color: var(--c-muted);
}

.admin-source__form select {
  width: min(100%, 18rem);
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-bg);
  color: inherit;
  font: inherit;
}

.admin-source__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.admin-source__data {
  display: grid;
  gap: var(--s-4);
}

@media (min-width: 62rem) {
  .admin-source:not(.admin-source--overview) {
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
    align-items: start;
  }

  .admin-source__data {
    grid-column: 1 / -1;
  }
}

.admin-token {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-4);
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
}

.admin-token h3 {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
}

.admin-token p {
  margin: 0;
  color: var(--c-muted);
  max-width: 42rem;
}

.admin-token__meta {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: 0.35rem 0.75rem;
  align-items: baseline;
  margin-top: 0.55rem;
  color: inherit;
}

.admin-token__meta span {
  color: var(--c-muted);
  font-size: var(--t-small);
}

.admin-token__meta code {
  overflow-wrap: anywhere;
  font-size: var(--t-small);
}

.admin-token__form {
  display: grid;
  gap: var(--s-3);
}

.admin-token__form label {
  display: grid;
  gap: 0.35rem;
}

.admin-token__label {
  font-size: var(--t-small);
  color: var(--c-muted);
}

.admin-token__form input[type="text"],
.admin-token__form input[type="password"],
.admin-token__form input[type="url"],
.admin-token__form select {
  width: min(100%, 28rem);
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-bg);
  color: inherit;
  font: inherit;
}

.admin-token__form input[type="url"] {
  width: 100%;
  max-width: 40rem;
}

.admin-token__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.admin-inline {
  display: inline-flex;
  margin: 0;
}

.admin-bootstrap {
  margin: 0 0 var(--s-4);
  padding: var(--s-3);
  border: 1px solid color-mix(in srgb, var(--c-primary) 40%, var(--c-border));
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--c-primary) 10%, var(--c-surface));
}

.admin-bootstrap h3 {
  margin: 0 0 var(--s-2);
}

.admin-bootstrap__secret {
  display: block;
  margin: var(--s-2) 0;
  padding: 0.55rem 0.7rem;
  font-size: 1.05rem;
  word-break: break-all;
}

.admin-body--login {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

.admin-login {
  width: min(26rem, calc(100vw - 2rem));
  padding: var(--s-5);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
}

.admin-login h1 {
  margin: 0 0 var(--s-2);
}

@media (min-width: 62rem) {
  .admin-token {
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
    align-items: start;
  }

  .admin-token--url {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (min-width: 62rem) {
  .admin {
    grid-template-columns: var(--w-admin-nav) minmax(0, 1fr);
  }

  .admin__nav {
    position: sticky;
    top: 0;
    align-self: start;
    border-bottom: 0;
    border-right: 1px solid var(--c-border);
    padding: var(--s-3) var(--s-3) var(--s-4);
    gap: var(--s-2);
    background: var(--c-surface);
  }

  .admin-menu {
    overflow: visible;
    padding: 0;
  }

  .admin-menu__link {
    width: 100%;
    padding: 0.4rem 0.5rem;
  }

  .admin-menu__hint {
    display: block;
  }

  .admin__stage {
    padding: var(--s-6) var(--s-6) var(--s-7);
  }
}

/* --------------------------------------------------- 9. Bewegung und Druck */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .site-header,
  .site-footer__nav,
  .layout__rail,
  .map,
  .search,
  .pagination,
  .skiplink,
  .admin__nav {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
    background-image: none;
  }

  .layout {
    display: block;
    padding: 0;
  }

  .card,
  .message,
  .panel {
    border: 1px solid #999;
    box-shadow: none;
    break-inside: avoid;
  }
}
