/*
 * PrintSupport — Design-Tokens, übernommen aus dem Android-Theme:
 *   app/src/main/java/com/antongebauer/filamentfinder/ui/theme/Color.kt  (alle Farbwerte)
 *   app/src/main/java/com/antongebauer/filamentfinder/ui/theme/Theme.kt  (Rollenzuordnung hell/dunkel)
 *   app/src/main/java/com/antongebauer/filamentfinder/ui/theme/Abstand.kt (4/8/12/16-dp-Raster)
 *   app/src/main/java/com/antongebauer/filamentfinder/ui/theme/Type.kt   (M3-Standardskala, Fettdruck nur preisProKg)
 *
 * Wie in der App besetzen die Markenfarben (Indigo/Cyan/Rosé aus dem PrintSupport-Logo)
 * ausschließlich die Akzentrollen; die Flächen bleiben neutral, damit der Preis pro
 * Kilogramm seine Sonderstellung behält.
 *
 * ============================================================================
 * ⛔ DIE SEITE IST DAUERHAFT DUNKEL — ES GIBT NUR NOCH EIN SCHEMA (03.09.2026)
 * ============================================================================
 *
 * Diese Datei hatte bis dahin ZWEI Blöcke: :root mit den hellen Werten und
 * :root[data-theme="dunkel"] mit 65 Überschreibungen darüber. Der zweite ist
 * ersatzlos entfallen, seine Werte stehen jetzt hier als die einzigen.
 *
 * ⛔ ES GIBT KEIN data-theme MEHR, und es darf keines zurückkommen. Wer einen
 * zweiten Satz Flächen einführt, führt zugleich jede Regel dieser Datei
 * doppelt — und jede Textfarbe muss dann gegen zwei Untergründe gemessen
 * werden statt gegen einen. Genau das ist hier abgeschafft worden.
 *
 * ⛔ VON DEN 108 TOKENS SIND 65 FARBROLLEN, 43 SIND ES NICHT (Abstände,
 * Typografie, Radien, Dauern, Markenmetriken). Nur die ersten hatten je eine
 * zweite Fassung; die zweiten waren immer schon schemaunabhängig.
 *
 * ⚠️ prefers-color-scheme wird nirgends mehr ausgewertet. Die Seite folgt
 * der Systemeinstellung nicht — das ist eine Entscheidung, kein Versehen.
 *
 * ----------------------------------------------------------------------------
 * ⛔ ZWEI STELLEN, AN DENEN ES TROTZDEM HELL IST — beide mit Grund
 * ----------------------------------------------------------------------------
 *
 * 1. DAS BILDFELD DER SCHEMAZEICHNUNG (--schema-feld und die drei Rollen
 *    daneben, weiter unten). Es ist eine technische Zeichnung auf hellem
 *    Grund, wie ein Foto, das im Dunkeln auch nicht dunkler wird. Diese vier
 *    Rollen standen schon vor dem 03.09. in BEIDEN Blöcken wertgleich; sie
 *    haben die Zusammenführung deshalb unverändert überstanden.
 *
 * 2. DAS PAPIER (css/basis.css, @media print). Auf Papier wird nicht dunkel
 *    gedruckt, und der Druckblock setzte bis zum 03.09.2026 zwar Papierfarbe
 *    und Textfarbe, aber KEINE Farbtokens — gemessen stand --on-surface dort
 *    bei 1,25:1 und --on-surface-variant bei 1,70:1 auf weißem Grund. Das war
 *    schon vorher kaputt, sobald jemand im Dunkelmodus druckte; seit es kein
 *    anderes Schema mehr gibt, wäre es der Normalfall. Die helle Palette lebt
 *    deshalb dort weiter — als Medium, nicht als Schema: kein Attribut, kein
 *    Umschalter, keine Systemabfrage.
 *
 * ⛔ WER HIER EINE FARBROLLE ÄNDERT, ÄNDERT SIE IM DRUCKBLOCK MIT — falls sie
 * dort ein Gegenstück hat. Die beiden Sätze sind bewusst getrennt (Papier ist
 * kein zweites Schema), aber sie beschreiben dieselben Rollen.
 *
 * ----------------------------------------------------------------------------
 * ⛔ DER TRÄGER DER ABGRENZUNG IST DIE KANTE, NICHT DIE FLÄCHE (02.09.2026)
 * ----------------------------------------------------------------------------
 *
 * Das gilt unverändert weiter und ist der Grund für --karten-kante und
 * --feld-kante. Die Zahlen des Gestaltungswechsels sind am hellen Schema
 * gemessen worden (Grund #F4F5F7 -> Karte #FFFFFF = 1,09:1, Kante #DCDFE6
 * beidseitig sichtbar); dunkel trägt die Flächenstufe mehr bei (#0F1115 ->
 * #181B21 = 1,3:1), die Kante kommt hinzu (#3D434B gegen die Karte 1,73:1).
 *
 * ⚠️ WER --karten-kante ODER --feld-kante WEGLÄSST, SCHWÄCHT DIE ABGRENZUNG.
 * Hell ließ er das Element ganz verschwinden; dunkel bleibt die Flächenstufe
 * übrig, aber die Seite verlöre ihr Gestaltungsmittel.
 *
 * ⚠️ Alle Textfarben sind auf ihren Flächen nachgemessen (Projektregel „Wer
 * eine Fläche ändert, misst die Texte darauf nach") — jetzt gegen EINEN Satz
 * Flächen statt gegen zwei. tests/pruefung.html rechnet sie bei jedem Lauf
 * neu aus dieser Datei.
 */

:root {
  /* --- Akzentrollen ---------------------------------------------------

     ⛔ --primary IST SEIT DEM 02.09.2026 NICHT MEHR DIE MARKENFARBE.
     Bis dahin trug diese Rolle das Indigo des Logos und damit zwei Dinge
     zugleich: den Akzent der Oberfläche UND die Wortmarke. Die Vorlagen
     verlangen ein kräftigeres, kühleres Blau für Preise und Knöpfe — und
     die Marke soll davon unberührt bleiben. Beides zusammen geht nur, wenn
     die Marke ihre eigene Rolle bekommt: --marke-akzent weiter unten.
     Wer hier etwas ändert, ändert die Marke NICHT mit; das ist Absicht,
     kein Vergessen. ⚠️ Seit dem 07.09.2026 ist die Marke eine Zeichnung,
     und ihre dunkle Hälfte nimmt `currentColor` — nur der Akzent hat noch
     eine eigene Rolle.

     ⚠️ Der Wert ist die AUFGEHELLTE Fassung desselben Blautons, nicht eine
     zweite Farbe daneben: Das Akzentblau der Vorlagen ist #2B50E0, und
     #8AA4FF ist es, so weit aufgehellt, dass es auf dunklem Grund trägt.
     (Bis zum 03.09.2026 standen beide in dieser Datei, je Schema eines.)

     Gemessen: #8AA4FF auf der Seite 7,95:1, auf der Karte 7,26:1 (Preis,
     Links), --on-primary darauf 7,29:1 (gefüllter Knopf, 14px/500). Beide
     Richtungen tragen — das ist die Bedingung dafür, dass dieselbe Rolle
     Fläche und Schrift sein darf. */
  --primary: #8AA4FF;
  --on-primary: #0C1740;
  /* Der Materialbadge der Kacheln und Detailseiten. 7,70:1. */
  --primary-container: #1E3AAE;
  --on-primary-container: #DCE4FF;
  --secondary: #22D3EE;            /* Cyan (Logoton) */
  --on-secondary: #164E63;
  --secondary-container: #155E75;  /* CyanContainerDunkel */
  --on-secondary-container: #CFFAFE; /* CyanHell */
  --tertiary: #FB7185;             /* Rose */
  --on-tertiary: #881337;
  --tertiary-container: #9F1239;   /* RoseContainerDunkel */
  --on-tertiary-container: #FFE4E6; /* RoseHell */

  /* --- Akzent der Marke (07.09.2026) ---------------------------------

     ⛔ HIER STANDEN --spulen-fuellung, --marke-print UND --marke-support.
     Alle drei sind mit dem Logotausch entfallen:

       --spulen-fuellung   der sichtbare Anteil in assets/logo-spule.png
                           (588 von 1024 Punkten). Die neuen Dateien tragen
                           keinen transparenten Rand — gemessen viewBox =
                           Inhalt, alle vier Ränder 0,000. Es gibt nichts
                           mehr auszugleichen.
       --marke-print       das Indigo des Schriftzugs
       --marke-support     das Rosé des Schriftzugs

     Die beiden Farbrollen trugen die zwei Hälften des GESCHRIEBENEN
     Markennamens. Den gibt es nicht mehr; die Wortmarke ist eine Zeichnung.

     ⛔ AN IHRE STELLE TRITT EINE EINZIGE ROLLE, und die dunkle Hälfte
     bekommt gar keine: Sie nimmt `currentColor` und folgt damit der
     Schriftfarbe ihrer Umgebung. Das ist mehr als eine Ersparnis — es ist
     der Grund, warum die Marke auf Papier richtig herauskommt, ohne dass
     irgendwo eine Fallunterscheidung steht.

     ⚠️ Der Wert ist das Cyan aus den Vorlagedateien, unverändert. Gemessen
     auf der Kopfleiste 8,44:1, auf der Seite 10,51:1 — beide weit über der
     Schwelle, ab der ein grafisches Objekt erkennbar ist.

     ⛔ AUF PAPIER TRÄGT ER NICHT (1,80:1 auf Weiß). Der Druckblock in
     css/basis.css setzt deshalb eine dunklere Fassung. Wer diesen Wert
     ändert, sieht dort nach — die beiden gehören zusammen. */
  --marke-akzent: #01D3F8;

  /* --- Fehlerrollen (M3-Standard) --- */
  --error: #F2B8B5;
  --on-error: #601410;
  --error-container: #8C1D18;
  --on-error-container: #F9DEDC;

  /* --- Neutrale Flächen -----------------------------------------------

     ⛔ DIE RAMPE STEIGT AUS DEM GRUND HERAUS. Gemessen (L* und Verhältnis
     gegen die Seite):

       Seite     #0F1115   L*   5,0    —      Hintergrund und --surface
       lowest    #0A0C10   L*   3,3   −1,7    Eingabefelder, Farbproben
       low       #14171C   L*   7,6   +4,3    zarte Bänder, Filterband
       container #181B21   L*   9,7   +2,1    KARTEN, Filterspalte
       high      #22262D   L*  15,0   +5,3    Kopfleiste, Menüs, Felder
       highest   #2C3138   L*  20,1   +5,1    abgesetzte Fläche IN der Karte

     ⚠️ Ab etwa 1,15:1 wird eine Fläche ohne Rahmen überhaupt wahrnehmbar.
     Die Karte liegt mit 1,10:1 knapp darunter — sie trägt die Abgrenzung
     deshalb NICHT allein, sondern zusammen mit --karten-kante (#3D434B
     gegen die Karte 1,73:1). Kopfleiste (1,24:1) und Wertblase (1,44:1)
     tragen sie auch über die Fläche.

     ⛔ HOVER UND AKTIV KOMMEN NICHT AUS DIESER RAMPE. Sie liegen in
     --zustand-hover / --zustand-aktiv weiter unten, und das ist keine
     Feinheit: Die Kopfleiste steht selbst auf --high, ihr Hover lag damit
     bei 1,00:1 — eine Rückmeldung, die es nicht gab. Wer Hover je wieder aus
     der Rampe holt, bringt den Fehler zurück; tests/pruefung.html wacht
     darüber.

     ⛔ --surface-container-highest ist die „abgesetzte Fläche INNERHALB
     einer Karte": Balken- und Reglerschienen, Bildflächen, hervorgehobene
     Zeilen, Wertblase. Der Abstand zur Karte ist dL* 10,4 — der Prüffall
     misst ihn als Betrag und verlangt mindestens 2,5.

     ⚠️ --surface-container-lowest ist DUNKLER als die Seite und damit die
     tiefste Stufe. Die fünf Stellen, die sie benutzen, sind Eingabefelder
     (.filter-suchfeld, .ordner-feld textarea) und neutrale Grundflächen für
     Farbproben (.farbpunkt, .farbflaeche--transparent, .vl-bild) — sie
     wollen eine ruhige Grundfläche, keine Erhebung.

     ----------------------------------------------------------------------
     ⚠️ VORGESCHICHTE, weil ihre Lehre über den Einzelfall hinausgeht:

     Bis zum 03.09.2026 gab es diese Rampe zweimal. Die HELLE Fassung war
     mehrfach Ursache stiller Fehler, und immer nach demselben Muster —
     nahe Weiß liefern große Zahlensprünge nur winzige Kontraste (#FFFFFF
     gegen #E0E0E0 sind erst 1,32:1). Am 08.08.2026 stand deshalb der ganze
     Bestand bei 1,07–1,16:1 und die Seite las sich als eine weiße Fläche;
     am 11.08.2026 standen -high und -highest beide auf #FFFFFF, wodurch
     jede Rückmeldung „eine Stufe höher" unsichtbar war.

     ⛔ Und zweimal riss eine Flächenänderung eine TEXTfarbe mit: Eine
     Abtönung um dL* 1,7 kostete --balken-gruen 4,65 -> 4,45:1 und
     --stern-gelb 3,13 -> 2,89:1, ohne dass jemand eine Textfarbe angefasst
     hätte. Diese Regel gilt unverändert für das eine verbliebene Schema:
     WER EINE FLÄCHE ÄNDERT, MISST DIE TEXTE DARAUF NACH. */
  --background: #0F1115;
  --on-background: #E3E6EA;
  --surface: #0F1115;
  --on-surface: #E3E6EA;
  --surface-variant: #2A2F37;
  --on-surface-variant: #C2C7CF;
  /* ⛔ ZWEI LINIENROLLEN, UND SIE SIND NICHT AUSTAUSCHBAR.

     --outline begrenzt BEDIENELEMENTE (Chip, Suchfeld, Balkenschiene,
     Druckerpille) und muss dafür nach WCAG 1.4.11 seine 3:1 tragen —
     gemessen 6,03:1 gegen die Seite, 5,50:1 gegen die Karte, 4,84:1 gegen
     die Kopfleiste. Wer hier --outline-variant einsetzt, weil es „ruhiger
     aussieht", nimmt dem Bedienelement seine Grenze.

     --outline-variant ist die Haarlinie: Kartenkante, Trennlinien,
     Tabellenlinien. Sie soll ausdrücklich NICHT 3:1 tragen — gemessen
     1,89:1 gegen die Seite, 1,73:1 gegen die Karte, 1,52:1 gegen die
     Kopfleiste. Sichtbar, ohne die Seite in ein Gitter zu zerlegen. Wer sie
     weiter zurücknimmt, nimmt der Karte ihre Abgrenzung. */
  --outline: #8C929B;
  --outline-variant: #3D434B;
  --surface-container-lowest: #0A0C10;
  --surface-container-low: #14171C;
  --surface-container: #181B21;
  --surface-container-high: #22262D;
  --surface-container-highest: #2C3138;
  --inverse-surface: #E3E6EA;
  --inverse-on-surface: #14171C;

  /* --- Kante der Karten und Felder ------------------------------------

     ⛔ NUR DIE HAARLINIE, KEIN SCHATTEN — und das ist gemessen, nicht
     gespart: Ein weicher schwarzer Schatten ist auf einem fast schwarzen
     Grund unsichtbar; er kostete Rechenzeit und zeigte nichts. Der große
     Schatten bleibt echten Überlagerungen vorbehalten
     (--schatten-schwebend: Menü, Sheet, Snackbar, aufgesetzte Preiskarte).

     ⚠️ Die Kante trägt die Abgrenzung ZUSAMMEN mit der Flächenstufe
     (Karte 1,10:1 gegen die Seite, Kante 1,73:1 gegen die Karte). Bis zum
     03.09.2026 gab es diese Rolle in zwei Fassungen: hell trug die Kante
     alles allein (Fläche 1,09:1), dunkel stand sie zeitweise sogar auf
     `none`. Beides ist Geschichte — sie ist seit dem 02.09.2026 das
     Gestaltungsmittel der Seite („klare Flächen, feine Ränder").

     ⚠️ Als box-shadow und NICHT als border. Ein Rahmen wüchse in die Breite
     jeder Karte (2px je Kachel) und verschöbe Raster, Spaltenbreiten und
     die gemessene Randsymmetrie.

     ⛔ INSET, und das ist der Unterschied zwischen „liegt an der Kante" und
     „liegt daneben" (17.09.2026). Ein ÄUSSERER Schatten mit 1px Spread malt
     seine Linie eine Pixelspalte AUSSERHALB des Kastens — und damit außerhalb
     jeder Fläche, die den Kasten deckt. Gemessen auf /filamente bei 1440px:
     Werkzeugzeile und Kachelreihe stehen beide bei 512…1364, die Kante lag
     aber bei x = 1364 und x = 511 und stand beim Rollen über die volle Höhe
     der klebenden Zeile sichtbar da (rgb(61,67,75) auf rgb(15,17,21)). Es sah
     aus, als klebe die Leiste zu schmal; zu schmal war sie nie.

     ⚠️ Nach innen kann das nicht passieren: Die Linie liegt dann innerhalb
     des Kastens und wird von jeder darüberliegenden Fläche verdeckt, so wie
     der Kasten selbst. Kleiner wird er davon nicht — `inset` verschiebt nur,
     WO gemalt wird, nicht die Geometrie.

     ⛔ DER PREIS: Ein inset-Schatten liegt über der Fläche, aber UNTER den
     Kindern. Wo ein Kind mit eigener Füllung randlos bis an die Kante
     reicht, ist die Linie dort verdeckt. An allen 23 Lesern dieser Rolle
     nachgemessen (21 Routen, Kante für Kante über ihre ganze Länge);
     betroffen sind fünf, und immer ist es dasselbe Muster — ein klebender
     Kopf, ein klebender Fuß oder eine randlose Bildfläche:

       .filter-sidebar    ⛔ BEHOBEN AM 23.09.2026 — hier stand „Oberkante
                          ganz (der klebende .fs-kopf), dazu 58px der
                          Seitenkanten; auf /drucker zusätzlich unten".
                          Die Spalte polstert jetzt 1px ringsum und hält die
                          Linie damit frei, genau wie .tabelle-rahmen
                          (css/seiten.css, .filter-sidebar). Der Preis
                          darunter gilt also nur noch für die vier übrigen.
       .kopfsuche-blatt   Oberkante (der erste Gruppenkopf)
       .tabelle-rahmen    Oberkante (der klebende Tabellenkopf); in der
                          Angebotstabelle der Detailseite auch die Seiten,
                          weil dort die Zellen eigene Flächen tragen
       .wb-flaeche        alle vier Kanten (Video bzw. Foto füllen sie ganz)
       .dd-gruppe         Oberkante — sie rutscht unter den 2px-Balken

     ⚠️ Es geht dabei NICHTS an Aussage verloren: Jede dieser Stellen trägt
     an derselben Kante etwas anderes Sichtbares (Kopfzeile, Balken, Bild).
     Wer eine davon doch umrandet haben will, gibt IHR eine eigene Kante —
     und dreht nicht dieses Token zurück, sonst steht der Überstand überall
     wieder da.

     ⚠️ Es wird auch etwas SICHTBAR: `.wr-karte` und `.wg-zeile` auf /wissen
     hatten gar keine Linie, weil ein Vorfahre mit `overflow: hidden` den
     äußeren Schatten abschnitt. Nach innen gemalt wird er nicht mehr
     beschnitten.

     ⚠️ Wo ein Element einen eigenen Rahmen trägt, rückt die Linie um dessen
     Breite weiter nach innen — inset bezieht sich auf den Polsterkasten.
     Betrifft `.filament-kachel` (2px durchsichtiger Rahmen für die
     Vergleichsauswahl): Die Linie steht 2px innerhalb der Kartenkante, die
     äußeren 2px zeigen die Kartenfläche. Am Bildschirmabzug nachgesehen und
     nicht zu erkennen — die Fläche trägt gegen die Seite nur 1,10:1.

     ⚠️ Die Haarlinie ist eine ECHTE Farbe (--outline-variant), kein
     schwaches Schwarz mit Deckkraft. Ein Versuch mit rgba(20,24,33,0.09)
     maß 1,20:1 — genauso schwach wie die Fläche, die er retten sollte. Als
     Volltonfarbe folgt sie derselben Rolle wie jede andere Trennlinie der
     Seite und ändert sich mit ihr. */
  --karten-kante:
    inset 0 0 0 1px var(--outline-variant);

  /* Eingabefelder tragen dieselbe Haarlinie: Ein Feld liegt IN einer Karte,
     es schwebt nicht über ihr. Ein Feld ohne erkennbare Kante ist ein
     dunkler Fleck.

     ⚠️ Es gibt eine Ausnahme, und sie steht nicht hier: `.suchfeld` steht
     als einziges Eingabefeld FREI auf der Seitenfläche statt in einer Karte
     und bekommt deshalb einen eigenen Ring in --outline (css/komponenten.css).
     Die Haarlinie trüge dort zu wenig. */
  --feld-kante: 0 0 0 1px var(--outline-variant);

  /* --- Zustandsebene für Hover und Aktiv (11.08.2026) ------------------

     ⛔ HOVER IST KEINE FLÄCHENSTUFE MEHR. Bis hierher ging jedes
     Bedienelement beim Überfahren auf --surface-container-high und beim
     Drücken auf --highest. Das konnte aus zwei Gründen nicht funktionieren,
     und beide sind gemessen:

     1. --surface-container-high IST die Fläche der Kopfleiste. Burger,
        Symbolknopf, Kategorielink, Druckerknopf und die Einträge der
        Hauptleiste liegen also auf genau der Farbe, auf die ihr Hover
        wechselte: 1,00:1. Eine Namenskollision — ein Token hieß „gehobene
        Fläche" und „Hover-Zustand" zugleich, und in der Kopfleiste fielen
        beide zusammen.
     2. Nahe an einem Ende der Rampe ist ohnehin kein Platz für zwei weitere
        Stufen (siehe Rampe oben).

     Die Ebene löst beides auf einmal, weil sie nicht sagt „nimm Farbe X",
     sondern „erhelle, was da ist". Gemessen als dL* gegen den jeweiligen
     Untergrund:

                Karte   Kopfleiste   Seite   Schiene
       hover      7,8        7,0       8,1      6,4
       aktiv     11,5       10,6      12,4      9,8

     Hover -> Aktiv liegen überall 3,4–4,3 L*-Punkte auseinander, sind also
     auch VONEINANDER unterscheidbar — das war vorher der zweite tote Punkt.

     ⚠️ Die Deckkraft ist bewusst dieselbe wie bei .knopf::after (8 % / 12 %).
     Der gefüllte Knopf trägt dieses Muster seit jeher, weil seine Fläche die
     Markenfarbe ist und es dort „eine Stufe höher" nicht gibt. Genau
     derselbe Satz gilt für jedes Element auf einer Fläche, die schon oben
     steht — der Knopf war nicht der Sonderfall, er war der erste Fall.

     ⚠️ Als rgba() ausgeschrieben und NICHT als color-mix(--on-surface):
     color-mix scheitert in älteren Browsern still, und eine verworfene
     background-Deklaration heißt hier „gar keine Rückmeldung" — also
     ausgerechnet der Zustand, der behoben werden sollte. Die Werte sind die
     von --on-surface des jeweiligen Schemas (#171A20 bzw. #E3E6EA); wer eine
     der beiden ändert, zieht sie hier nach.

     ⚠️ ZWEI ANWENDUNGSARTEN, und die Verwechslung ist ein stiller Fehler:
     Elemente OHNE eigene Fläche (Chip, Burger, Menüeintrag) setzen die Ebene
     schlicht als `background` — darunter liegt die Fläche des Elternteils,
     und genau die soll durchscheinen. Elemente MIT eigener Fläche (Kachel,
     Ordner- und Materialkachel) dürfen das nicht: `background` ersetzte ihre
     Füllung, und die Seite schiene durch die Kachel hindurch. Sie legen die
     Ebene als `background-image: linear-gradient(...)` ÜBER ihre
     `background-color`. */
  /* ⚠️ Die Werte sind die von --on-surface (#E3E6EA). Wer diese Rolle
     ändert, zieht die beiden hier nach — sie sind ihre durchscheinende
     Fassung und keine eigene Farbe. */
  --zustand-hover: rgba(227, 230, 234, 0.08);
  --zustand-aktiv: rgba(227, 230, 234, 0.12);

  /* --- Statusgrün (dokumentierte Ausnahme: M3 kennt keine Grün-Rolle) --- */
  --gruen-container: #1E4B2E;      /* GruenContainerDunkel */
  --gruen-inhalt: #A9E5B4;         /* GruenHell */
  /* Das Materialfeld der Gerätekarte (Bildvorlage „12c", 18.09.2026): sehr
     dunkle Füllung, die Kante trägt die Abgrenzung — dieselbe Bauart wie bei
     den Karten der Seite. Ein Feld auf --gruen-container wäre eine
     Ampelfläche; hier geht es um EIN hervorgehobenes Feld, nicht um einen
     Zustand. */
  --gruen-feld: #101A13;
  --gruen-kante: #23402E;

  /* --- Ampelskala der Kennwert-Balken --- */
  /* ⛔ DAS TOKEN TRÄGT NICHT NUR BALKEN, SONDERN AUCH TEXT: die
     Überschriften und Hakenzeilen der Bandbreiten-Aufschlüsselung im
     Gerätedatenblatt (.dd-gruppe--ja h3, .dd-punkte .dr-punkt--ja) stehen
     ohne Kartenfläche direkt auf dem Seitengrund. Für sie gelten 4,5:1,
     nicht die 3:1 einer Grafik. Gemessen: 7,99:1 auf der Seite, 7,29:1 auf
     der Karte.

     ⚠️ Die helle Fassung dieser Rolle musste zwischen dem 08. und dem
     11.08.2026 ZWEIMAL nachgezogen werden, ohne dass jemand die Grünfarbe
     angefasst hätte — beide Male hatte eine Abtönung des Seitengrunds sie
     unter 4,5:1 gedrückt (4,92 -> 4,03, dann 4,65 -> 4,45). Die Farbe ist
     mit dem hellen Schema entfallen, die Lehre nicht: Wer den Seitengrund
     anfasst, misst diese Zeile zuerst. */
  --balken-gruen: #66BB6A;
  --balken-gelb: #FFD54F;
  --balken-rot: #EF5350;

  /* --- Sterne der positiven Kennwerte ---
     Gemessen 12,22:1 auf der Karte — als grafisches Objekt braucht der Stern
     3:1, er hat also reichlich Reserve.

     ⛔ MERKSATZ AUS DER HELLEN FASSUNG, der unabhängig vom Schema gilt:
     Sie war zu hell gewählt worden, weil gegen die KARTE gemessen wurde
     (3,44:1, sah gut aus). Die Sterne des Materialvergleichs stehen aber in
     `.vt-zelle`, und die hat gar keine eigene Fläche — sie sitzen also auf
     der SEITE, wo derselbe Ton nur 2,87:1 trug. Nicht gegen die Fläche
     messen, die man vermutet, sondern gegen die, auf der das Element
     tatsächlich liegt.

     Es bleibt ein EIGENES Token neben --balken-gelb (siehe dessen
     Begründung in komponenten.css): Sterne sind Auszeichnung, Balken tragen
     Bedeutung. Dass beide denselben Hexwert haben, ist Zufall. */
  --stern-gelb: #FFD54F;

  /* --- Kauf-Abschluss (Zum-Shop-Knopf der Kaufbox) ---
     Eigene Rolle statt --primary: Indigo trägt auf der Detailseite bereits den
     preisProKg, die Wortmarke, beide Nebenknöpfe und die Preise in „Weitere
     Shops". Der Schritt in den Shop ist der einzige, der die Seite verlässt —
     zwischen fünf indigofarbenen Elementen war er nicht mehr als solcher zu
     erkennen.
     Derselbe Grünton wie die Zeile „Lieferbar" zwei Zeilen darüber
     (--balken-gruen): Zusage und Abschluss sollen als EIN Signal gelesen
     werden, nicht als zwei verschiedene Grün.
     ⚠️ Auf dunklem Grund kehrt sich das Paar um: helle Fläche, dunkle
     Schrift — dasselbe Muster wie --primary/--on-primary. Weiß läge hier bei
     2,4:1 und wäre unlesbar. Geprüft: #062910 auf #66BB6A = 6,67:1, über AA
     (4,5:1) für die 14px-Beschriftung. */
  --kauf: #66BB6A;
  --on-kauf: #062910;

  /* Gedämpfte Fassung für ein nicht lieferbares Angebot. Sie zeigt auf die
     neutralen Flächenrollen statt eigene Werte zu führen und folgt ihnen
     dadurch von selbst. Geprüft: 7,9:1. */
  --kauf-aus: var(--surface-variant);
  --on-kauf-aus: var(--on-surface-variant);

  /* --- Warnstufen-Signalfarbe des Kachel-Warnsymbols ---
     Orange für „erhöhte Anforderungen". Bewusst von der Fehlerrolle getrennt;
     das Android-Theme kennt kein Orange (vgl. --ladekreis), daher eigener Wert.
     Die Hardware-Warnung nutzt weiterhin die Fehlerrolle --error.

     Sie trägt TEXT auf der Karte (.versand-zusatz--unbekannt,
     .chip-warn--erhoeht) und auf -high (.badge--eingeschraenkt,
     .badge--ungeprueft); gemessen 10,23:1 auf der Karte.

     ⚠️ Die helle Fassung dieser Rolle stand zeitweise bei 4,53:1 — formal
     über den 4,5, aber mit einer Reserve von 0,03, während eine einzige
     Abtönung der Flächen 0,20 Punkte kostete. Sie wäre also bei der nächsten
     Flächenänderung gekippt, ohne dass jemand die Warnfarbe angefasst hätte.
     Genau dafür gibt es den Reserve-Prüffall in tests/pruefung.html: Er
     meldet eine zu dünne Reserve, BEVOR sie zum Fehler wird. */
  --warnung-erhoeht: #FDBA74;

  /* --- Bausteine der Produktkachel (Bildvorlage, 23.09.2026) ---

     ⛔ BENANNT NACH DEM BAUSTEIN, NICHT NACH DER KACHEL. Preis, Fläche und
     Kante der Kachel bleiben bei --primary, --surface-container und
     --outline-variant: Ein anderes Blau für denselben Preis auf Kachel und
     Detailseite wäre schlimmer als eine Abweichung von der Vorlage. Diese
     Rollen tragen nur, was es AUSSERHALB der Kachel nicht gibt.

     Materialkennzeichen: gefüllte Pille, Weiß darauf 6,10:1. Nicht
     --primary-container — die Rolle trägt acht andere Stellen der Seite, und
     sie aufzuhellen färbte alle mit.

     Versandmarke: „Versandfrei" grün (8,99:1), der Aufschlag gelblich
     hinterlegt (10,19:1). ⛔ NUR „frei" IST GRÜN — der Aufschlag ist gelb,
     nicht grün, und „ohne Versandangabe" bleibt neutral grau
     (--on-surface-variant auf --surface-container-highest).

     ⛔ --knopf-kante ist das DUNKELSTE Grau, das 3:1 (WCAG 1.4.11) hält —
     und zwar auch auf der ÜBERFAHRENEN Kachel: --surface-container mit
     --zustand-hover darüber ergibt #282B31, dagegen 3,02:1; auf der ruhenden
     Karte 3,67:1. Die Vorlage setzt #4A505B (2,3:1). Wer die Karte oder die
     Hover-Ebene aufhellt, misst diese Zeile zuerst — ihre Reserve auf der
     überfahrenen Kachel ist null. */
  --kennzeichen-flaeche: #2F4DF0;
  --kennzeichen-tinte: #FFFFFF;
  --versand-frei-flaeche: #16241A;
  --versand-frei-tinte: #7FD39B;
  --versand-auf-flaeche: #2A2412;
  --versand-auf-tinte: #F2CF5B;
  --knopf-kante: #6E747F;

  /* --- Drucker-Illustration auf /wissen ---

     ⛔ DIESE VIER ROLLEN SIND DIE EINZIGEN HELLEN DER SEITE, und das ist
     Absicht. Das Bildfeld trägt eine technische Zeichnung auf hellem Grund —
     wie ein Foto, das auf einer dunklen Seite auch nicht dunkler wird. Eine
     helle Kontur auf hellem Feld wäre unsichtbar, also ist die Kontur dunkel,
     obwohl ringsum alles andere hell auf dunkel steht.

     ⚠️ Sie sind der Grund, warum die Umstellung auf ein einziges Schema am
     03.09.2026 hier NICHTS zu tun hatte: Die vier standen schon vorher in
     beiden Blöcken WERTGLEICH — ausgeschrieben und nicht weggelassen, damit
     niemand sie „nachzieht". Wer sie an die übrigen Flächenrollen angleicht,
     macht die Zeichnung unlesbar, ohne dass etwas meldet.

     Kontur auf Feld: 15,3:1. Marke auf Feld 5,4:1, Tinte auf Marke 6,3:1 —
     beide über den 4,5:1 für Text und den 3:1 für ein grafisches Objekt. */
  --schema-feld: #ECEEF2;
  --schema-kontur: #14181F;
  --schema-marke: #2B50E0;
  --schema-marke-tinte: #FFFFFF;

  /* Die Marken des interaktiven Modells auf /wissen. Sie liegen AUF dem
     hellen Blatt und sind deshalb schemaunabhängig wie die vier
     --schema-*-Rollen darüber: Das Blatt ist eine technische Zeichnung und
     bleibt hell, gleich in welchem Schema die Seite steht. */
  --wm-marke-feld: rgba(89, 128, 166, 0.06);
  --wm-marke-feld-aktiv: rgba(89, 128, 166, 0.20);
  --wm-lupe-glas: rgba(232, 240, 247, 0.92);
  --wm-lupe-stiel: linear-gradient(180deg, #c7ccd1, #7b8188);

  /* --- Das Blatt der Explosionszeichnung auf /wissen ---
     Dieselbe Sache wie das Bildfeld darüber und aus demselben Grund hell: Die
     Zeichnung des Druckkopfs ist ein technisches Blatt, das im Dunkeln nicht
     dunkler wird. Sie bringt ihren Verlauf aus der Vorlage mit; er steht als
     GANZER Wert hier und nicht in css/seiten.css, weil dort keine
     Farbliterale stehen dürfen — ein Prüffall hält das fest.
     ⛔ Wer diese beiden an die Flächenrollen angleicht, macht die Zeichnung
     unlesbar: Ihre 229 Kästen tragen ihre eigenen hellen Farben und lassen
     sich nicht mitdrehen. Tinte auf dem hellsten Punkt des Verlaufs: 15,6:1. */
  --wx-blatt-grund: linear-gradient(180deg, #F6F6F7 0%, #ECEDED 60%, #E6E7E8 100%);
  --wx-blatt-tinte: #1D1F20;

  /* --- Hotend-Rampe auf /wissen ---
     Fünf Stufen von kalt nach heiß: kühles Blaugrau oben, warmes Braun unten.
     Die Farbtemperatur trägt die Aussage, die Textfarbe trägt die Lesbarkeit
     — deshalb zwei Tinten und nicht fünf. Gemessen auf allen fünf Flächen:
     kühl 9,1–10,3:1, warm 7,8–9,5:1. */
  --hotend-1: #232B38;
  --hotend-2: #2B3443;
  --hotend-3: #3A2517;
  --hotend-4: #452B18;
  --hotend-5: #4F3018;
  --hotend-tinte-kuehl: #D3DCEA;
  --hotend-tinte-warm: #F2CBA0;

  /* --- Schichtschnitt des Resin-Druckers auf /wissen ---
     Sechs Schichten von der Bauplatte bis zum LED-Feld. Eine Tinte für alle:
     Die Flächen sind so gewählt, dass sie durchgehend über 4,5:1 trägt
     (gemessen 8,5–11,7:1). */
  --resin-schicht-1: #39414F;
  --resin-schicht-2: #23324F;
  --resin-schicht-3: #4A2440;
  --resin-schicht-4: #2A2F38;
  --resin-schicht-5: #1E2A4A;
  --resin-schicht-6: #3A2C5A;
  --resin-schicht-tinte: #E6EAF2;

  /* --- Ladeoverlay ---
     Der Kreisindikator ist laut
     Website-Vorgabe orangefarben; das Android-Theme definiert kein Orange
     (die App nutzt dort IndigoHell #818CF8), daher hier ein eigener Wert. */
  --ladekreis: #FB923C;
  --schleier: rgba(0, 0, 0, 0.4);

  /* --- Abstände ---
     Zwei Bereiche mit einer klaren Grenze dazwischen: bis 16px wird INNERHALB
     eines Abschnitts abgestuft, ab 24px werden Abschnitte VONEINANDER
     getrennt. Der Sprung von 16 auf 40 ist der eigentliche Zweck der Skala —
     das Auge erkennt Zusammengehörigkeit am Größenunterschied der Abstände,
     nicht an Linien. Wer zwischen zwei Abschnitten --abstand-l setzt, hebt
     die Gruppierung wieder auf.

     Die vier unteren Stufen stammen aus Abstand.kt (4-dp-Raster) und behalten
     ihre Werte; xxs, xl, 2xl und 3xl sind Website-Ergänzungen. */
  --abstand-xxs: 2px;  /* optische Korrektur (Symbol auf Grundlinie ziehen) */
  --abstand-xs: 4px;   /* extraKlein */
  --abstand-s: 8px;    /* klein */
  --abstand-m: 12px;   /* mittel */
  --abstand-l: 16px;   /* gross — Obergrenze INNERHALB eines Abschnitts */
  --abstand-xl: 24px;  /* Innenraum von Karten und Sheets */
  --abstand-2xl: 40px; /* zwischen Abschnitten */
  --abstand-3xl: 64px; /* zwischen großen Blöcken, Leerzustände */
  /* ⚠️ Am 02.09.2026 ergänzt. Die Vorlagen setzen zwischen den großen
     Bahnen der Startseite und über dem Kopfbereich deutlich mehr Luft, als
     die Skala bis dahin hergab; mit --abstand-3xl als Obergrenze standen
     „zwischen Abschnitten" und „zwischen Bahnen" auf demselben Wert und die
     Gliederung ging verloren. 96 setzt den Sprung von 64 fort (Faktor 1,5). */
  --abstand-4xl: 96px; /* zwischen ganzen Bahnen einer Seite */

  /* --- Gerüstmaße ---
     Kopfhöhe = 2 × --abstand-s Innenabstand + 40px Symbolknopf. Sie stand
     vorher dreimal als „56px“/„72px“ im Quelltext; jede Änderung an der
     Kopfzeile musste an allen Stellen nachgezogen werden. Sticky-Versätze
     rechnen jetzt mit diesem Wert statt mit einer Zahl.

     ⚠️ Der Wert hier ist nur der STARTWERT für die erste Bildfolge. Die
     Kopfleiste ist je nach Breite ein- oder zweizeilig und wird beim Scrollen
     kompakter — eine feste Zahl kann das nicht abbilden. js/app.js misst die
     Leiste und schreibt --kopf-hoehe am <html> auf die wirkliche Höhe fort.
     Genau daran hing ein stiller Fehler: Nach der Einführung der zweiten
     Zeile war die Leiste rund 112px hoch, hier standen weiter 56px — die
     haftende Filterleiste und die Seitenspalte der Detailseite rutschten
     dadurch unter die Kopfleiste. */
  --kopf-hoehe: 56px;
  /* ⚠️ 0, seit die untere Leiste des Handys entfallen ist (06.08.2026 — ihre
     Ziele stehen in der rechten Hauptleiste). Der Token bleibt stehen, weil
     Snackbar, Vergleichsleiste und Fußbereich ihre Abstände daraus rechnen:
     Mit dem Token auf 0 stimmen alle drei Formeln weiter, ohne dass jede
     Stelle einzeln umgebaut werden muss — und käme je wieder eine feste
     Leiste an den unteren Rand, ist dies der eine Wert, der sie einpreist. */
  --nav-hoehe: 0px;

  /* --- Radien (M3-Standard-Formen, wie CardDefaults.shape) ---
     Zuordnung: Bedienelement = s, Fläche/Karte = m, Overlay/Sheet = l,
     Pille nur für runde Symbolknöpfe und Zählpillen. */
  --radius-s: 8px;     /* shapes.small */
  --radius-m: 12px;    /* shapes.medium — Kartenecke (KARTEN_ECKE in FilamentCard.kt) */
  --radius-l: 16px;    /* shapes.large */
  --radius-pille: 999px;

  /* --- Typografie ---
     GEWOLLTE ABWEICHUNG von Type.kt der App (siehe CLAUDE.md): Die
     M3-Standardskala vergibt dieselbe Größe mehrfach — title-medium,
     body-large und title-small/label-large/body-medium waren größengleich.
     Eine Zwischenüberschrift war damit exakt so groß wie der Fließtext
     daneben und unterschied sich nur im Gewicht; auf einer 1600px breiten
     Seite wirkt dadurch alles gleich wichtig.

     Die Leiter lautet jetzt 12 · 13 · 14 · 16 · 18 · 20 · 26 · 28 · 34 · 44.
     Textgrößen liegen eng beieinander (das ist richtig so), Überschriften
     weit auseinander: 16 → 20 → 26 → 34, also Sprünge von 1,25 bis 1,31.
     Die App bleibt bei ihrer Skala — Handy-Layout und Desktop haben
     verschiedene Anforderungen.

     ⛔ DREI FAMILIEN SEIT DEM 02.09.2026, und jede hat eine Aufgabe:

       --schrift        serifenlos   Fließtext, Bedienelemente, Marke
       --schrift-serif  Serif        Überschriften, Preise, Kennzahlen
       --schrift-mono   Monospace    technische Werte, Kicker, Badges

     Die Aufteilung stammt aus den Vorlagen und ist dort durchgehend: Was
     GEMESSEN ist — Temperaturen, Mengen, Preisbestandteile, Trefferzahlen,
     Zeitangaben — steht in Schreibmaschinenschrift; was BENANNT wird, steht
     serifenlos; was die Seite GLIEDERT, steht in Serif.

     ⛔ DIE WORTMARKE BLEIBT SERIFENLOS (--schrift). Das ist keine Nachlässig-
     keit: An ihr hängen --marke-tinte (0,766) und --marke-grundlinie (0,412)
     in layout.css, und diese beiden Zahlen sind Schriftmetriken von Segoe UI.
     Eine andere Familie an der Marke macht die Spulengröße und ihre Lage auf
     der Grundlinie still falsch — CLAUDE.md sagt dazu „wer die Schriftfamilie
     wechselt, misst neu". Die Vorlagen zeigen die Marke ebenfalls serifenlos.

     ⚠️ FETTDRUCK IST NICHT MEHR ALLEIN DEM PREIS VORBEHALTEN. Die alte Regel
     („Überschriften unterscheiden sich über GRÖSSE, nicht über Gewicht")
     stammt aus einer Zeit mit einer einzigen Familie — dort war Fettdruck
     das einzige verfügbare Signal und musste deshalb knapp gehalten werden.
     Jetzt trägt die Serifenschrift die Auszeichnung, und Überschriften stehen
     in ihr auf 600. Der Preis behält seine Sonderstellung über GRÖSSE UND
     FARBE (bis 44px in --primary), nicht mehr über das Alleinstellungsmerkmal
     Fettdruck.

     Die Schriftdateien liegen als woff2 unter /assets/fonts (Etappe 1 des
     Gestaltungswechsels). Es sind Variable Fonts mit voller Gewichtsachse —
     eine Datei je Familie, zusammen 89 KB. Eingebunden in css/basis.css.
     ⛔ KEINE Fremdquelle: Die CSP der Seite erlaubt `default-src 'self'`,
     und die Datenschutzerklärung sagt „keine Fremdabrufe" zu. Ein
     Google-Fonts-Verweis bräche beides zugleich. */
  --schrift: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --schrift-serif: "Source Serif 4", ui-serif, Georgia, "Times New Roman", serif;
  --schrift-mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, "SF Mono", monospace;
  /* 64px — H1 des Startseiten-Kopfbereichs. Einzige Stufe über 44; sie steht
     genau einmal auf der Seite und trägt dort die ganze Aussage. */
  --display-large: 4rem;
  --display-medium: 2.75rem;     /* 44px — preisProKg Detailseite */
  --headline-large: 2.125rem;    /* 34px — h1 Seitentitel */
  --headline-medium: 1.75rem;    /* 28px — preisProKg Kachel */
  --headline-small: 1.625rem;    /* 26px — h2 Abschnittsüberschrift */
  --title-large: 1.25rem;        /* 20px — h3 Zwischenüberschrift */
  --title-medium: 1.125rem;      /* 18px — Kartentitel, Gewicht 500 */
  --title-small: 1rem;           /* 16px — kleiner Titel, Gewicht 500 */
  --body-large: 1rem;            /* 16px — Fließtext */
  --body-medium: 0.875rem;       /* 14px — Nebentext */
  --body-small: 0.8125rem;       /* 13px — Meta, Fußnoten */
  --label-large: 0.875rem;       /* 14px — Knopf-/Chipbeschriftung, Gewicht 500 */
  --label-medium: 0.75rem;       /* 12px — Zähler, Gewicht 500 */
  --label-small: 0.75rem;        /* 12px — Untergrenze; 11px war zu klein */

  /* --- Zeilenhöhen ---
     Vorher galt pauschal 1.5 für alles, auch für den 44px-Preis (Zeilenkasten
     67px) und für 12px-Nebentext. Je größer die Schrift, desto enger die
     Zeile. */
  --zeile-eng: 1.15;    /* ab 26px */
  --zeile-normal: 1.35; /* Titel und UI-Text */
  --zeile-text: 1.6;    /* Fließtext */
  --lesebreite: 68ch;   /* Zeilenlänge für Fließtext (vorher 60/70/78ch) */

  /* --- Bewegungsdauer ---
     Zwei Stufen statt der bisherigen fünf Einzelwerte (120/180/200/220/250).
     Abschaltung über prefers-reduced-motion in basis.css. */
  --dauer-kurz: 120ms;   /* Zustandswechsel an Bedienelementen */
  --dauer-mittel: 200ms; /* Ein- und Ausblenden von Flächen */
  --dauer-lang: 640ms;   /* Explosion des Druckkopfs auf /wissen — ⚠️ NICHT
                            mehr der Zoom: Der läuft seit dem 07.09.2026 in
                            zwei Phasen und führt eigene Tokens
                            (--wm-zoom-dauer, --wm-fahrt-dauer) */

  /* --- Erhebung ---
     NUR für echte Überlagerungen (Klappmenü, Sheet, Snackbar,
     Vergleichsleiste). Karten und Kacheln tragen keinen Schatten mehr; sie
     heben sich über ihre Fläche ab. Ein Schatten ohne darunterliegenden
     Inhalt ist Dekoration. */
  --schatten-schwebend: 0 4px 16px rgba(0, 0, 0, 0.55);

  color-scheme: dark;
}

