/* ════════════════════════════════════════════════════════════════════════════
   BSS Kicker – Material Design 3 (Expressive) Design-Tokens
   ────────────────────────────────────────────────────────────────────────────
   Zentrale Token-Quelle für App (index.html), Kiosk (kiosk.html) und das
   Design-Muster (docs/m3-muster.html). Werte folgen m3.material.io
   (Styles: Color / Typography / Shape / Motion / Elevation / States).

   KONVENTIONEN
   - System-Tokens:  --md-sys-<gruppe>-<name>       (offizielle M3-Rollen)
   - App-Extensions: --md-ext-color-<name>          (success/warning/team1/team2)
   - Legacy-Brücke:  --bg, --card, --blue, …        (Altvariablen → Token-Aliase,
                     hält bestehende Styles funktionsfähig)
   - Dunkelmodus:    html[data-theme="dark"]        (Attribut, kein CSS-Reinject)

   BROWSER-REGELN (Kiosk-Chromium!)
   - KEIN color-mix(), KEIN :has(), KEIN @property.
   - Transparenzen über RGB-Triplets: rgba(var(--md-sys-color-primary-rgb)/.08)
   - linear()-Spring-Kurven nur hinter @supports (am Dateiende).

   EIN DESIGN (seit 2026-09-30): eigene Designs aus der Datenbank gibt es nicht
   mehr, nur den Farbmodus (Automatisch/Hell/Dunkel, docs/SPEZIFIKATION.md 10.1).
   ════════════════════════════════════════════════════════════════════════════ */


/* ── 0. Fonts & Icon-Basis (eine Quelle für App, Kiosk und Muster) ──────────── */
/* Die Textschrift ist seit dem 2026-09-30 **Geist** (Neugestaltung: der
   freigegebene Entwurf ist in Geist gesetzt, und der Betreiber will ihn
   „wirklich wie in dem Entwurf"). SIL Open Font License 1.1, erzeugt von
   `scripts/subset_font.py` - Herkunft und Messung stehen dort: 18.364 Byte,
   eine Achse wght 400-700.

   Bis dahin stand hier Roboto Flex (38.616 Byte, wght und opsz); sie ist
   mit diesem Tag entfallen. Die Familie heisst jetzt ehrlich 'Geist' - der
   Grund, sie 'Roboto' zu nennen, waren die eigenen Designs aus der
   Datenbank, und die gibt es seit demselben Tag nicht mehr.

   ⚠️ `font-weight: 400 700` mit LEERZEICHEN und ohne Komma - das ist die
   Bereichsangabe fuer variable Schriften. Mit Komma waere es eine Liste und
   der Browser nimmt die Schrift dann nur fuer genau diese zwei Gewichte. */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/geist.woff2') format('woff2-variations'),
       url('../fonts/geist.woff2') format('woff2');
}
/* Die Symbole seit dem 2026-09-30: Material Symbols OUTLINED, Strichstaerke
   300, ungefuellt - „fresh und reduziert" statt der runden 400er. Eine
   statische Instanz, erzeugt von `scripts/subset_icons.py` (Herkunft,
   Pruefsummen und Verfahren stehen dort). `font-weight: 400` bleibt, weil die
   Datei nur EINEN Schnitt hat - der Browser soll ihn nicht kuenstlich fetten. */
@font-face {
  font-family: 'Material Symbols'; font-style: normal; font-weight: 400; font-display: block;
  src: url('../fonts/material-symbols.woff2') format('woff2');
}
.msym {
  font-family: 'Material Symbols';
  font-weight: normal;
  font-style: normal;
  font-size: 1.25em;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  vertical-align: middle;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'liga';
  -webkit-user-select: none;
  user-select: none;
}

/* ── 1. Farbe · LIGHT ──────────────────────────────────────────────────────────
   Die reduzierte Palette der Neugestaltung (2026-09-30). Der Betreiber: „Ich
   möchte nicht so viele Farben und Bunt wie es vielleicht jetzt ist." Nach dem
   Entwurf, den er freigegeben hat (claude.ai-Designfläche „Kicker
   Neugestaltung"):

   * **Flächen neutral** (Grau mit einem Hauch Wärme) statt violett getönt.
   * **`primary` ist der schwarz-weiße Akzent**: Hauptknöpfe, Auswahl, aktive
     Zustände - im Hellen fast Schwarz, im Dunkeln fast Weiß. So entschieden
     am 2026-09-30 („Akzentfarben: So wie es im Entwurf ist").
   * **Farbe tragen nur die Tischseiten**: Team 1 Blau (eigene Rollen
     `--md-ext-color-team1*`, bis dahin ein Alias auf `primary`), Team 2 Orange
     (`tertiary`, wie bisher). Dazu Rot für Fehler und LIVE.
   * `secondary` ist ein neutrales Grau: Pillen, Chips und die Navigation
     werden grau statt violett.

   Die Rollennamen bleiben, nur die Werte ändern sich: 112 Testdateien und
   hunderte `--md-sys-*`-Verweise hängen an den Namen, ein zweites Schema wäre
   ein neues Muster ohne Gewinn.

   Kontrast, GERECHNET nach WCAG 2.1 (gemessen im Browser: siehe
   SPEZIFIKATION 10.1): on-surface #131417 auf surface #F4F4F2 ≈ 17 : 1,
   on-surface-variant #5B5D65 auf surface-container-high #ECECE9 ≈ 5,6 : 1,
   Team 1 #2358D5 auf Weiß ≈ 5,6 : 1, Team 2 #BF4A08 auf Weiß ≈ 4,9 : 1.

   Bis zum 2026-09-30 stand hier ein Schema aus Seed #6442d6 (SchemeVibrant,
   `tools/gen-theme.mjs`). Der Generator bleibt als Werkzeug liegen; für eine
   Palette mit EINEM neutralen Akzent bringt er nichts - er erzeugt aus jedem
   Seed getönte Flächen. */
:root {
  --md-sys-color-primary:                    #131417;
  --md-sys-color-on-primary:                 #FFFFFF;
  --md-sys-color-primary-container:          #E4E4E0;
  --md-sys-color-on-primary-container:       #131417;
  --md-sys-color-secondary:                  #5B5D65;
  --md-sys-color-on-secondary:               #FFFFFF;
  --md-sys-color-secondary-container:        #E4E4E0;
  --md-sys-color-on-secondary-container:     #131417;
  --md-sys-color-tertiary:                   #BF4A08;
  --md-sys-color-on-tertiary:                #FFFFFF;
  --md-sys-color-tertiary-container:         #FAEADF;
  --md-sys-color-on-tertiary-container:      #3A1500;
  --md-sys-color-error:                      #C8282E;
  --md-sys-color-on-error:                   #FFFFFF;
  --md-sys-color-error-container:            #FBE4E3;
  --md-sys-color-on-error-container:         #7A1015;
  --md-sys-color-background:                 #F4F4F2;
  --md-sys-color-on-background:              #131417;
  --md-sys-color-surface:                    #F4F4F2;
  --md-sys-color-on-surface:                 #131417;
  --md-sys-color-surface-variant:            #E4E4E0;
  --md-sys-color-on-surface-variant:         #5B5D65;
  --md-sys-color-surface-dim:                #E4E4E0;
  --md-sys-color-surface-bright:             #FAFAF8;
  --md-sys-color-surface-container-lowest:   #FFFFFF;
  --md-sys-color-surface-container-low:      #FAFAF8;
  --md-sys-color-surface-container:          #F0F0ED;
  --md-sys-color-surface-container-high:     #ECECE9;
  --md-sys-color-surface-container-highest:  #E4E4E0;
  --md-sys-color-outline:                    #74767D;
  --md-sys-color-outline-variant:            #E3E3DF;
  --md-sys-color-inverse-surface:            #26272B;
  --md-sys-color-inverse-on-surface:         #F4F4F2;
  --md-sys-color-inverse-primary:            #EDEDEF;
  --md-sys-color-surface-tint:               #131417;
  --md-sys-color-shadow:                     #000000;
  --md-sys-color-scrim:                      #000000;

  /* Fixed-Rollen (per Definition in Hell + Dunkel identisch) */
  --md-sys-color-primary-fixed:              #E4E4E0;
  --md-sys-color-primary-fixed-dim:          #C9C9C4;
  --md-sys-color-on-primary-fixed:           #131417;
  --md-sys-color-on-primary-fixed-variant:   #3A3B40;
  --md-sys-color-secondary-fixed:            #E4E4E0;
  --md-sys-color-secondary-fixed-dim:        #C9C9C4;
  --md-sys-color-on-secondary-fixed:         #131417;
  --md-sys-color-on-secondary-fixed-variant: #3A3B40;
  --md-sys-color-tertiary-fixed:             #FFDCC2;
  --md-sys-color-tertiary-fixed-dim:         #FFB77C;
  --md-sys-color-on-tertiary-fixed:          #331200;
  --md-sys-color-on-tertiary-fixed-variant:  #6B3400;

  /* App-Extensions (Erfolg/Warnung + Team-Semantik) */
  --md-ext-color-success:                    #146C2E;
  --md-ext-color-on-success:                 #FFFFFF;
  --md-ext-color-success-container:          #C4EFCB;
  --md-ext-color-on-success-container:       #002108;
  --md-ext-color-warning:                    #7D5700;
  --md-ext-color-on-warning:                 #FFFFFF;
  --md-ext-color-warning-container:          #FFDF9E;
  --md-ext-color-on-warning-container:       #271900;
  /* Die Figurenfarben am Tisch (2026-09-09). ⚠️ Sie stehen NUR hier und
     drehen sich im Dunkelmodus NICHT um - dieselbe Begruendung wie bei
     `shadow` und `scrim`: die Figuren sind schwarz und weiss, egal wie der
     Monitor eingestellt ist. Eine Rolle, die mitdreht, hiesse „der schwarze
     Spieler hat im Dunkeln weisse Figuren".
     Nicht ganz #000/#FFF: auf einer Flaeche stehend wirken die Reinwerte wie
     ein Loch bzw. wie ein Blitz, und der Balken traegt ohnehin eine Kontur. */
  --md-ext-color-figur-dunkel:               #101014;
  --md-ext-color-figur-hell:                 #F2F2F5;
  --md-ext-color-figur-dunkel-rgb:           16 16 20;
  --md-ext-color-figur-hell-rgb:             242 242 245;
  /* Die Kontur, die eine schwarze Flaeche auf dunklem und eine weisse auf
     hellem Grund trotzdem erkennbar macht (M3-RULES Regel 2, 2026-10-06) -
     derselbe Umriss, den `.lv-figur` im Kiosk-Spielstand schon traegt. */
  --md-ext-color-figur-kontur:               var(--md-sys-color-outline);

  /* ⚠️ Team-Rollen zeigen seit dem 2026-10-06 auf die FIGURENFARBE und nicht
     mehr auf eine eigene Palette (Blau/Orange). Der Betreiber: „Wir haben
     schwarze und weisse Spielfiguren. [...] Alle Darstellungen und
     Ueberschriften bzw. farblichen Darstellungen sollen sich dann daran
     orientieren." WELCHE Seite schwarz ist, sagt die Einstellung
     (`team1_figuren_schwarz`, Karte „Der Tisch" unter Allgemein); das
     Attribut `html[data-figuren-t1]` traegt sie vor dem ersten Bild ins
     Dokument (routers/settings.py::ui_boot_snippet, SPEZIFIKATION
     „Figurenfarbe"). Vorgabe (kein Attribut oder „schwarz"): Team 1 schwarz.

     ⚠️ NICHT im `html[data-theme="dark"]`-Block definiert: eine Team-Rolle
     dort haette dieselbe Spezifitaet wie die Regel unten, und es gewaenne
     die SPAETER geladene Regel - nicht die gewollte. Die Figurenfarbe haengt
     an der SEITE, nicht am Thema.

     `-container` ist bewusst NEUTRAL (keine aus Schwarz/Weiss gemischte
     Toenung): eine ganze Flaeche in Schwarz oder Weiss waere ein Loch bzw.
     ein Blitz. Die Seite zeigt sich stattdessen ueber die Kontur oben und
     die tatsaechliche Figurenfarbe an kleinen Flaechen (Markenpunkte,
     Avatar-Initialen). */
  --md-ext-color-team1:                      var(--md-ext-color-figur-dunkel);
  --md-ext-color-on-team1:                   var(--md-ext-color-figur-hell);
  --md-ext-color-team1-container:            var(--md-sys-color-surface-container-high);
  --md-ext-color-on-team1-container:         var(--md-sys-color-on-surface);
  /* Der helle Ton fuer dunklen Grund, in BEIDEN Themes gleich (wie die
     Fixed-Rollen oben) - fuer das Endebanner auf dem Scrim. */
  --md-ext-color-team1-fixed-dim:            var(--md-ext-color-figur-dunkel);
  --md-ext-color-team2:                      var(--md-ext-color-figur-hell);
  --md-ext-color-on-team2:                   var(--md-ext-color-figur-dunkel);
  --md-ext-color-team2-container:            var(--md-sys-color-surface-container-high);
  --md-ext-color-on-team2-container:         var(--md-sys-color-on-surface);
  --md-ext-color-team2-fixed-dim:            var(--md-ext-color-figur-hell);
  /* Das aktive Stueck einer Schiene (Segmente, obere Navigation): im Hellen
     Weiss auf Grau. ⚠️ Eine eigene Rolle, weil `surface-container-lowest` im
     Dunkeln DUNKLER ist als die Schiene - das aktive Segment saehe dort wie
     ein Loch aus. */
  --md-ext-color-schiene-aktiv:              #FFFFFF;

  /* RGB-Triplets für State-Layers/Scrims (rgba(var(--…-rgb)/.08)) */
  --md-sys-color-primary-rgb:            19 20 23;
  --md-sys-color-on-primary-rgb:         255 255 255;
  --md-sys-color-on-surface-rgb:         19 20 23;
  --md-sys-color-on-surface-variant-rgb: 91 93 101;
  --md-sys-color-tertiary-rgb:           191 74 8;
  --md-sys-color-error-rgb:              200 40 46;
  --md-sys-color-inverse-surface-rgb:    38 39 43;
  --md-sys-color-scrim-rgb:              0 0 0;
  --md-ext-color-success-rgb:            20 108 46;
  --md-ext-color-warning-rgb:            125 87 0;
  /* Die Flächen als Triplets (2026-09-30), für die halbdurchsichtigen
     Einblendungen im Kiosk - der Kiosk-Chromium kann kein color-mix(). */
  --md-sys-color-surface-container-rgb:      240 240 237;
  --md-sys-color-surface-container-high-rgb: 236 236 233;
  --md-sys-color-surface-container-lowest-rgb: 255 255 255;
  --md-ext-color-team1-rgb:              var(--md-ext-color-figur-dunkel-rgb);
  --md-ext-color-team2-rgb:              var(--md-ext-color-figur-hell-rgb);
  /* Die Kaesten ueber dem Kamerabild (Kiosk, 2026-09-30, freigegebener
     Entwurf): Flaeche `surface-container-lowest` mit der Deckkraft aus
     `kiosk_config.grund_deckkraft`, eine Haarlinie und ein eigener, KRAEFTIGERER
     Nebentext. ⚠️ Der Nebentext ist gerechnet und nicht geschaetzt: bei 70 %
     Deckkraft ueber einem rein schwarzen Bild haelt #43454D noch 4,53 : 1, das
     `on-surface-variant` der App (#5B5D65) nur 3,1 : 1. */
  --md-ext-color-kasten-rand:                rgba(0, 0, 0, .08);
  --md-ext-color-kasten-text2:               #43454D;

  /* Scrollbalken, Formularfelder und Datumswähler folgen dem Modus. */
  color-scheme: light;
}

/* Seite 1 spielt weiss (2026-10-06) - die Gegenprobe zur Vorgabe oben in
   `:root`. Dieselbe Spezifitaet wie `:root`, deshalb WEDER im
   `html[data-theme="dark"]`-Block noch irgendwo sonst dazwischen: zwei
   Regeln mit gleichem Gewicht gewinnt die, die im Quelltext spaeter steht -
   diese hier muss also die EINZIGE zweite Stelle fuer Team-Rollen bleiben. */
html[data-figuren-t1="weiss"] {
  --md-ext-color-team1:                      var(--md-ext-color-figur-hell);
  --md-ext-color-on-team1:                   var(--md-ext-color-figur-dunkel);
  --md-ext-color-team1-fixed-dim:            var(--md-ext-color-figur-hell);
  --md-ext-color-team1-rgb:                  var(--md-ext-color-figur-hell-rgb);
  --md-ext-color-team2:                      var(--md-ext-color-figur-dunkel);
  --md-ext-color-on-team2:                   var(--md-ext-color-figur-hell);
  --md-ext-color-team2-fixed-dim:            var(--md-ext-color-figur-dunkel);
  --md-ext-color-team2-rgb:                  var(--md-ext-color-figur-dunkel-rgb);
}


/* ── 2. Typografie (M3 Type Scale, Roboto) ──────────────────────────────────── */
:root {
  /* Referenzschicht: die Schriften einmal benennen, die Systemschicht zeigt
     darauf. Bis zum 2026-09-03 gab es nur `--md-sys-typescale-font` - eine
     Stelle, die Familie UND Rolle in einem Wert vermischte.

     ⚠️ `weight-display: 475` ist ein Zwischengewicht und wirkt erst mit einer
     VARIABLEN Schrift. Mit den drei statischen Roboto-Schnitten (400/500/700)
     rundet der Browser auf 500. Das Token steht schon hier, damit die
     Umstellung auf Roboto Flex nur noch die Schrift austauscht und nicht die
     Struktur. */
  --md-ref-typeface-brand: 'Geist', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --md-ref-typeface-plain: 'Geist', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --md-ref-typeface-mono:  ui-monospace, 'Roboto Mono', 'Cascadia Mono', Consolas, monospace;
  --md-ref-typeface-weight-regular: 400;
  --md-ref-typeface-weight-medium:  500;
  --md-ref-typeface-weight-bold:    700;
  /* Wirkt jetzt WIRKLICH: mit den drei statischen Schnitten rundete der
     Browser auf 500. Roboto Flex kann 475. */
  --md-ref-typeface-weight-display: 475;

  --md-sys-typescale-font: var(--md-ref-typeface-plain);
  --md-sys-typescale-brand-font: var(--md-ref-typeface-brand);

  --md-sys-typescale-display-large-size: 57px;   --md-sys-typescale-display-large-line-height: 64px;   --md-sys-typescale-display-large-weight: 400;  --md-sys-typescale-display-large-tracking: -0.25px;
  --md-sys-typescale-display-medium-size: 45px;  --md-sys-typescale-display-medium-line-height: 52px;  --md-sys-typescale-display-medium-weight: 400; --md-sys-typescale-display-medium-tracking: 0;
  --md-sys-typescale-display-small-size: 36px;   --md-sys-typescale-display-small-line-height: 44px;   --md-sys-typescale-display-small-weight: 400;  --md-sys-typescale-display-small-tracking: 0;

  --md-sys-typescale-headline-large-size: 32px;  --md-sys-typescale-headline-large-line-height: 40px;  --md-sys-typescale-headline-large-weight: 400; --md-sys-typescale-headline-large-tracking: 0;
  --md-sys-typescale-headline-medium-size: 28px; --md-sys-typescale-headline-medium-line-height: 36px; --md-sys-typescale-headline-medium-weight: 400;--md-sys-typescale-headline-medium-tracking: 0;
  --md-sys-typescale-headline-small-size: 24px;  --md-sys-typescale-headline-small-line-height: 32px;  --md-sys-typescale-headline-small-weight: 400; --md-sys-typescale-headline-small-tracking: 0;

  --md-sys-typescale-title-large-size: 22px;     --md-sys-typescale-title-large-line-height: 28px;     --md-sys-typescale-title-large-weight: 400;    --md-sys-typescale-title-large-tracking: 0;
  --md-sys-typescale-title-medium-size: 16px;    --md-sys-typescale-title-medium-line-height: 24px;    --md-sys-typescale-title-medium-weight: 500;   --md-sys-typescale-title-medium-tracking: 0.15px;
  --md-sys-typescale-title-small-size: 14px;     --md-sys-typescale-title-small-line-height: 20px;     --md-sys-typescale-title-small-weight: 500;    --md-sys-typescale-title-small-tracking: 0.1px;

  --md-sys-typescale-body-large-size: 16px;      --md-sys-typescale-body-large-line-height: 24px;      --md-sys-typescale-body-large-weight: 400;     --md-sys-typescale-body-large-tracking: 0.5px;
  --md-sys-typescale-body-medium-size: 14px;     --md-sys-typescale-body-medium-line-height: 20px;     --md-sys-typescale-body-medium-weight: 400;    --md-sys-typescale-body-medium-tracking: 0.25px;
  --md-sys-typescale-body-small-size: 12px;      --md-sys-typescale-body-small-line-height: 16px;      --md-sys-typescale-body-small-weight: 400;     --md-sys-typescale-body-small-tracking: 0.4px;

  --md-sys-typescale-label-large-size: 14px;     --md-sys-typescale-label-large-line-height: 20px;     --md-sys-typescale-label-large-weight: 500;    --md-sys-typescale-label-large-tracking: 0.1px;
  --md-sys-typescale-label-medium-size: 12px;    --md-sys-typescale-label-medium-line-height: 16px;    --md-sys-typescale-label-medium-weight: 500;   --md-sys-typescale-label-medium-tracking: 0.5px;
  --md-sys-typescale-label-small-size: 11px;     --md-sys-typescale-label-small-line-height: 16px;     --md-sys-typescale-label-small-weight: 500;    --md-sys-typescale-label-small-tracking: 0.5px;
}


/* ── 3. Form (Shape Scale, inkl. Expressive-Stufen) ─────────────────────────── */
:root {
  --md-sys-shape-corner-none:                  0px;
  --md-sys-shape-corner-extra-small:           4px;
  --md-sys-shape-corner-small:                 8px;
  --md-sys-shape-corner-medium:                12px;
  --md-sys-shape-corner-large:                 16px;
  --md-sys-shape-corner-large-increased:       20px;
  --md-sys-shape-corner-extra-large:           28px;
  --md-sys-shape-corner-extra-large-increased: 32px;
  --md-sys-shape-corner-extra-extra-large:     48px;
  --md-sys-shape-corner-full:                  9999px;
  /* Die Karte der Neugestaltung (2026-09-30): 24 px wie im Entwurf. Ein
     eigenes Token und kein veraendertes `corner-medium` - die Stufenleiter
     der M3-Formen bleibt, wie sie ist (tests/test_m3_bauteile.py). */
  --md-ext-shape-card:                         24px;
}


/* ── 4. Motion (Easing + Duration + Expressive Springs) ─────────────────────── */
:root {
  --md-sys-motion-easing-emphasized:            cubic-bezier(0.2, 0, 0, 1);
  --md-sys-motion-easing-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
  --md-sys-motion-easing-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15);
  --md-sys-motion-easing-standard:              cubic-bezier(0.2, 0, 0, 1);
  /* Die M2-Kurve. Sie fehlte, und Altbestaende brauchen sie: eine Regel, die
     „das alte Gefuehl" will, soll ein Token nennen und keine Zahlenreihe. */
  --md-sys-motion-easing-legacy:                cubic-bezier(0.4, 0, 0.2, 1);
  --md-sys-motion-easing-standard-decelerate:   cubic-bezier(0, 0, 0, 1);
  --md-sys-motion-easing-standard-accelerate:   cubic-bezier(0.3, 0, 1, 1);
  --md-sys-motion-easing-linear:                cubic-bezier(0, 0, 1, 1);

  --md-sys-motion-duration-short1: 50ms;   --md-sys-motion-duration-short2: 100ms;
  --md-sys-motion-duration-short3: 150ms;  --md-sys-motion-duration-short4: 200ms;
  --md-sys-motion-duration-medium1: 250ms; --md-sys-motion-duration-medium2: 300ms;
  --md-sys-motion-duration-medium3: 350ms; --md-sys-motion-duration-medium4: 400ms;
  --md-sys-motion-duration-long1: 450ms;   --md-sys-motion-duration-long2: 500ms;
  --md-sys-motion-duration-long3: 550ms;   --md-sys-motion-duration-long4: 600ms;
  --md-sys-motion-duration-extra-long1: 700ms; --md-sys-motion-duration-extra-long2: 800ms;
  --md-sys-motion-duration-extra-long3: 900ms; --md-sys-motion-duration-extra-long4: 1000ms;

  /* Expressive-Springs. „spatial" = Position/Größe MIT Überschwingen,
     „effects" = Farbe/Opazität OHNE.

     Die `cubic-bezier`-Werte hier sind Näherungen und der Rückfall für alte
     Browser; die echten Kurven stehen weiter unten hinter `@supports`.

     ⚠️ Die Laufzeiten sind am 2026-09-03 auf die Werte des Kits gegangen
     (spatial 550/400, effects 300/200 statt 500/350/200/150). Sie sind die
     Spezifikationswerte, hergeleitet aus Steifigkeit und Dämpfung – unsere
     waren geschätzt. Alles wird dadurch etwas ruhiger.

     ⚠️ Und unsere SECHS Namen bleiben, obwohl das Kit vier hat: `style.css`
     liest sie 15-mal, und `tests/test_end_rank.py` nennt einen namentlich.
     Gemessen benutzt werden allerdings nur DREI – fast-spatial (9x),
     default-spatial (3x), fast-effects (1x). `slow-*` und `default-effects`
     stehen ungenutzt da und bleiben, weil sie nichts kosten und die Leiter
     vollständig halten. */
  --md-sys-motion-spring-fast-spatial-duration: 400ms;
  --md-sys-motion-spring-fast-spatial-easing:   cubic-bezier(0.42, 1.67, 0.21, 0.90);
  --md-sys-motion-spring-default-spatial-duration: 550ms;
  --md-sys-motion-spring-default-spatial-easing:   cubic-bezier(0.38, 1.21, 0.22, 1.00);
  --md-sys-motion-spring-slow-spatial-duration: 650ms;
  --md-sys-motion-spring-slow-spatial-easing:   cubic-bezier(0.39, 1.29, 0.35, 0.98);
  --md-sys-motion-spring-fast-effects-duration: 200ms;
  --md-sys-motion-spring-fast-effects-easing:   cubic-bezier(0.31, 0.94, 0.34, 1.00);
  --md-sys-motion-spring-default-effects-duration: 300ms;
  --md-sys-motion-spring-default-effects-easing:   cubic-bezier(0.34, 0.80, 0.34, 1.00);
  --md-sys-motion-spring-slow-effects-duration: 300ms;
  --md-sys-motion-spring-slow-effects-easing:   cubic-bezier(0.34, 0.88, 0.34, 1.00);
}


/* ── 4b. Abstands- und Layoutraster ─────────────────────────────────────────────
   Das 4-dp-Raster und die Maße der Navigationsflächen. Beides gab es bei uns
   nicht als Token; die Werte standen als Zahlen in `style.css`.

   ⚠️ `--nav-h` BLEIBT und zeigt jetzt hierher. `style.css` liest es fünfmal
   (u. a. `top: var(--nav-h)` an der klebenden Kopfzeile), und ein Alias ist
   billiger als fünf Änderungen an lebenden Regeln.

   ⚠️ Die `min-width`-Abfragen des Kits (600/840/1200/1600 für einen
   wachsenden Seitenrand) sind NICHT übernommen. Dieses Projekt hat genau zwei
   Umbruchpunkte, und `tests/test_responsive.py` lässt keinen dritten zu –
   siehe M3-RULES.md, Regel 10. Die Layout-Tokens stehen deshalb einstufig. */
:root {
  --md-sys-spacing-1:   4px;
  --md-sys-spacing-2:   8px;
  --md-sys-spacing-3:  12px;
  --md-sys-spacing-4:  16px;
  --md-sys-spacing-5:  20px;
  --md-sys-spacing-6:  24px;
  --md-sys-spacing-8:  32px;
  --md-sys-spacing-10: 40px;
  --md-sys-spacing-12: 48px;
  --md-sys-spacing-16: 64px;

  /* 72 statt 64 seit dem 2026-09-30: die Pillen stehen jetzt in einer
     grauen Schiene (4 px Polster), und eine Pille ist 56 hoch - bei 64 stiesse
     die Schiene oben und unten an die Kante. Die Treffflaeche bleibt 56. */
  --md-sys-layout-topbar-height: 72px;
  --md-sys-layout-navbar-height: 80px;
  /* ⚠️ Ohne Verbraucher seit dem 2026-09-07. Das Seitenmenue ist an jenem Tag
     zurueckgebaut worden (der Betreiber: „Das Menü soll nicht mehr links am
     Rand sein, sondern wieder oben in der Leiste"), und mit ihm ist
     `css/m3-rail.css` entfallen - die einzige Datei, die dieses Mass las.

     Der Token bleibt trotzdem stehen: der Abgleich hat die SIEBEN
     Layout-Masse des Kits uebernommen (docs/M3-ABGLEICH.md, Block 8a), und
     sechs davon zu fuehren waere eine halbe Entscheidung. Die schmale
     Fassung (`--md-ext-layout-rail-width-schmal: 64px`) ist dagegen gegangen:
     sie war keine Material-Groesse, sondern eine Erfindung fuer das
     eingeklappte Menue. */
  --md-sys-layout-rail-width:    80px;
  --md-sys-layout-max-width:   1440px;
  --md-sys-layout-margin:        24px;
  --md-sys-layout-gutter:        24px;
  --md-sys-layout-icon-size:     24px;

  /* Die Expressive-Groessenleiter fuer alles Klickbare (ANALYSE.md §8).
     Fuenf Stufen, und die Vorgabe dieses Projekts ist **M**.

     ⚠️ Das ist eine bewusste Wahl INNERHALB der Leiter und keine Abweichung
     von ihr. M3 nennt fuer den gewoehnlichen Knopf Stufe S (40 px) - am
     Kicker-Touch mit `--ui-zoom: 1.1` waeren das 44 px, gegen heute
     gemessene 62. Eine Verkleinerung der wichtigsten Trefffläche um 29
     Prozent, an einem Geraet, das im Stehen mit Fingern bedient wird.
     `--min-touch` ist deshalb ein Alias auf Stufe M und bleibt die Vorgabe.

     S und XS gibt es fuer Elemente, die KEINE primaeren Ziele sind (Chips,
     Marken, Zaehler in Tabellenzellen). */
  --md-sys-comp-size-xs:  32px;
  --md-sys-comp-size-s:   40px;
  --md-sys-comp-size-m:   56px;
  --md-sys-comp-size-l:   96px;
  --md-sys-comp-size-xl: 136px;
}


/* ── 5. State-Layer-Opazitäten ──────────────────────────────────────────────── */
:root {
  --md-sys-state-hover-state-layer-opacity:   0.08;
  --md-sys-state-focus-state-layer-opacity:   0.10;
  --md-sys-state-pressed-state-layer-opacity: 0.10;
  --md-sys-state-dragged-state-layer-opacity: 0.16;
  /* Abgeschaltete Elemente: 38 % auf dem Inhalt, 12 % auf der Flaeche. Die
     zwei fehlten und wurden an ~25 Stellen als literale 0.38/0.12 wiederholt
     (u. a. in `body.nicht-am-tisch [data-requires-table]`). */
  --md-sys-state-disabled-opacity:           0.38;
  --md-sys-state-disabled-container-opacity: 0.12;
}


/* ── 6. Elevation (Light: Schatten; Dark: tonale Container, s.u.) ───────────── */
:root {
  --md-sys-elevation-level0: none;
  --md-sys-elevation-level1: 0 1px 2px rgba(0,0,0,0.30), 0 1px 3px 1px rgba(0,0,0,0.15);
  --md-sys-elevation-level2: 0 1px 2px rgba(0,0,0,0.30), 0 2px 6px 2px rgba(0,0,0,0.15);
  --md-sys-elevation-level3: 0 1px 3px rgba(0,0,0,0.30), 0 4px 8px 3px rgba(0,0,0,0.15);
  --md-sys-elevation-level4: 0 2px 3px rgba(0,0,0,0.30), 0 6px 10px 4px rgba(0,0,0,0.15);
  --md-sys-elevation-level5: 0 4px 4px rgba(0,0,0,0.30), 0 8px 12px 6px rgba(0,0,0,0.15);
}


/* ── 7. Legacy-Brücke (Altvariablen → Tokens; Werte je Modus identisch zum
        bisherigen M3-Theme-String – hält alle bestehenden Styles + Inline-
        Styles + eigene DB-Themes am Leben) ───────────────────────────────────── */
:root {
  --bg:         var(--md-sys-color-background);
  --surface:    var(--md-sys-color-surface-container-lowest);
  --card:       var(--md-sys-color-surface-container);
  --border:     var(--md-sys-color-outline-variant);
  --text:       var(--md-sys-color-on-surface);
  --text-dim:   var(--md-sys-color-on-surface-variant);
  --blue:       var(--md-ext-color-team1);
  --blue-dark:  var(--md-sys-color-on-primary-fixed-variant);   /* #4F378B */
  --orange:     var(--md-sys-color-tertiary);
  --orange-dark:#7A3600;
  --green:      var(--md-ext-color-success);
  --red:        var(--md-sys-color-error);
  --yellow:     var(--md-ext-color-warning);
  --radius:     var(--md-sys-shape-corner-large);
  --radius-sm:  var(--md-sys-shape-corner-small);
  --shadow:     var(--md-sys-elevation-level1);
  /* Alias auf die Expressive-Stufe M. Der Wert ist derselbe wie vorher; der
     Name sagt jetzt, WO auf der Leiter er steht. */
  --min-touch:  var(--md-sys-comp-size-m);
  /* Mit dem Abstand zur Notch (App vom Startbildschirm, `viewport-fit=cover`).
     EINE Stelle, und alle Verbraucher (Kopfzeile, Inhaltsabstand, klebende
     Kopfzeilen, Nachrichtenraster) gehen mit. Am Tisch und am Rechner ist
     `env()` 0. */
  --nav-h:      calc(var(--md-sys-layout-topbar-height) + env(safe-area-inset-top, 0px));
  /* Oberflächen-Skalierung (CSS zoom auf <body>) und Avatar-Größe.
     --ui-zoom wird zur Laufzeit von App.display gesetzt (Einstellungen → Anzeige).
     Viewport-Einheiten (dvh/vw) müssen durch --ui-zoom geteilt werden, weil sie
     nicht mitskalieren. */
  --ui-zoom:      1;
  /* Avatargröße: EINE Stellschraube. --avatar-scale wird zur Laufzeit gesetzt
     (Einstellungen → Anzeige → Avatare). Der gedämpfte Faktor für die ohnehin
     großen 44px-Kreise (.player-avatar, .avatar-circle) leitet sich daraus ab,
     damit nur ein Wert gepflegt werden muss.

     ⚠️ Die Stufen stehen NICHT hier, sondern in `static/js/display.js`
     (`App.display.AVATAR_STEPS`) - eine zweite Aufzählung im Kommentar ist
     genau das, was hier bis zum 2026-09-02 stand und still veraltet ist. Zum
     Einordnen der Rechnung:
       2.6 → 1.67   3.2 → 1.92   3.8 → 2.18

     Gemessen am 2026-09-02 im Spielaufbau: die 44px-Kreise werden bei der
     höchsten Stufe 105 px, die Spielerkarte 201 px hoch, ohne Überlauf und
     ohne dass der Name verschwindet. Eine Obergrenze (`min(…)`) auf diesem
     Faktor war deshalb nicht nötig. */
  --avatar-scale: 2.6;
  --avatar-scale-lg: calc(1 + (var(--avatar-scale) - 1) * 0.42);
  --transition: var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
  --scrollbar-thumb:       rgba(var(--md-sys-color-on-surface-rgb) / 0.28);
  --scrollbar-thumb-hover: rgba(var(--md-sys-color-on-surface-rgb) / 0.45);
  --scrollbar-track:       transparent;
}


/* ════════════════════════════════════════════════════════════════════════════
   DUNKELMODUS (True Black / OLED) – nur Farb-/Elevation-Deltas
   ════════════════════════════════════════════════════════════════════════════ */
html[data-theme="dark"] {
  --md-sys-color-primary:                    #EDEDEF;
  --md-sys-color-on-primary:                 #131417;
  --md-sys-color-primary-container:          #2E2F34;
  --md-sys-color-on-primary-container:       #EDEDEF;
  --md-sys-color-secondary:                  #9C9EA5;
  --md-sys-color-on-secondary:               #131417;
  --md-sys-color-secondary-container:        #2E2F34;
  --md-sys-color-on-secondary-container:     #EDEDEF;
  --md-sys-color-tertiary:                   #FF9F5F;
  --md-sys-color-on-tertiary:                #3A1500;
  --md-sys-color-tertiary-container:         #4A2410;
  --md-sys-color-on-tertiary-container:      #FFDCC2;
  --md-sys-color-error:                      #FF7B7F;
  --md-sys-color-on-error:                   #3D0508;
  --md-sys-color-error-container:            #5C1216;
  --md-sys-color-on-error-container:         #FFDAD8;
  --md-sys-color-background:                 #0C0D0F;
  --md-sys-color-on-background:              #EDEDEF;
  --md-sys-color-surface:                    #0C0D0F;
  --md-sys-color-on-surface:                 #EDEDEF;
  --md-sys-color-surface-variant:            #2A2B30;
  --md-sys-color-on-surface-variant:         #9C9EA5;
  --md-sys-color-surface-dim:                #0C0D0F;
  --md-sys-color-surface-bright:             #2E2F34;
  --md-sys-color-surface-container-lowest:   #08090A;
  --md-sys-color-surface-container-low:      #121315;
  --md-sys-color-surface-container:          #16171A;
  --md-sys-color-surface-container-high:     #1F2023;
  --md-sys-color-surface-container-highest:  #28292D;
  --md-sys-color-outline:                    #85878E;
  --md-sys-color-outline-variant:            #2A2B30;
  --md-sys-color-inverse-surface:            #EDEDEF;
  --md-sys-color-inverse-on-surface:         #26272B;
  --md-sys-color-inverse-primary:            #131417;
  --md-sys-color-surface-tint:               #EDEDEF;

  --md-ext-color-success:                    #7DD891;
  --md-ext-color-on-success:                 #00391B;
  --md-ext-color-success-container:          #00522A;
  --md-ext-color-on-success-container:       #C4EFCB;
  --md-ext-color-warning:                    #F6D975;
  --md-ext-color-on-warning:                 #3F2E00;
  --md-ext-color-warning-container:          #5B4300;
  --md-ext-color-on-warning-container:       #FFDF9E;

  --md-sys-color-primary-rgb:            237 237 239;
  --md-sys-color-on-primary-rgb:         19 20 23;
  --md-sys-color-on-surface-rgb:         237 237 239;
  --md-sys-color-on-surface-variant-rgb: 156 158 165;
  --md-sys-color-tertiary-rgb:           255 159 95;
  --md-sys-color-error-rgb:              255 123 127;
  --md-sys-color-inverse-surface-rgb:    237 237 239;
  --md-ext-color-success-rgb:            125 216 145;
  --md-ext-color-warning-rgb:            246 217 117;
  --md-sys-color-surface-container-rgb:      22 23 26;
  --md-sys-color-surface-container-high-rgb: 31 32 35;
  --md-sys-color-surface-container-lowest-rgb: 8 9 10;
  /* Gerechnet wie im hellen Modus: bei 70 % ueber einem rein WEISSEN Bild
     haelt #C4C6CD noch 4,53 : 1, #9C9EA5 nur 2,8 : 1. */
  --md-ext-color-kasten-rand:                rgba(255, 255, 255, .10);
  --md-ext-color-kasten-text2:               #C4C6CD;

  /* ⚠️ KEINE Team-Rollen hier (Falle „gleiche Spezifitaet gewinnt die
     spaetere Regel"): `team1`/`team2` stehen in `:root` und in
     `html[data-figuren-t1="weiss"]`, beide theme-unabhaengig. Die
     `-container`-Rollen zeigen auf `surface-container-high` und drehen sich
     darueber von selbst mit - keine eigene Dunkelfassung noetig. */
  --md-ext-color-schiene-aktiv:              #34353A;

  color-scheme: dark;

  /* Elevation im Dunkeln: flache Schatten – Tiefe kommt aus helleren
     Surface-Containern (Komponenten wählen die Container-Rolle). */
  --md-sys-elevation-level1: 0 1px 3px rgba(0,0,0,0.60);
  --md-sys-elevation-level2: 0 1px 4px rgba(0,0,0,0.60);
  --md-sys-elevation-level3: 0 2px 6px rgba(0,0,0,0.60);
  --md-sys-elevation-level4: 0 3px 8px rgba(0,0,0,0.60);
  --md-sys-elevation-level5: 0 4px 10px rgba(0,0,0,0.60);

  /* Brücken-Deltas (Rollen-Aliase, die im Dunkeln anders zugeordnet sind) */
  --surface:    var(--md-sys-color-surface-container);        /* #141218 */
  --card:       var(--md-sys-color-surface-container-high);   /* #1D1B20 */
  --blue-dark:  #B69DF8;
  --orange-dark:#E59B5F;
}


/* ── Reduced Motion: alle Bewegungen kollabieren ────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  :root {
    --md-sys-motion-duration-short1: 1ms;  --md-sys-motion-duration-short2: 1ms;
    --md-sys-motion-duration-short3: 1ms;  --md-sys-motion-duration-short4: 1ms;
    --md-sys-motion-duration-medium1: 1ms; --md-sys-motion-duration-medium2: 1ms;
    --md-sys-motion-duration-medium3: 1ms; --md-sys-motion-duration-medium4: 1ms;
    --md-sys-motion-duration-long1: 1ms;   --md-sys-motion-duration-long2: 1ms;
    --md-sys-motion-duration-long3: 1ms;   --md-sys-motion-duration-long4: 1ms;
    --md-sys-motion-duration-extra-long1: 1ms; --md-sys-motion-duration-extra-long2: 1ms;
    --md-sys-motion-duration-extra-long3: 1ms; --md-sys-motion-duration-extra-long4: 1ms;
    --md-sys-motion-spring-fast-spatial-duration: 1ms;
    --md-sys-motion-spring-default-spatial-duration: 1ms;
    --md-sys-motion-spring-slow-spatial-duration: 1ms;
    --md-sys-motion-spring-fast-effects-duration: 1ms;
    --md-sys-motion-spring-default-effects-duration: 1ms;
    --md-sys-motion-spring-slow-effects-duration: 1ms;
  }
}


/* ── Optionales Upgrade: echte Spring-Kurven via linear() (Chromium ≥ 113) ──── */
/* ── Die echten Spring-Kurven ───────────────────────────────────────────────────
   `linear()` beschreibt eine Feder als Stützstellenfolge; `cubic-bezier` kann
   das Überschwingen nur andeuten. Die vier Kurven hier sind die offiziellen
   aus dem Expressive-Kit und ersetzen seit dem 2026-09-03 zwei
   handgerechnete Näherungen – die zwei effects-Springs bekommen ihre Kurve
   überhaupt erst.

   ⚠️ Hinter `@supports`, und das bleibt so: der Kiosk-Chromium ist alt. Ohne
   die Abfrage fiele er auf GAR KEINE Kurve zurück statt auf die
   `cubic-bezier`-Näherung darüber – eine Animation, die springt, statt zu
   federn. Das Kit setzt `linear()` unbedingt; wir können das nicht.

   ⚠️ `slow-spatial` und `slow-effects` haben im Kit kein Gegenstück und
   behalten ihre Näherung. Sie werden in `style.css` ohnehin nicht benutzt. */
@supports (animation-timing-function: linear(0, 1)) {
  :root {
    --md-sys-motion-spring-default-spatial-easing: linear(0, 0.0018, 0.0071 1.14%, 0.0293 2.36%, 0.0645 3.58%, 0.1152 4.9%, 0.1991 6.72%, 0.3776 10.06%, 0.5934 13.8%, 0.7352 16.6%, 0.8447 19.2%, 0.9304 21.7%, 0.9976 24.3%, 1.0447 27%, 1.0717 29.9%, 1.0822 32.3%, 1.0791 36.3%, 1.0602 41.5%, 1.0305 49.5%, 1.0063 60.6%, 0.9964 70.2%, 0.9977 81.3%, 1);
    --md-sys-motion-spring-fast-spatial-easing:    linear(0, 0.0049, 0.0195 1.4%, 0.0755 2.9%, 0.1655 4.5%, 0.3378 7.1%, 0.6018 10.9%, 0.8079 14.6%, 0.9506 18.2%, 1.0356 22%, 1.0729 26.1%, 1.0748 30.7%, 1.0486 37.6%, 1.0116 48.2%, 0.9974 60.5%, 0.9992 78%, 1);
    --md-sys-motion-spring-default-effects-easing: linear(0, 0.1058 4.5%, 0.3313 9.4%, 0.5525 14.3%, 0.7261 19.4%, 0.8474 24.7%, 0.9236 30.2%, 0.9663 36.1%, 0.9873 42.5%, 0.9969 50.3%, 1);
    --md-sys-motion-spring-fast-effects-easing:    linear(0, 0.2142 3.4%, 0.5386 7.1%, 0.7784 11.1%, 0.9107 15.5%, 0.9711 20.5%, 0.9931 26.5%, 0.9988 34.5%, 1);
  }
}
