/* ==========================================================================
   tokens.css — die EINZIGE Quelle der Design-Token
   ==========================================================================

   Vorher standen diese Token doppelt: einmal in style.css (App-Shell,
   Editor, Beat-Editor, Listen-Seite) und einmal als Kopie in consent.css
   (Login, Registrierung, 2FA, Passwort-Reset, Rechtstexte, Fehlerseiten).
   Wer nur eine der beiden Dateien anfasste, bekam ein zweigeteiltes
   Erscheinungsbild — die Anmeldeseite sah anders aus als die App dahinter.
   Diese Datei löst das auf; style.css und consent.css definieren keine
   Farbtoken mehr, sondern setzen sie nur noch ein.

   Jedes Template, das style.css ODER consent.css lädt, MUSS tokens.css
   davor laden.

   ---------------------------------------------------------------------
   Farbwahl: nachgerechnet, nicht geschätzt
   ---------------------------------------------------------------------
   Seit 2026-10-11 (Optik-Stufe 1, docs/design/DESIGNRICHTUNG.md 2.1)
   neutrales Graphit statt Navy. Das alte Navy (#151925, Farbton ~228°,
   deutlich gesättigt) war ein großer Teil des Eindrucks "ungewohnt"; die
   gewohnten dunklen Arbeitsoberflächen (macOS, Logic, Ableton, VS Code)
   sind nahezu neutral. Kontrastwerte nach WCAG 2.1 (Schwelle 4.5:1 für
   normalen Text, 3:1 für Bedienelemente und große Schrift):

     Token              --bg   --panel  --panel-elevated  --surface-3
     --text-primary    16.86   15.52        14.01            12.11
     --text-secondary   9.83    9.04         8.16             7.05
     --text-dim         6.22    5.73         5.17             4.47  <- dort verboten
     --accent           7.73    7.11         6.42             5.55
     --border-strong    3.77    3.47         3.13             2.70  <- dort verboten

   `--text-dim` trägt an über 120 Stellen Meta-Zeilen, Hinweise und
   Platzhalter durch die ganze App. Auf `--surface-3` und auf `--fill-2`
   (4.27 über --panel) fällt es unter 4.5:1 und gehört dort nicht hin.

   `--border` und `--border-soft` bleiben bewusst schwach. Sie trennen
   Flächen optisch und sind KEINE Bedienelemente. Ein einziges Rand-Token,
   das überall 3:1 erreicht, würde jede Panelkante hell umranden und die
   Oberfläche zerlegen. Ränder, die tatsächlich ein Bedienelement begrenzen
   (Eingabefelder, Schalter), nehmen `--border-strong` bzw. `--field-border`.

   Akzent in zwei Rollen, weil es kein Blau gibt, das zugleich als Linkfarbe
   auf dunklem Grund lesbar ist UND weiße Schrift trägt (Apples #0a84ff
   liefert mit Weiß nur 3.65:1):
   - `--accent` (hell): Links, aktive Symbole, Fokusring, gewählte
     Reiterschrift. Gefüllte Flächen in `--accent` tragen `--on-accent`
     (dunkle Schrift, 7.80:1), nie `#fff`. Das ist der Altbestand, bis die
     Knöpfe auf `--accent-fill` umziehen (DESIGNRICHTUNG 3.2).
   - `--accent-fill` (tief): Primärknopf, gefüllte Badges, gewählter
     Schalter. Schrift darauf `--on-accent-fill` (Weiß), in Ruhe, Hover und
     gedrückt jeweils mindestens 5:1 (Nutzervorgabe).

   Neue Füll- und Trennlinien-Token stehen bewusst als rgba() oder var(),
   nicht als 8-stelliger Hexwert: Halbdurchsichtiges lässt sich nur über
   einer konkreten Fläche bewerten, und check_contrast.py rechnet solche
   Paare ausdrücklich über einer genannten Fläche.

   Nachrechnen lässt sich das jederzeit mit tests/harnesses/checks/check_contrast.py.
   Das Skript liest NUR die Basis-`:root`-Blöcke, nicht die Media-Blöcke.
   ========================================================================== */

:root {
  /* --- Flächen, von hinten nach vorn ---------------------------------- */
  --bg: #101216;             /* Seitenhintergrund */
  --panel-deep: #0b0d10;     /* eingelassene Flächen, Eingabefelder */
  --panel: #181b21;          /* Karten, Listen, Kacheln */
  --panel-elevated: #20242b; /* Dialoge, Menüs, Popover */

  /* --- Ränder ---------------------------------------------------------- */
  --border-soft: #262a31;    /* reine Trennlinie */
  --border: #323741;         /* Standardrand einer Fläche */
  --border-strong: #69707e;  /* Rand eines BEDIENELEMENTS (>= 3:1, nicht auf --surface-3) */

  /* --- Schrift --------------------------------------------------------- */
  --text-primary: #f1f3f6;
  --text-secondary: #b6bcc7;
  --text-dim: #8e95a2;       /* nicht auf --surface-3 und --fill-2 */

  /* --- Akzente --------------------------------------------------------- */
  --accent: #6aa8ff;         /* Links, aktive Symbole, Fokus */
  --on-accent: #0d1117;      /* Schrift AUF gefülltem --accent (Altbestand) */
  --accent-soft: rgba(106, 168, 255, 0.16); /* Auswahl-Hintergrund in Listen */
  --accent-fill: #2262d6;            /* Primärknopf, Weiß darauf 5.55:1 */
  --accent-fill-hover: #2668df;      /* heller beim Überfahren, Weiß 5.09:1 */
  --accent-fill-pressed: #1c56c4;    /* tiefer beim Drücken, Weiß 6.61:1 */
  --on-accent-fill: #ffffff;         /* Schrift AUF --accent-fill */
  --accent-teal: #22d3ee;    /* NUR Wellenform und Meter, nie Link oder Status */
  --accent-red: #e85d4d;     /* NUR Aufnahme und Peak im Editor */
  --accent-yellow: #f2c14e;  /* Schneiden / Achtung */

  /* --- Status ---------------------------------------------------------- */
  --success: #3ccf6e;        /* "Aktiv", "Gesund", gespeichert */
  --warning: var(--accent-yellow);
  --danger: #ff6b5e;         /* Fehlertext, roter Text an Löschknöpfen */
  --danger-fill: #c9372c;    /* gefüllter Gefahrenknopf */
  --on-danger-fill: #ffffff; /* Schrift AUF --danger-fill, 5.16:1 */

  /* --- Füllungen und Haarlinien (halbdurchsichtig, auf jeder Fläche) --- */
  --separator: rgba(255, 255, 255, 0.08); /* rein optisch, ~1.25:1 */
  --fill-1: rgba(255, 255, 255, 0.06);    /* Hover einer Zeile, Spur des Segmentschalters */
  --fill-2: rgba(255, 255, 255, 0.10);    /* sekundärer Knopf, gewählter Eintrag */
  --fill-3: rgba(255, 255, 255, 0.14);    /* gedrückt */
  --field-bg: var(--panel-deep);
  --field-border: var(--border-strong);
  --focus-ring: var(--accent);  /* mit Abstand (--focus-ring-offset), dann steht er auf dem Grund */

  --glow-1: #5c9dff;
  --glow-2: #22d3ee;
  --glow-3: var(--tone-1);

  /* --- Farbleiter: Tiefblau -> Türkis -------------------------------------
     Einzige Quelle für die Bento-Kacheln UND das Hintergrundraster
     (static/js/tile-background.js liest dieselben sechs Werte). Gleichmäßig
     abgestuft in OKLCH-Farbton (265° -> 195°, Schritte 6.7°/16.4°/15.5°/
     15.0°/16.6°), damit die Stufen als eine Leiter wirken statt als
     zufällig gewählte Einzeltöne.

     Kontrast je Stufe auf --panel-elevated (#20242b, seit 2026-10-11):
       --tone-1  4.30:1  <- unter der 4.5:1-Textschwelle, deshalb NUR als
                            Leuchten/Rand zulässig, niemals als Textfarbe
       --tone-2  5.73:1
       --tone-3  6.53:1
       --tone-4  7.40:1
       --tone-5  8.62:1
       --tone-6  8.20:1

     Alpha-Hinweis fürs Hintergrundraster: Cyan (--tone-5/6) strahlt bei
     gleicher Deckkraft rund 2,2x so hell wie Tiefblau (--tone-1) — wer aus
     diesen Token Flächen mit fester Alpha aufbaut, muss die Deckkraft je
     Stufe gegenläufig ausgleichen, sonst wirkt die Leiter am türkisen Ende
     ausgebrannt und am blauen Ende blass. */
  --tone-1: #4d7fff;   /* 4.30:1 auf --panel-elevated — NUR Leuchten/Rand, nie Text */
  --tone-2: #5c9dff;   /* 5.73:1 */
  --tone-3: #3bb0fc;   /* 6.53:1 */
  --tone-4: #17c1f5;   /* 7.40:1 */
  --tone-5: #22d3ee;   /* 8.62:1 */
  --tone-6: #2fd0d0;   /* 8.20:1 */

  /* Eine Farbe je Bento-Kachel-"Art" — jetzt Stufen derselben Farbleiter
     statt eigener Hexwerte, erweiterbar für künftige Arten. */
  --type-new: var(--tone-2);
  --type-mix: var(--tone-3);
  --type-master: var(--tone-4);
  --type-local: var(--tone-5);
  --type-local-recent: var(--tone-6);

  /* Schutz-Token: zwei Stellen nutzten die Typ-Token bisher zweckfremd mit
     eigener Bedeutung. Damit die Farbleiter sie nicht unbemerkt mitfärbt,
     tragen sie jetzt ihren bisherigen Hexwert unter eigenem Namen weiter —
     gleiches Muster wie --tile-bg/--tile-bg-hover (Commit 17d3248). */
  --status-ok: var(--success); /* bis 2026-10-11 Türkis #2fd0d0, Status ist jetzt grün, Türkis bleibt Wellenform */
  --brand-discord: #c792ea;  /* bisheriger Wert von --type-local, bewusst nah an der Discord-Markenfarbe */

  /* --- Glas (static/js/liquid-glass.js) --------------------------------
     Seit 2026-10-11 praktisch deckend (Grundton --panel bzw.
     --panel-elevated): Karten sind ruhige Flächen, das Hintergrundraster
     scheint nicht mehr durch. Material mit Durchblick gibt es nur noch für
     schwebende Leisten (--material-*). Die Namen bleiben, weil elf
     Stellen (Editor, Marketplace, Panels) und liquid-glass.js daran hängen. */
  --glass-bg: rgba(24, 27, 33, 0.94);
  --glass-bg-hover: rgba(32, 36, 43, 0.97);
  /* Eigene Werte NUR für die Bento-Kacheln (.tile); ebenfalls deckend,
     damit Name und Meta auf ruhiger Fläche stehen. */
  --tile-bg: rgba(24, 27, 33, 0.96);
  --tile-bg-hover: rgba(32, 36, 43, 0.98);
  --glass-border: rgba(255, 255, 255, 0.08);
  --glass-border-hover: rgba(106, 168, 255, 0.45);

  /* --- Geometrie -------------------------------------------------------
     Radien moderat 8/12/16 (Nutzerentscheidung 2026-10-11; bisher 8/14/20).
     Regel: innen = außen − Innenabstand. --radius-full ist keine Stufe,
     sondern die Pillenform (Badges, Avatare, runde Play-Knöpfe). */
  --radius-s: 8px;           /* Knöpfe, Felder, Sidebar-Einträge */
  --radius-m: 12px;          /* Karten, gruppierte Listen, Popover */
  --radius-l: 16px;          /* Bento-Kacheln, Dialoge, Sheets */
  --radius-full: 999px;

  /* Abstandsraster (4-px-Raster) und Steuerelementhöhen. Erst definiert,
     eingesetzt ab Optik-Stufe 2 (DESIGNRICHTUNG 2.3). */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --control-h-s: 24px;       /* Editor, Tabellen */
  --control-h-m: 32px;       /* Standard in der App */
  --control-h-l: 40px;       /* Anmeldung, Hauptaktion */
  --hit-min: 44px;           /* Mindestmaß unter (pointer: coarse) */
  --content-max: 1080px;
  --content-max-narrow: 760px;
  --page-pad-x: clamp(16px, 4vw, 40px);
  --toolbar-h: 52px;

  /* Schrift: Fließtext in Systemschrift (Nutzerentscheidung 2026-10-11).
     --font-body bleibt als Name bestehen, weil html/body und zehn weitere
     Stellen ihn nutzen; er zeigt jetzt auf --font-text (unten). Space
     Grotesk bleibt nur Marke und Überschriften. fonts.css bleibt
     unangetastet (die VST-Ressourcentests zählen dort zehn Verweise). */
  --font-display: "Space Grotesk", var(--font-text);
  --font-body: var(--font-text);
  --font-mono: "JetBrains Mono", monospace;

  /* Sidebar 232/60 statt 264/76 (DESIGNRICHTUNG 2.7, Nachtrag AP1b vom
     2026-10-11). Erst gesetzt, nachdem Stufe 2 die Sidebar umgebaut hat
     (ab 1200 px offen, Symbolknopf statt Fader). Die drei calc()-Einzüge in
     style.css bleiben bei 60 px positiv: (60 − 2·12 − 18)/2 = 9,
     (60 − 24 − 28)/2 = 4, (60 − 24 − 32)/2 = 2. */
  --sidebar-w: 232px;
  --sidebar-w-collapsed: 60px;

  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  --lg-filter: none;

  /* --- Altlasten: benutzt, aber bis hierher NIRGENDS definiert ---------
     Neun Variablen wurden im Stylesheet eingesetzt, ohne je definiert zu
     sein. Acht davon trugen einen hartcodierten Ersatzwert aus einer
     fremden, grauen Palette (`var(--surface, #1b1b1f)`), der deshalb immer
     griff — diese Flächen liefen also dauerhaft am Theme vorbei.
     `--text` hatte nicht einmal einen Ersatzwert: `color: var(--text)` ist
     ungültig und fiel auf die geerbte Farbe zurück (editor.css:2815, 2840,
     2860, 2932). Hier werden sie auf die echten Token abgebildet; die
     Fundstellen selbst bleiben unverändert. --------------------------- */
  --text: var(--text-primary);
  --surface: var(--panel);
  --surface-2: var(--panel-elevated);
  --surface-3: #2a2f37;      /* gewähltes Segment, Hover in Menüs, kein --text-dim darauf */
  --panel-2: var(--panel);
  --bg-panel: var(--panel);
  --bg-input: var(--panel-deep);
  --bg-secondary: var(--panel-elevated);
  --border-color: var(--border-strong);
}

/* ==========================================================================
   Stellen, die diese Token nicht erben können
   ==========================================================================

   Drei Sitzungen arbeiten parallel an diesem Repo; Stellen, die eine
   CSS-Variable technisch gar nicht laden können, tragen ihre Farbe
   zwangsläufig als Hexwert und müssen bei jeder Palettenänderung von Hand
   nachgezogen werden. Ohne Begründung sieht so ein Eintrag wie eine
   vergessene Aufräumarbeit aus und wird irgendwann "bereinigt" — mit
   Begründung ist klar, dass er so bleiben MUSS. Neue Einträge unten
   anhängen, gleiches Format: Datei, Zeile(n), hartcodierte Werte, Grund.

   1. src/client/app.py, Zeilen 363–385, `_show_unreachable_window`.
      Hartcodiert: #151925, #f0f2f7, #b9c2d4, #5c9dff, #0d1117, #e85d4d.
      Grund: Dieses Fenster meldet, dass der Server NICHT erreichbar ist —
      es kann sein Stylesheet schlecht ausgerechnet von diesem Server
      holen. Stand 2026-10-11: noch die alte Navy-Palette. Mit Optik-Stufe 1
      gilt --bg #101216, --text-primary #f1f3f6, --text-secondary #b6bcc7,
      --accent #6aa8ff (bzw. --accent-fill #2262d6 mit Weiß für Knöpfe);
      nachziehen übernimmt die für src/client/app.py zuständige Sitzung.

   2. src/client/app.py, Zeile 1041, Update-Hinweis.
      Hartcodiert: `background: #1f2430; color: #f2f2f2`.
      Kein Erbproblem, sondern eine Altlast aus einer fremden Palette —
      beide Werte gehören zu KEINEM Token dieses Projekts (--panel ist
      #1f2534, --text-primary ist #f0f2f7). Der Hinweis wird per
      evaluate_js in die laufende Seite injiziert, könnte also technisch
      auf --panel/--text-primary umgestellt werden; das übernimmt die für
      src/client/app.py zuständige Sitzung. Eintrag entfällt danach.

   3. src/vst/src/SatelliteEditor.cpp, Konstanten im anonymen Namespace
      (background, textColour, mutedColour, accentColour, panelColour,
      rowColour, borderColour, dimColour).
      Hartcodiert: die Navy-Palette vor 2026-10-11 (#151925, #f0f2f7,
      #b9c2d4, #5c9dff, #1f2534, #283042, #3d4763, #98a1b5).
      Grund: JUCE zeichnet nativ und kann keine CSS-Variable lesen. Muss mit
      dem nächsten VST-Build auf --bg #101216, --text-primary #f1f3f6,
      --text-secondary #b6bcc7, --accent #6aa8ff, --panel #181b21,
      --panel-elevated #20242b, --border #323741, --text-dim #8e95a2
      nachgezogen werden (zuständig: VST-Sitzung).
   ========================================================================== */

/* ==========================================================================
   Design-Grundlagen nach Apple-Vorbild (Apple-Design-Plan AP1, 2026-10-11)
   ==========================================================================

   Warum ein eigener Abschnitt statt Änderungen oben: Die Werte oben tragen
   Palette, Radien und Glas (seit Optik-Stufe 1 vom 2026-10-11 Graphit,
   8/12/16, deckend). Dieser Abschnitt ERGÄNZT nur Token für Schrift,
   Bewegung und Material; `--ease` bleibt unverändert. So kann jede Datei einzeln umziehen (Marke
   "design-system: migriert" als eigener Kommentar, bewacht von
   tests/test_design_system_css.py), und ein späterer Optik-Schritt kann die
   neuen Token gezielt nachstellen, ohne Altbestand mitzuziehen.

   Nutzerentscheidungen vom 2026-10-11, die hier festgeschrieben sind:
   - Fließtext läuft über den system-ui-Stack (`--font-text`). Er bringt
     optische Größen, Laufweitentabellen und Hinting des Betriebssystems mit.
     Space Grotesk bleibt nur die Marken-Display-Schrift (`--font-display`,
     unverändert). fonts.css bleibt unangetastet (die VST-Ressourcentests
     zählen dort genau zehn Verweise).
   - Regler (Fader, Knopf, EQ) folgen dem Zeiger 1:1 und schwingen nie
     nach. Die Federn unten sind für Sheets, Schubladen und Dialoge da, NIE
     für Reglerwerte.
   - Nur Dark Mode. Es gibt deshalb keinen prefers-color-scheme-Block.

   Diese Datei bleibt selektorfrei: nur `:root` und die drei Media-Blöcke
   am Ende, kein url(), kein @import. Das VST-Plugin liefert sie unverändert
   aus seinem DLL aus und löst dort keine Pfade auf.
   ========================================================================== */

:root {
  /* --- Schriftfamilien --------------------------------------------------
     `--font-text` für alles, was gelesen wird.
     Seit 2026-10-12 steht "Segoe UI Variable Text" VOR system-ui. Grund:
     Chrome löst system-ui unter Windows auf die klassische "Segoe UI" auf
     und sucht für Gewicht 600 deren Datei segoeuisb.ttf. Fehlt sie (auf
     einem Entwickler-PC gemessen), nimmt Chrome den nächstschwereren
     Schnitt, "Segoe UI Black" (900): Knöpfe und Titel wurden plakativ fett.
     Die variable Fassung von Windows 11 deckt 300-700 aus einer Datei ab
     und kennt das Problem nicht. Ohne sie (macOS, Linux, Windows 10) greift
     wie bisher system-ui, danach die übrigen Systemschriften. */
  --font-text: "Segoe UI Variable Text", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* --- Typo-Skala --------------------------------------------------------
     Je Stufe drei Werte als Satz: Größe (rem, wächst mit der
     Schriftgrößeneinstellung des Nutzers mit), Zeilenhöhe (große Schrift
     eng, kleine luftiger) und Laufweite (große Schrift negativ, weil die
     Buchstaben mit der Größe optisch auseinanderdriften; kleine leicht
     positiv für Lesbarkeit). Eine einzige feste Laufweite für alle Größen
     wäre an irgendeiner Stelle immer falsch.
     Basis 1rem = 16px. Die App ist eine dichte Arbeitsoberfläche, deshalb
     liegt `body` bei 14px statt der 17px eines Telefons. */
  --size-display: 2.5rem;       /* 40px — Markenzeilen, Hero */
  --leading-display: 1.1;
  --tracking-display: -0.022em;

  --size-title-1: 1.75rem;      /* 28px — Seitentitel */
  --leading-title-1: 1.18;
  --tracking-title-1: -0.018em;

  --size-title-2: 1.375rem;     /* 22px — Abschnittstitel */
  --leading-title-2: 1.25;
  --tracking-title-2: -0.012em;

  --size-title-3: 1.125rem;     /* 18px — Karten-, Dialogtitel */
  --leading-title-3: 1.3;
  --tracking-title-3: -0.006em;

  --size-headline: 0.9375rem;   /* 15px — betonte Zeile, mit --weight-semibold */
  --leading-headline: 1.35;
  --tracking-headline: -0.002em;

  --size-body: 0.875rem;        /* 14px — Fließtext */
  --leading-body: 1.5;
  --tracking-body: 0em;

  --size-callout: 0.8125rem;    /* 13px — Beschriftungen, Listen */
  --leading-callout: 1.45;
  --tracking-callout: 0.004em;

  --size-footnote: 0.75rem;     /* 12px — Meta-Zeilen, Hinweise */
  --leading-footnote: 1.4;
  --tracking-footnote: 0.008em;

  --size-caption: 0.6875rem;    /* 11px — Achsen, Badges; kleinste Stufe */
  --leading-caption: 1.35;
  --tracking-caption: 0.016em;

  /* Hierarchie entsteht aus Gewicht + Größe + Zeilenhöhe als Satz. */
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;

  /* --- Bewegung ----------------------------------------------------------
     Federn als linear()-Kurven, analytisch aus der Sprungantwort eines
     gedämpften Feder-Masse-Systems gerechnet (33 gleichmäßige Stützstellen,
     Ende dort, wo die Abweichung unter 0,1 % fällt). Die Dauer gehört fest
     zur Kurve: wer --spring nimmt, nimmt --dur-spring dazu.

     --spring           Dämpfung 1.0, Antwort 0.35 s: kein Überschwingen.
                        Standard für alles, was auf- oder zugeht.
     --spring-momentum  Dämpfung 0.8, Antwort 0.3 s (Apples Wert für
                        Schubladen/Sheets): 1,5 % Überschwingen. NUR, wenn
                        vorher eine Geste Schwung mitgebracht hat (Wischen,
                        Werfen, Loslassen nach Ziehen).

     Regler bekommen keine dieser Kurven (siehe Kopf).

     --motion-scale ist ein Faktor für Wege: translate(calc(var(--motion-scale)
     * 24px)). Unter prefers-reduced-motion fällt er auf 0, dann bleibt nur
     die Überblendung übrig statt einer Bewegung. */
  --spring: linear(0, 0.035, 0.116, 0.218, 0.325, 0.428, 0.522, 0.605, 0.677, 0.737, 0.788, 0.83, 0.864, 0.892, 0.914, 0.932, 0.947, 0.958, 0.967, 0.974, 0.98, 0.984, 0.988, 0.991, 0.993, 0.994, 0.996, 0.997, 0.997, 0.998, 0.998, 0.999, 1);
  --dur-spring: 520ms;
  --spring-momentum: linear(0, 0.031, 0.108, 0.21, 0.322, 0.434, 0.541, 0.637, 0.72, 0.791, 0.849, 0.896, 0.932, 0.96, 0.98, 0.994, 1.004, 1.01, 1.014, 1.015, 1.015, 1.014, 1.013, 1.011, 1.009, 1.008, 1.006, 1.005, 1.004, 1.003, 1.002, 1.001, 1);
  --dur-spring-momentum: 410ms;

  /* Feste Dauern für Farb-, Deckkraft- und Hover-Wechsel, die keine Feder
     brauchen. */
  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-slow: 320ms;

  /* Rückmeldung beim Drücken: sofort auf pointerdown, nicht erst beim
     Loslassen. 0.97 ist sichtbar, ohne dass Text im Knopf springt. */
  --press-scale: 0.97;
  --dur-press: 100ms;

  --motion-scale: 1;

  /* --- Materialien -------------------------------------------------------
     Vier Stufen von durchlässig nach dicht. Größere Flächen nehmen die
     dichtere Stufe mit stärkerem Blur und tieferem Schatten. Nie zwei
     durchlässige Flächen übereinander, sonst kippt die Lesbarkeit.
     Hintergrund und Filter immer zusammen setzen:
       background: var(--material-regular-bg);
       backdrop-filter: var(--material-regular-filter);
     Die Grundtöne sind --bg, --panel und --panel-deep mit Alpha (seit
     2026-10-11 die Graphit-Palette). */
  --material-ultrathin-bg: rgba(16, 18, 22, 0.38);
  --material-ultrathin-filter: blur(12px) saturate(140%);
  --material-thin-bg: rgba(24, 27, 33, 0.55);
  --material-thin-filter: blur(16px) saturate(160%);
  --material-regular-bg: rgba(24, 27, 33, 0.72);
  --material-regular-filter: blur(24px) saturate(180%);
  --material-thick-bg: rgba(11, 13, 16, 0.86);
  --material-thick-filter: blur(32px) saturate(180%);

  /* Lichtkante: helle Oberkante, an der das Licht das Material trifft. Als
     box-shadow-Wert, damit sie keinen Platz im Layout belegt. */
  --material-edge-color: rgba(255, 255, 255, 0.1);
  --material-edge: inset 0 1px 0 0 var(--material-edge-color);

  /* Rand- und Fokusbreiten. Unter prefers-contrast: more werden sie
     kräftiger. */
  --border-width: 1px;
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;

  /* Schatten: klein für Chips/Knöpfe, mittel für Karten/Menüs, groß für
     Dialoge und Sheets. Reines Schwarz mit Alpha, damit die Farbe der
     Fläche darunter bleibt. */
  --shadow-s: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 1px rgba(0, 0, 0, 0.2);
  --shadow-m: 0 4px 12px rgba(0, 0, 0, 0.32), 0 1px 3px rgba(0, 0, 0, 0.24);
  --shadow-l: 0 16px 40px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.28);

  /* Abdunklung hinter modalen Dialogen ("abdunkeln, um zu fokussieren").
     Nicht modale Seitenpaneele bekommen keinen Scrim. */
  --scrim: rgba(8, 10, 16, 0.6);

  /* Scroll-Kanten: weicher Auslauf statt harter Trennlinie, wo Inhalt
     unter schwebende Leisten läuft. Nutzung:
       mask-image: var(--scroll-edge-mask);
     Die Maske wertet nur die Deckkraft aus; #000 heißt hier "sichtbar",
     nicht "schwarz". */
  --scroll-edge-size: 1.5rem;
  --scroll-edge-mask: linear-gradient(to bottom, transparent 0, #000 var(--scroll-edge-size), #000 calc(100% - var(--scroll-edge-size)), transparent 100%);
  --scroll-edge-mask-x: linear-gradient(to right, transparent 0, #000 var(--scroll-edge-size), #000 calc(100% - var(--scroll-edge-size)), transparent 100%);
}

/* ==========================================================================
   Nutzereinstellungen des Betriebssystems (2026-10-11)
   ==========================================================================

   Die drei Blöcke überschreiben NUR Bewegungs-, Material- und Rand-Token.
   Sie tragen KEINE Farbwerte, auch nicht als rgba() oder Farbname, sondern
   verweisen höchstens per var() auf bestehende Token. Grund: Ein Farbwert
   hier unten wäre eine zweite Palette, die check_contrast.py nicht
   nachrechnet. Bis 2026-10-11 las das Skript jede Zeile `--name: #hex;` und
   behielt den LETZTEN Wert, ein Farbwert hier hätte also still die
   Basisfarbe ersetzt. Seitdem liest es nur noch die Basis-`:root`-Blöcke
   (Gegenprobe in tests/test_check_contrast.py), die Regel bleibt trotzdem.
   tests/test_design_system_css.py bewacht sie.

   Reihenfolge mit Absicht: "mehr Kontrast" steht zuletzt und gewinnt, wenn
   zugleich "weniger Transparenz" gesetzt ist. */

/* Weniger Bewegung: keine Wege, kein Überschwingen, kein Drück-Schrumpfen.
   Überblendungen bleiben, weil sie Zustandswechsel verständlich machen,
   ohne das Gleichgewichtsorgan zu reizen. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --spring: var(--ease);
    --dur-spring: var(--dur-base);
    --spring-momentum: var(--ease);
    --dur-spring-momentum: var(--dur-base);
    --press-scale: 1;
    --motion-scale: 0;
  }
}

/* Weniger Transparenz: Materialien werden deckend und verlieren den Blur.
   Die Glas- und Kachel-Token oben ziehen mit, damit auch der Altbestand
   (Bento-Kacheln, liquid-glass.js) deckend wird. */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --material-ultrathin-bg: var(--bg);
    --material-ultrathin-filter: none;
    --material-thin-bg: var(--panel);
    --material-thin-filter: none;
    --material-regular-bg: var(--panel);
    --material-regular-filter: none;
    --material-thick-bg: var(--panel-deep);
    --material-thick-filter: none;
    --glass-bg: var(--panel);
    --glass-bg-hover: var(--panel-elevated);
    --tile-bg: var(--panel);
    --tile-bg-hover: var(--panel-elevated);
  }
}

/* Mehr Kontrast: deckende Flächen mit klarer Kante. Trennlinien nehmen das
   Bedienelement-Rand-Token (>= 3:1), Ränder und Fokusring werden breiter,
   die Scroll-Kanten laufen nicht mehr aus, sondern enden hart. */
@media (prefers-contrast: more) {
  :root {
    --material-ultrathin-bg: var(--bg);
    --material-ultrathin-filter: none;
    --material-thin-bg: var(--panel);
    --material-thin-filter: none;
    --material-regular-bg: var(--panel);
    --material-regular-filter: none;
    --material-thick-bg: var(--panel-deep);
    --material-thick-filter: none;
    --material-edge-color: var(--border-strong);
    --border-soft: var(--border-strong);
    --border: var(--border-strong);
    --glass-border: var(--border-strong);
    --border-width: 2px;
    --focus-ring-width: 3px;
    --scroll-edge-mask: none;
    --scroll-edge-mask-x: none;
  }
}
