/* tokens.css — der EINE Token-Satz. K4 (#482), UI-Konzept §5.
   =====================================================================

   Warum es diese Datei gibt
   -------------------------
   BEFUND-UX-18, gemessen am 02.09.2026: **vier** Design-Sprachen ueber
   fuenf Seiten. `app.css` fuehrte 83 Tokens, `planfenster.css` 15,
   `bericht.html` 15, `bericht-bezirke.html` 15, `entwurf-planung.html` 15,
   `vergleich-ptv.html` 10 — jede Seite ihren eigenen Satz, vier davon mit
   einer eigenen Schrift von einem fremden Server.

   Ein Token-Satz je Seite ist kein Token-Satz. Er ist eine Absprache, die
   niemand geschlossen hat: `--border` stand mit SECHS verschiedenen
   Rueckfallwerten im Code (#e8e8e8, #eee, #d8dde5, #e2e6ea, #e8ebee,
   #d7dce2), ohne je definiert zu sein. Ein Screenshot fuer ein Angebot sah
   deshalb zweimal verschieden aus, je nachdem, welche Datei ihn gemalt hat.

   Was hier steht und was nicht
   ----------------------------
   HIER stehen Farbe, Schrift, Groessen, Abstaende, Radien, Schatten, Mass
   und Bewegung — alles, was mehr als eine Seite braucht.

   NICHT hier steht die Dokument-Palette der drei Berichtsseiten
   (`--papier`, `--tinte`): sie sind gesetzte Dokumente mit eigener
   Anmutung, und ihr Inhalt ist nach I2 ein eigenes Ticket (#623). Sie
   holen sich von hier den Schriftstapel — und nur den.

   Ladepfad
   --------
   `index.html` laedt die Datei VOR `app.css` und `planfenster.css`; das
   Versions-Token `?v=` kommt aus `_compute_asset_version()` in
   `webapp/app.py`, das `static/*.css` per Glob einsammelt — kein
   Bau-Schritt, kein Bundler. Die vier Standalone-Seiten laden sie ohne
   Token: `/static` liefert `Cache-Control: no-cache, no-store` (siehe
   `_NoCacheStaticFiles`), sie koennen also gar nicht veralten.

   Gates: tests/js/gates.test.mjs (K4-Block),
          tests/js/schrift-auslieferung.test.mjs (die Schriftdateien) und
          tests/js/zustandsfarben.test.mjs (K2, liest diese Datei mit).
   ===================================================================== */

/* =====================================================================
   Die drei Schriften — selbst ausgeliefert, aus `webapp/static/fonts/`
   =====================================================================

   Warum sie hier stehen und nicht bei Google
   ------------------------------------------
   Bis zum 08.09.2026 holten sich vier Seiten sechs Schriftfamilien bei
   Google Fonts. Auf einer Kundeninstanz ist das ein Abruf bei einem
   Dritten — bei jedem Seitenaufruf, mit der IP-Adresse des Kunden.

   E16 (07.09.2026) wollte die Abrufe deshalb ersatzlos streichen, auf der
   Praemisse, `Inter` werde ohnehin „nie geladen". Am 08.09.2026 wurde
   nachgemessen: die Praemisse war FALSCH. `index.html` lud Inter und
   JetBrains Mono; wer die Anwendung mit Netz oeffnete, hat sie gesehen —
   zwei Monate lang war Inter die Schrift der Oberflaeche. Richtig an der
   Messung war „kein `@font-face`, keine .woff im Repo"; der Schluss daraus
   war es nicht.

   Emil hat entschieden: das Aussehen bleibt, die Abrufe gehen. Also
   liefert Compas die Schriften selbst aus. Gegenueber dem bisherigen
   Online-Stand ist damit KEIN Schriftwechsel sichtbar; sichtbar anders ist
   nur der Fall ohne Netz — dort stand vorher die Systemschrift, jetzt
   steht Inter.

   Relativer Pfad, nicht `/static/fonts/…`
   ---------------------------------------
   `url()` wird gegen die Adresse des STYLESHEETS aufgeloest, nicht gegen
   die des Dokuments. `tokens.css` liegt neben `fonts/` und neben den fuenf
   Seiten, also trifft `url(fonts/…)` beide Faelle: `/static/tokens.css` am
   Server und `file:///…/webapp/static/tokens.css` in der Berichtsseite,
   die verschickt wird. Ein absoluter Pfad traefe im zweiten Fall die
   Wurzel der Platte (derselbe Fehler wie beim Stylesheet-Link selbst).

   Kein `?v=` an diesen Adressen
   -----------------------------
   Die anderen statischen Dateien tragen ein `?v=<hash>` aus
   `_compute_asset_version()`. Schriftdateien brauchen es nicht: `/static`
   antwortet mit `Cache-Control: no-cache, no-store, must-revalidate`
   (`_NoCacheStaticFiles` in `webapp/app.py`), sie werden also ohnehin bei
   jedem Aufruf frisch geholt. Der Preis dafuer steht in
   `fonts/HERKUNFT.md` — dort auch Quelle, Version und Pruefsumme jeder
   Datei (I2).

   `font-display: swap`: der Text steht sofort in der Rueckfallschrift und
   wird ausgetauscht, sobald die Datei da ist. Ohne das haelt der Browser
   ihn bis zu drei Sekunden unsichtbar.
   ===================================================================== */

/* Inter — vier Schnitte, genau die vier, die vorher bei Google bestellt
   waren (`Inter:wght@400;500;600;700`). Bewusst keine Variable-Datei:
   Inter 4 traegt eine `opsz`-Achse, die der Browser selbst verstellt;
   Google lieferte statische Schnitte bei `opsz` 14. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/Inter-Regular.woff2) format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(fonts/Inter-Medium.woff2) format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(fonts/Inter-SemiBold.woff2) format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(fonts/Inter-Bold.woff2) format("woff2");
}

/* JetBrains Mono — 400 (8x), 500 (6x) und 600 (2x) stehen in der
   `font`-Kurzform; alle drei waren bei Google bestellt. */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/JetBrainsMono-Regular.woff2) format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(fonts/JetBrainsMono-Medium.woff2) format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(fonts/JetBrainsMono-SemiBold.woff2) format("woff2");
}

/* Newsreader — hier DOCH die Variable-Datei, und zwar aus demselben Grund,
   aus dem Inter sie nicht bekommt: die Berichtsseiten hatten die
   `opsz`-Achse ausdruecklich bestellt (`opsz,wght@6..72,300;400;500;600`).
   Eine Datei deckt 200-800 ab und ist kleiner als drei statische Schnitte.
   Kursiv wird nicht ausgeliefert — keine Seite setzt kursive Serifen. */
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url(fonts/Newsreader-Variable.woff2) format("woff2");
}

:root {
  /* --- Flaechen ------------------------------------------------------ */
  --bg-app:          #ffffff;     /* Programmhintergrund */
  --bg-panel:        #ffffff;     /* Seitenleiste / Detail */
  --bg-subtle:       #fafafa;     /* zweite Flaeche, Hover */
  --bg-muted:        #f5f5f5;     /* dritte Flaeche */
  --bg-scrim:        rgba(10, 10, 10, 0.32);

  /* --- Tinte --------------------------------------------------------- */
  --ink-strong:      #0a0a0a;     /* Ueberschriften, Kennzahlen */
  --ink-body:        #1f1f1f;     /* Fliesstext */
  --ink-muted:       #737373;     /* zweite Beschriftung */
  --ink-faint:       #a3a3a3;     /* Platzhalter */

  /* --- Linien -------------------------------------------------------- */
  --line-faint:      #f4f4f5;
  --line:            #ebebeb;
  --line-strong:     #d4d4d4;

  /* --- Akzent: fast schwarz, sparsam benutzt ------------------------- */
  --accent-50:       #f4f4f5;
  --accent-100:      #e4e4e7;
  --accent-200:      #d4d4d8;
  --accent-500:      #0a0a0a;     /* Grundton */
  --accent-600:      #000000;     /* Hover */
  --accent-700:      #000000;     /* Aktiv */

  /* Fokusring. R20 (#291), BEFUND-UX-07: der alte Wert rgba(10,10,10,0.14)
     ergab auf Weiss einen Kontrast von 1,36:1 — WCAG 2.4.11 verlangt 3:1.
     0,55 Schwarz auf Weiss blendet zu #787878 und misst 4,4:1. Der Ring soll
     zurueckhaltend WIRKEN, aber sichtbar SEIN. */
  --focus-ring:      rgba(10, 10, 10, 0.55);

  /* --- Warn-Skala ---------------------------------------------------- */
  /* K4 (#482): `--warn-500` (#f59e0b) ist entfallen. Es war der ZWEITE
     Bernsteinwert und stand in drei Paaren direkt neben dem ersten, jeweils
     an zwei Stufen DERSELBEN Skala (`.alert-under` gegen `.alert-vorbehalt`,
     `.termin-check.warn` gegen `.bad`). Zwei Bernsteintoene fuer zwei Stufen
     einer Skala sind derselbe Fehler wie vier Rottoene fuer eine Bedeutung,
     nur eine Etage tiefer: die Farbe unterscheidet, wo das Gewicht
     unterscheiden sollte. Nebenbei: #f59e0b auf Weiss misst 2,1:1, der eine
     verbliebene Ton #b45309 misst 5,0:1 (nachgerechnet nach WCAG 2.1:
     5,0216 — nicht 5,2, wie hier bis zur Skeptiker-Runde stand).
     Grun gibt es nicht mehr — `--ok-500`/`--ok-50` waren seit K2 (#616)
     unbenutzt: ein Plan, den nichts blockiert, traegt keine Farbe. */
  --warn-50:         #fffbeb;
  --warn-100:        #fef3c7;
  --warn-200:        #fde68a;
  --warn-700:        #b45309;
  --warn-900:        #92400e;

  /* --- Zustand — GENAU ZWEI Bedeutungen. Kein Gruen. -----------------
     K2 (#616), UI-Konzept §5.1. Vorher standen hier sechs Danger-Stufen, und
     auf der Kartenflaeche trugen vier davon vier VERSCHIEDENE Aussagen:
     `#b91c1c` das Verdikt UND den Rail-Zaehler „1.128", `#dc2626` dasselbe
     Verdikt im Banner, `#ef4444` „1.088 Filialen unbedient", `#c62828` die
     Ampel auf den Mitarbeiterzeilen. Vier Rottoene sind nicht vier
     Bedeutungen — sie sind eine Bedeutung, die viermal verloren geht.

       Rot        eine harte Grenze ist verletzt ODER nicht bewiesen (I4).
                  Das Ding darf nicht raus.
       Bernstein  schraenkt die Aussage ein, sperrt aber nicht.
       Tinte      ein Messwert — auch ein unangenehmer. Traegt keine Farbe.

     Bernstein zeigt bewusst auf die Warn-Skala statt einen zweiten
     Zahlenwert zu fuehren. Gate: tests/js/zustandsfarben.test.mjs. */
  --zustand-sperrt:          #b91c1c;
  --zustand-sperrt-weich:    #fef2f2;
  --zustand-sperrt-linie:    #fecaca;
  --zustand-vorbehalt:       var(--warn-700);
  --zustand-vorbehalt-weich: var(--warn-50);
  --zustand-vorbehalt-linie: var(--warn-200);

  /* --- Identitaet: Handelskette. Zugehoerigkeit, keine Bedeutung. ---
     NP-Markt ist eine rote Marke. Der Ton steht hier unter seinem
     Bedeutungs-Namen, damit das Gate ihn nicht mit einem Zustand
     verwechselt — und damit niemand ihn fuer einen haelt. */
  --marke-np-grund:  #fff1f1;
  --marke-np-linie:  #e69a9a;
  --marke-np-ink:    #9c1f28;

  /* Grundton einer Gebiets-Stecknadel. `map.js` setzt am Element
     `--pin-color:<Gebietsfarbe>` und schlaegt diesen Wert damit; hier steht
     nur, was gilt, solange kein Gebiet zugeordnet ist. Bis K4 stand er als
     `var(--pin-color, #64748b)` im Stylesheet — ein Token ohne Definition
     ist ein Rueckfallwert mit Tarnkappe. */
  --pin-color:       #64748b;

  /* --- Schrift -------------------------------------------------------
     Drei Stapel, drei Familien — und jede fuehrende Familie liegt als
     Datei unter `fonts/` (die `@font-face`-Bloecke stehen ueber diesem
     Block, samt Begruendung). Was dahinter steht, ist Rueckfall fuer die
     Sekunde, in der die Datei noch nicht da ist, und fuer den Fall, dass
     sie es nie wird.

     Was sich am Aussehen aendert: gegenueber dem bisherigen ONLINE-Stand
     nichts in der Anwendung — Inter und JetBrains Mono kamen bisher von
     Google, jetzt aus dem eigenen Verzeichnis. Sichtbar anders ist der
     Fall OHNE Netz: dort stand vorher die Systemschrift, jetzt steht
     Inter. Auf den drei Berichtsseiten aendert sich mehr: `Source Sans 3`
     wird zu Inter, `IBM Plex Mono` zu JetBrains Mono und `Fraunces` zu
     Newsreader. Drei Familien fuer drei Stapel; eine vierte waere eine
     vierte Design-Sprache, und genau davon handelt BEFUND-UX-18. */
  --font-sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono:  "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --font-serif: "Newsreader", Georgia, serif;

  /* --- Schriftgroessen: sieben Stufen (§5.2) -------------------------
     Rohe Werte werden auf die naechste Stufe gerundet; bei Gleichstand auf
     die groessere (11,5 -> 12; 12,5 -> 13). Rueckfallwerte gibt es nicht:
     `--fs-xs` stand bis K4 mit DREI verschiedenen im Code (10, 11, 12) bei
     einer Definition von 10 px. Ein Token mit drei Werten ist kein Token. */
  --fs-xs:   10px;
  --fs-sm:   11px;
  --fs-base: 12px;
  --fs-md:   13px;
  --fs-lg:   15px;
  --fs-xl:   22px;
  --fs-2xl:  28px;

  /* --- Abstaende (§5.3, E17) -----------------------------------------
     Die Skala hiess 4/8/12/16/20/24/32/40 und traf die Wirklichkeit nicht:
     die zwei haeufigsten ROHEN Werte in `app.css` waren 6 px (73x) und
     10 px (60x) — beide fehlten. (E17 nannte 72x/58x; nachgemessen auf
     392d8cb mit dem Rezept aus `gates.test.mjs` sind es 73 und 60.) E17 hat entschieden, die Skala an die
     Wirklichkeit anzupassen statt umgekehrt: 2, 6 und 10 kommen dazu.

     Der Name traegt den Wert. `--space-3` verschwieg, dass es 12 px sind,
     und lud damit zum Raten ein; `--sp-12` tut das nicht. */
  --sp-2:   2px;
  --sp-4:   4px;
  --sp-6:   6px;
  --sp-8:   8px;
  --sp-10: 10px;
  --sp-12: 12px;
  --sp-16: 16px;
  --sp-20: 20px;
  --sp-24: 24px;
  --sp-32: 32px;
  --sp-40: 40px;

  /* --- Radien -------------------------------------------------------- */
  --radius-sm: 3px;
  --radius:    4px;
  --radius-md: 6px;
  --radius-lg: 8px;

  /* --- Schatten (fast keiner — es tragen die 1px-Linien) ------------- */
  --shadow-xs:  0 0 0 1px rgba(0, 0, 0, 0.02);
  --shadow-sm:  0 1px 1px rgba(0, 0, 0, 0.02);
  --shadow-md:  0 2px 8px rgba(0, 0, 0, 0.04);
  --shadow-lg:  0 8px 24px rgba(0, 0, 0, 0.06);
  --shadow-focus: 0 0 0 3px var(--focus-ring);

  /* --- Mass ----------------------------------------------------------- */
  /* `--topbar-h` ist am 27.08.2026 entfallen: es gibt keine Kopfzeile mehr.
     Ihr Inhalt beschrieb den angezeigten Plan und steht jetzt in der
     Seitenleiste; die Ansichten beginnen wieder ganz oben. */
  --rail-w:    56px;
  --panel-w:   320px;
  --detail-w:  440px;

  /* --- Bewegung ------------------------------------------------------- */
  --ease:      cubic-bezier(0.2, 0, 0, 1);
  --dur-fast:  120ms;
  --dur-med:   180ms;
  --dur-slow:  260ms;

  /* --- Alt-Aliasse, die noch benutzt werden ---------------------------- */
  /* R16 (#469): neun Aliasse standen hier, ohne dass ein einziger von
     ihnen je gelesen wurde — Tokens, die nichts faerben, laden dazu ein,
     an der falschen Stelle zu drehen. Entfernt: bg, bg-elevated,
     surface-hover, ink-soft, accent-hover, alert, line-soft,
     radius-sm-legacy, fs-3xl. */
  --surface:       var(--bg-panel);
  --ink:           var(--ink-strong);
  --accent:        var(--accent-500);
}
