/* PrintSupport — Seitengerüst (Chrome): Kopfzeile, Hauptnavigation, Inhaltsbereich,
   Seitenübergang, Testmodus-Banner und die zugehörigen responsiven Regeln.
   Reine Struktur/Rahmen — wiederverwendbare Bausteine liegen in komponenten.css,
   seitenspezifisches Layout in seiten.css. */

/* ---------- Kopfleiste ----------

   Eine ruhige Zeile in drei Gruppen statt zweier Zeilen mit elf Einträgen:

     Wortmarke │ Filament Resin Drucker ······ Mehr ♡ ⚖ │ Mein Drucker  Benutzer
     └ Marke ──┘└──── Hauptnavigation ────┘   └ Ziele ─┘ └─── Werkzeuge ────────┘

   Getrennt wird über ABSTAND, nicht über Rahmen: Die früheren umrandeten
   Pillen um Währung und Drucker gaben jedem Einzelteil eine Kante und ließen
   die Leiste als Ansammlung lesen. Ein Bedienelement ist hier am Zeigefinger
   erkennbar (Hover), nicht an einem Kästchen.

   Drei Stufen, ein Markup:
     < 640px  Kategorien in eigener Zeile, Ziele unten in der Leiste
     ≥ 640px  Kategorien in eigener Zeile, Ziele oben rechts
     ≥ 1024px alles in EINER Zeile */

.kopfzeile {
  position: sticky;
  top: 0;
  /* Über der Hauptleiste (45) — das Druckermenü fährt nach unten aus.
     Modale Overlays (60), Snackbar (70) und Ladeoverlay (80) bleiben darüber. */
  z-index: 50;
  /* Die senkrechte Luft steht hier statt in .kopfzeile-inhalt, weil sie seit
     dem Umbau vom 06.08.2026 ZWEI Zeilen betrifft: die Kopfzeile selbst und
     die Kategorieleiste darunter. Als Wert der inneren Zeile wäre sie für die
     Kategoriereihe daneben unerreichbar gewesen — sie sind Geschwister. */
  /* ---------- KEIN SCHRUMPFEN BEIM SCROLLEN MEHR (22.09.2026) ----------

     ⛔ Die Kopfleiste hat EINE Größe, und zwar die, die sie in Ruhe hatte.
     Entfallen sind damit: --kopf-fortschritt, --marke-skala, die beiden
     Endwerte --kopfzeile-gross/--kopfzeile-klein (und ihre Geschwister der
     Handy-Fassung), das @property --kopf-roll und der rAF-Schreiber in
     js/app.js, der den Rollstand hierher schrieb.

     ⚠️ --kopf-hoehe BLEIBT und wird weiterhin gemessen. Die Höhe ist jetzt
     je Fensterbreite konstant, aber nicht je Seite gleich (72 / 64 / zwei
     Zeilen), und an ihr hängen die klebenden Spalten. Was entfallen ist,
     ist das Modell dahinter (zwei gemessene Endlagen, linear geteilt) —
     es gibt nur noch eine Lage zu messen.

     ⚠️ --werkzeug-roll ist etwas ANDERES und unberührt: Die Werkzeugzeile
     der Listen schrumpft auf dem Handy weiterhin beim Rollen
     (css/seiten.css). Sie hing nur am selben Rollzähler, nie an dieser
     Variablen.

     ⛔ WER HIER WIEDER EINE SCHWELLE ODER EINEN FORTSCHRITT EINFÜHRT, holt
     zugleich das Höhenmodell zurück: Jede Größe der Leiste müsste dann
     wieder affin in derselben Zahl sein, sonst rechnet js/app.js an jedem
     Zwischenstand lautlos falsch. */
  /* ---------- Höhe der EINEN Zeile ----------

     Zwei feste Endwerte, dazwischen linear geteilt. Vorher stand hier eine
     zusammengesetzte Rechnung (Spulenmaß × Skala + zweimal Luft); mit dem
     Umbau auf eine Zeile (10.08.2026) trägt die Zeile aber nicht mehr nur die
     Marke, sondern auch den 44px hohen Burger — und der ist ihr Mindestmaß.

     ⛔ KEIN `max()` in dieser Rechnung. Das Maximum zweier linearer Funktionen
     ist stückweise linear, nicht linear: Sobald der Knick zwischen die beiden
     Endlagen fiele, wäre die Interpolation in js/app.js (modellHoehe teilt
     linear zwischen den gemessenen Endlagen) falsch — und zwar lautlos, mit
     einem um mehrere Pixel danebenliegenden --kopf-hoehe. Zwei feste Endwerte
     sind per Bauart linear und lassen sich so wählen, dass der Burger in JEDER
     Lage hineinpaßt (siehe die Werte je Fensterbreite weiter unten). */
  /* ⛔ 72/60 STATT 96/60 (03.09.2026) — UND DIE KOMPAKTE LAGE IST BEWUSST
     STEHENGEBLIEBEN. Die schlanke Leiste spart ihre 24px in der RUHELAGE; das
     kompakte Ende bleibt, wo es war, weil dort etwas anderes den Ausschlag
     gibt als der Geschmack: Die Kategoriegrafik ist 57,19px hoch (sie behält
     ihre sichtbare Größe, siehe „Kategoriegrafik"), und `.kopfzeile-inhalt`
     trägt seit dem 10.08.2026 KEIN `overflow: clip` mehr — was nicht in die
     Zeile paßt, ragt sichtbar über ihre Unterkante hinaus. 60px lassen der
     Grafik 1,4px auf jeder Seite; jeder kleinere Wert ließe sie unten
     herausstehen, und zwar erst nach 120px Rollweg, also lange nachdem man
     hingesehen hat.
     Wer die kompakte Lage doch senken will, verkleinert vorher die Grafik —
     nicht umgekehrt. */
  --kopfzeile-hoehe: 72px;
  /* ---------- Bild- und Wortmarke (07.09.2026) ----------

     Links die Bildmarke, rechts die Wortmarke, BEIDE GLEICH HOCH. Eine Zahl
     bestimmt das: --marke-hoehe. Die Breiten folgen über das Seitenverhältnis
     der viewBox (`width: auto` am SVG) — sie stehen nirgends als Zahl und
     können deshalb auch nicht auseinanderlaufen.

     ⛔ WAS HIER GESTANDEN HAT UND ERSATZLOS ENTFALLEN IST:

       --marke-tinte, --marke-grundlinie   Schriftmetriken von Segoe UI
       --marke-spule, --spulen-groesse     Spulendurchmesser aus der Schrift
       --marke-spulen-versatz              Unterkante auf die Grundlinie
       --spulen-bild, --spulen-ueberhang   Füllausgleich der PNG-Datei
       --marke-schrift                     Schriftgröße des Schriftzugs

     Die ersten drei Gruppen rechneten die Spule aus der Texthöhe des
     Schriftzugs und setzten ihre Unterkante auf dessen Grundlinie. Beides
     hat keinen Gegenstand mehr: Die Wortmarke ist kein Text, sie hat keine
     Grundlinie und keine Tinte, und die neuen Dateien tragen KEINEN
     transparenten Rand (gemessen: viewBox = Inhalt, alle vier Ränder 0,000).
     Der Füllausgleich rechnete gegen einen Rand, den es nicht gibt.

     ⚠️ --marke-schrift ist mit dem Schriftzug gegangen. Es setzte die
     font-size der Wortmarke; ein SVG hat keine.

     ⛔ 20px, auf Ansage vom 07.09.2026. Die Wortmarke ist mit 6,109:1 sehr
     breit — bei H misst die Marke insgesamt H · 6,827 + Lücke. Gemessen:

       H = 20px  →  Bildmarke 14,4 · Wortmarke 122,2 · Marke 148,5px
       H = 22,9  →  (die alte Spulenhöhe)                       168,2px

     20px hält die Marke damit fast genau auf ihrer bisherigen Breite
     (143,9px, als der Schriftzug noch der kürzere alte Name war; 187,0px mit
     dem heutigen Namen als Text) und
     gibt dem Suchfeld daneben seinen Platz zurück. Wer sie vergrößert, misst
     das Suchfeld bei 1024px nach — dort ist die Zeile am engsten.

     ⚠️ EINE Höhe für alle Breiten. Der Schriftzug ging früher je Fenster
     eine Stufe zurück, weil er neben den Kategorien Platz brauchte; die
     Marke ist jetzt schmal genug, daß das entfällt.

     ⚠️ Sie ist das VERSALBAND der Wortmarke — deren Kasten ist höher
     (--marke-wort-hoehe), das Symbol daneben ist es ebenfalls
     (--marke-bild-hoehe). Sie ist das Maß, an dem beide hängen. */
  --marke-hoehe: 20px;

  /* ---------- Das SYMBOL ist größer als das Versalband (23.09.2026) ----

     ⛔ BIS ZUM 23.09.2026 WAR ES GENAU SO HOCH WIE DAS VERSALBAND, und mit
     dem neuen, fast quadratischen Symbol (viewBox 41 × 42 statt der alten
     hochformatigen 91,12 × 126,88) sah das falsch aus: Gleich hoch heißt
     bei einer quadratischen Zeichnung auch gleich breit, und daneben steht
     ein Schriftzug von 195 Einheiten Länge. Das Symbol verschwand.

     Maßgeblich ist die Vorlage vom 23.09.2026. Aus ihr abgemessen
     (Bildpunkte, Symbol gegen das „P“ von Print):

       Symbol      y 46 … 110   Höhe 65
       Versalband  y 54 …  98   Höhe 45      →  65 / 45 = 1,444

     ⛔ ALS FAKTOR UND NICHT ALS ZWEITE PIXELZAHL. Das Verhältnis ist die
     Eigenschaft der Vorlage; die Größe steckt allein in --marke-hoehe. Als
     eigene Zahl notiert bliebe das Symbol stehen, sobald jemand den
     Schriftzug ändert — und ein Symbol, das nicht mitwächst, fällt erst
     auf, wenn man beide nebeneinander sieht.

     ⚠️ AUSGERICHTET WIRD ÜBER DIE MITTE, nicht über die Grundlinie. Das
     Symbol ragt damit 4,4px über das Versal und 4,4px darunter; in der
     Vorlage sind es 8 und 12 Bildpunkte, also 3,6 und 5,3px — der
     Unterschied liegt unter einem Bildpunkt der Vorlage und ist die
     Messgenauigkeit, keine Aussage. Eine eigene Verschiebung wäre eine
     dritte Zahl, die niemand nachrechnet.

     ⚠️ Die Breite folgt über das Seitenverhältnis (width: auto): 29 ×
     41/42 = 28,3px. Die Marke wird dadurch rund 9px breiter — gemessen,
     und das Suchfeld bei 1024px trägt es. */
  --marke-bild-hoehe: calc(var(--marke-hoehe) * 1.444);

  /* ⛔ --marke-skala IST ENTFALLEN (22.09.2026). Sie skalierte die ganze
     Marke beim Rollen auf 0,75; mit dem Schrumpfen der Leiste ist sie
     gegenstandslos. Die Marke hat eine Größe. */

  /* ---------- Die WORTMARKE ist höher als ihr Kasten (22.09.2026) -------

     ⛔ BEIDE TEILE GLEICH HOCH ZU SETZEN WAR OPTISCH FALSCH. Die viewBox
     der Wortmarke (194,75 × 31,88) ist ihr Tintenkasten und trägt die
     Unterlängen von „p“ und „pp“ mit; die Bildmarke dagegen füllt ihre
     viewBox ganz. Auf dieselbe Kastenhöhe gestellt wirkt der Schriftzug
     deshalb kleiner als das Symbol daneben — und zwar um genau die
     Unterlänge.

     Maßgeblich ist das VERSALBAND, also Oberkante der Großbuchstaben bis
     Grundlinie. Aus den Pfaddaten in index.html abgelesen:

       Oberkante   y = 0,25   (das „S“ von Support, das höchste Versal;
                               der i-Punkt liegt bei 0,00)
       Grundlinie  y = 24,75  (Mittel der flachen Füße: P 24,50 · i 24,62 ·
                               n 24,62 · r 24,88)
       Versalband  24,50 von 31,88  =  0,7685 der viewBox

     Damit das Versalband --marke-hoehe misst, braucht die Wortmarke
     20 / 0,7685 = 26,0px Kastenhöhe. Die Breite folgt über das
     Seitenverhältnis (width: auto): 26 × 6,109 = 158,8px.

     ⚠️ --marke-wort-versatz ist die Folge davon und keine Kosmetik. Der
     26px-Kasten trägt 0,2px über dem Versal und 5,8px darunter; mittig
     zum Symbol ausgerichtet säße der Schriftzug deshalb 2,8px zu hoch.
     Der Versatz schiebt ihn um genau diese Hälfte der Unterlänge nach
     unten, sodass die Versalbänder beider Teile aufeinander liegen.
     Über `transform` und nicht über `margin`: Er ist eine optische
     Korrektur und soll die belegte Höhe der Zeile nicht verändern.

     ⛔ WER EINE DER BEIDEN SVG-DATEIEN AUSTAUSCHT, MISST DAS VERSALBAND
     NEU. Die 0,7685 stehen in keiner Datei, sie sind aus dieser einen
     Zeichnung abgelesen. */
  --marke-wort-hoehe: 26px;
  --marke-wort-versatz: 2.8px;

  /* ---------- Die Marke steht mittig vor den Kategorien (22.09.2026) ----

     Links vom Fensterrand, rechts vom Wort „Filament“ — beide Abstände
     sind dieselbe Zahl. Rechts setzt sie sich aus drei Teilen zusammen,
     und alle drei stehen zwischen Marke und Schrift:

       column-gap der Zeile          --abstand-m         12px
       margin-left von .kategorienav                     16px
       padding-left des Eintrags     --kategorie-polster 12px
       -----------------------------------------------------
                                                         40px

     ⛔ GEMESSEN WIRD ZUR SCHRIFT, nicht zum Linkkasten. Dessen Polster ist
     unsichtbar; mittig zu einer unsichtbaren Kante sähe um genau dieses
     Polster schief aus. Genau deshalb steht es als eigenes Token da
     (--kategorie-polster) — es ist unter 1024px eine Stufe kleiner, und
     der Rand der Reihe muss das mitrechnen, sonst wandert die Mitte.

     ⛔ 40px UND NICHT 64px, und das ist gerechnet: Vorher stand die Marke
     bei 16px links und hatte 64px bis zur Schrift. Die Summe (80px) ist
     der Platz, den die Zeile für diesen Bereich hergibt — zentriert heißt
     also 40 und 40, nicht 64 und 64. Mit 64px wäre die Marke zwar ebenso
     mittig, die Zeile aber 48px breiter, und die bezahlt bei 1024px das
     Suchfeld: gemessen 84px statt 108px Feldbreite.

     ⚠️ Die Zahl steht deshalb ZWEIMAL, und das ist Absicht: hier als
     linker Innenabstand der Zeile, drüben als margin-left der
     Kategoriereihe (dort als Rest nach Lücke und Polster). Wer eine
     ändert, rechnet die andere nach; tests/pruefung.html stellt beide
     gegeneinander.

     ⚠️ Unter 768px gilt sie nicht: Dort haben die Kategorien eine eigene
     Zeile, und die Marke steht allein. Der Zweig setzt padding-inline
     selbst. */
  --marken-luft: 40px;

  /* Der waagerechte Innenabstand EINES Kategorieeintrags. Er steht hier
     und nicht allein in `.kategorie-ziel`, weil ihn zwei Regeln brauchen:
     der Eintrag selbst und der Rand der Reihe, der die Marke mittig hält
     (Rechnung oben). Unter 1024px eine Stufe kleiner. */
  --kategorie-polster: var(--abstand-m);

  /* ---------- Die Unterstreichung des aktiven Eintrags (22.09.2026) ----

     Sie steht hier und nicht allein in `.kategorie-ziel`, weil sie zwei
     Regeln betrifft — und die zweite ist die überraschende: die MARKE.

     ⛔ JEDER Eintrag trägt sie, nur meist durchsichtig (sonst sprängen die
     Einträge beim Wechsel um ihre Höhe). Sie liegt INNERHALB des
     Linkkastens, und `align-items: center` der Zeile zentriert den Kasten
     samt Kante. Damit sitzt die SCHRIFT darin um die halbe Kantenstärke zu
     hoch — und die Marke daneben, die keine Kante hat, um dieselbe halbe
     Kantenstärke zu tief. Gemessen bei 1400px: Tinte der Kategorien mittig
     bei 34,66px, Marke bei 36,00px.

     ⚠️ Es ist eine KOPPLUNG und keine gemessene Zahl: `.marke` bekommt
     denselben Wert als margin-bottom und rückt dadurch um exakt dieselbe
     Hälfte nach oben. Wer die Kante ändert, ändert beides zugleich; eine
     abgeschriebene Pixelzahl liefe beim ersten Umbau davon, und zwar
     lautlos — eine Marke, die einen Pixel zu tief steht, sieht nicht nach
     einem Fehler aus, sondern nach nichts.

     ⚠️ Es bleibt ein Rest von 0,34px aus der Schriftmetrik (die Tinte von
     „Filament" liegt nicht genau mittig in ihrer Zeilenbox). Er ist
     gemessen und stehengelassen: ein Drittel Pixel, und die einzige
     Alternative wäre eine Zahl je Schriftstufe, die niemand nachrechnet. */
  --kategorie-unterstrich: 2px;
  /* Die Kopfleiste läuft ÜBER den Streifen der Icon-Spalte hinweg bis an die
     Fensterkante: Das <body>-Padding hält nur den Inhalt von der Spalte frei,
     die Leiste selbst braucht die volle Breite — sonst wäre „mittig" die
     Mitte des Restplatzes statt der Seitenbreite, und der Burger könnte nie
     in der Flucht der Icon-Spalte stehen.

     ⚠️ BEIDE Seiten, seit das <body>-Padding beidseitig ist (08.08.2026).
     Mit nur `margin-right` begänne die Leiste 60px vom linken Fensterrand
     und endete an der rechten Kante — ihre Mitte läge damit 30px rechts der
     Fenstermitte, und die Wortmarke stünde genau dort. Das ist die
     Zusicherung „MITTIG STEHT DIE WORTMARKE" (siehe „Rollende Spule"), und
     sie hängt daran, dass diese Zeile dem Padding folgt. Nachgemessen bei
     1400, 800 und 500px. */
  margin-inline: calc(-1 * var(--leiste-schmal));
  /* ---------- Eigene Fläche (10.08.2026) ----------
     Vorher trug die Kopfzeile `--surface`, also exakt die Fläche der Seite —
     sie war nur an ihrer Unterkante zu erkennen. Jetzt steht sie eine
     Flächenstufe höher und ist als Leiste lesbar.

     ⚠️ `--surface-container-high`, NICHT `--surface-container`. Der Unterschied
     ist gemessen, nicht gewählt: Die Kartenstufe (`--surface-container`) trägt
     im HELLEN Schema 1,24:1 gegen die Seite — dieselbe Abhebung wie die
     Karten, also erkennbar. Im DUNKLEN kommt sie aber nur auf 1,10:1 und liegt
     damit unter der Schwelle von etwa 1,15:1, ab der eine Fläche ohne Rahmen
     überhaupt erst wahrnehmbar wird (CLAUDE.md, „Helles Farbschema"). Eine
     Leiste, die man nur in einem der beiden Schemata sieht, erfüllt die
     Anforderung nicht.

     Eine Stufe höher trägt in beiden:
       dunkel  #0F1115 (Seite) → #22262D (Leiste)
       hell    #E1E4EC (Seite) → #FFFFFF (Leiste)
     Deutlich, aber ohne eigene Farbigkeit — die Leiste bleibt eine Fläche der
     Seite und wird nicht zum Fremdkörper. */
  background: var(--surface-container-high);
  /* Die Kante bleibt und wird jetzt gebraucht wie nie: Der Inhalt scrollt
     unter der Leiste hindurch. Trennung über Abstand ist unmöglich — sie
     klebt. */
  border-bottom: 1px solid var(--outline-variant);
}

/* ---------- EINE ZEILE (seit 10.08.2026) ----------

   Marke links, Kategorien mittig, Druckerwähler und Burger rechts.

   ⚠️ Die Mitte der Kategorien ist die SEITENMITTE, nicht die Mitte des
   Restplatzes zwischen Marke und Werkzeugen. Deshalb liegen Marke,
   Druckerwähler und Burger ABSOLUT (aus dem Fluss genommen) und die
   Kategoriereihe ist das einzige Fluss-Kind — der Flex-Kasten zentriert damit
   sie und nichts anderes. Weder eine lange Wortmarke links noch ein langer
   Gerätename rechts können die Kategorien verschieben; das war schon in der
   früheren zweizeiligen Fassung die tragende Technik und gilt unverändert.

   ⚠️ Senkrecht wird über die Kastenhöhe zentriert (align-items der Zeile)
   und NICHT über `top: 50%; transform: translateY(-50%)`. Der Grund war bis
   zum 22.09.2026 das Schrumpfen an `.marke` — ein zweiter Transform hätte
   mit ihm in EINER Deklaration stehen müssen, und dann bezöge sich das
   Prozent-Translate auf die UNSKALIERTE Höhe. Mit dem Schrumpfen ist er
   entfallen; die Regel bleibt, weil sie jetzt eine andere trägt:
   `.marke-wort` hält ihren Versatz über `transform`. */
.kopfzeile-inhalt {
  position: relative;
  /* ⛔ ALLE VIER GRUPPEN STEHEN IM FLUSS (03.09.2026), und damit endet die
     Zusicherung „die Kategorien stehen auf der Seitenmitte".

     Sie war richtig, solange die Mitte frei war. Seit dort das Suchfeld steht
     (siehe .kopfsuche), gibt es nichts mehr zu zentrieren: Die Kategorien
     rücken nach links neben die Marke, die Suche nimmt den Platz bis zu den
     Werkzeugen. Marke, Druckerwähler und Burger lagen bis dahin ABSOLUT —
     einzig, um die Reihe in der Mitte freizustellen. Dieser Grund ist weg,
     also ist auch das Absolute weg; eine Zeile aus vier Fluss-Kindern
     verteilt sich von selbst und braucht keine gerechneten Ränder mehr.

     ⚠️ Die Marke schrumpft weiterhin per `transform: scale`, und ein Transform
     ändert die belegte BREITE nicht. Beim Rollen entsteht rechts von ihr
     deshalb Luft (gemessen bis 38px in der kompakten Lage). Das ist bewusst
     hingenommen: Die Alternative wäre eine mitschrumpfende Breite, also
     Layout in jedem Bild — genau die Rechnung, die der Umbau vom 07.08.2026
     abgeschafft hat. Sichtbar wird es als etwas mehr Abstand zu den
     Kategorien; die Kategorien selbst rücken dabei keinen Pixel, sie stehen
     also ruhig. */
  /* ⚠️ Die Zeilenhöhe steht als RECHNUNG da, nicht als Innenabstand um einen
     Inhalt, der selbst schrumpft. Sie ist die einzige Größe des Kopfes, die
     beim Scrollen noch Layout auslöst — und sie muss es, denn eine Leiste,
     die nicht kürzer wird, gibt keinen Platz frei.

     Der Spulendurchmesser ist das höchste Element der Zeile (64px gegen rund
     41px Zeilenkasten der Wortmarke) und steht als Token bereit; die Höhe
     lässt sich deshalb ohne Messung ausdrücken. Die Marke selbst schrumpft
     per transform und trägt zur Höhe nichts mehr bei — ohne diese Rechnung
     bliebe die Zeile hoch und unter dem verkleinerten Logo klaffte Luft.

     KEINE transition: Der Wert folgt dem Scrollen unmittelbar. Eine
     Übergangszeit liefe hier gegen ein Ziel, das sich in jedem Frame
     weiterbewegt — das Ergebnis ist Nachlauf, kein weicher Verlauf. */
  height: var(--kopfzeile-hoehe);
  /* ⚠️ RECHTS --burger-rechts, nicht --abstand-l: Der Burger ist das letzte
     Kind im Fluss, sein Abstand zur Fensterkante ist damit der Innenabstand
     dieser Zeile. Er steht weiterhin in der Flucht der Icon-Spalte — die
     Rechnung dazu steht unverändert bei --burger-rechts. */
  /* ⚠️ --marken-luft und nicht --abstand-l: Die Marke steht mittig
     zwischen Fensterrand und dem Wort „Filament“ (Rechnung oben). */
  padding-left: var(--marken-luft);
  padding-right: var(--burger-rechts);
  display: flex;
  align-items: center;
  /* ⛔ `column-gap`, NICHT `gap`. Unter 768px wird dieselbe Zeile zu einem
     Raster mit zwei Reihen; ein Kurzform-`gap` setzte dort auch die
     ZEILENlücke, und die addierte sich zu den beiden Zeilenhöhen. Gemessen
     113px statt der gerechneten 100 — und zwar lautlos, denn das Höhenmodell
     in js/app.js mißt die Endlagen und teilt linear, es merkt eine
     zusätzliche Konstante nicht. */
  column-gap: var(--abstand-m);
  /* ⛔ KEIN `overflow: clip` mehr. Bis zum 10.08.2026 stand es hier als Bühne
     des Ausrollens, weil die Spule nach RECHTS um 100vw wegrollte und ein
     Überhang nach rechts zum rollbaren Bereich zählt.
     Seit dem Umbau auf eine Zeile rollt sie nach LINKS aus (siehe „Rollende
     Spule"), und ein Überhang nach links erzeugt keinen Rollbalken — der
     Zuschnitt wird also nicht mehr gebraucht. Er wäre jetzt sogar schädlich:
     In dieser Zeile hängt das Druckermenü, und `clip` schnitte es an der
     Unterkante der Leiste ab. */
}

/* Seit der Umstellung auf echte Pfade ist die Wortmarke ein <a>, kein
   <button> — text-decoration und Farbe müssen deshalb zurückgesetzt werden,
   die Button-Rücksetzer bleiben für ältere Abzüge unschädlich stehen. */
.marke {
  /* ⚠️ IM FLUSS seit dem 03.09.2026. Sie lag absolut, damit die Kategorien
     daneben auf der Seitenmitte stehen konnten; diese Zusicherung ist mit dem
     Suchfeld in der Mitte gefallen (Begründung oben bei .kopfzeile-inhalt).
     Als erstes Fluss-Kind steht sie von selbst links und braucht weder
     `left` noch die senkrechte Spannung — align-items der Zeile zentriert
     sie, und der Transform bleibt für die Skalierung frei. */
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  /* ⛔ HIER STAND DAS SCHRUMPFEN (`transform: scale(var(--marke-skala))`
     samt `transform-origin: left center`) und ist am 22.09.2026 entfallen.
     Die Marke hat eine Größe; es gibt nichts mehr zu skalieren. Mit ihm
     ist auch die Luft weg, die der Transform rechts von der Marke stehen
     ließ (er ändert die belegte Breite nicht) — die Zeile ist damit an
     dieser Stelle wieder so breit, wie sie aussieht. */
  gap: var(--abstand-m);
  /* ⛔ AUF HÖHE DER KATEGORIEN (22.09.2026), und zwar über eine Kopplung
     statt über eine gemessene Zahl: Die Einträge tragen ihre
     Unterstreichung INNERHALB des Linkkastens, die Zeile zentriert den
     Kasten samt Kante, und die Schrift darin sitzt deshalb um die halbe
     Kantenstärke höher als die Mitte der Zeile. Derselbe Wert als unterer
     Rand hier hebt die Marke um genau diese Hälfte — der Rand zählt bei
     `align-items: center` mit.
     ⚠️ Unter 768px steht das Token auf 0: Dort hat der aktive Eintrag
     keine Unterstreichung, sondern eine gefüllte Pille, und die Marke
     steht ohnehin allein in ihrer Zeile. */
  margin-bottom: var(--kategorie-unterstrich);
  background: none;
  border: 0;
  /* Waagerecht KEIN Innenabstand: Sonst begänne die Wortmarke 4px weiter
     rechts als der Inhalt darunter, der bei --abstand-l ansetzt. Genau
     solche 4px sind es, die eine Seite unaufgeräumt wirken lassen.
     Senkrecht bleibt der Abstand als Trefferfläche. */
  padding: var(--abstand-xs) 0;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}

/* ---------- Bildmarke und Wortmarke ----------

   ⛔ HIER STAND DIE ROLLENDE SPULE, UND SIE IST ERSATZLOS ENTFALLEN
   (07.09.2026). Mit ihr: .marke-buehne, .marke-spule, der Füllausgleich,
   @keyframes pd-spule-rollen (32,5 s Zyklus: andocken → 30 s stehen → nach
   links hinausrollen → zurück) und die prefers-reduced-motion-Regel dazu.
   Die Marke bewegt sich nicht mehr von selbst.

   ⚠️ Die Rollleiste der Seite (js/rollspule.js) ist etwas ANDERES und
   unberührt. Sie zeichnet ihre Spule als eigenes Inline-SVG und hat die
   Logodatei nie gelesen. Sie führt damit als einzige das Spulenmotiv weiter;
   das ist gesehen und auf Ansage vom 07.09.2026 so gelassen.

   ⛔ BEIDE TEILE SIND GLEICH HOCH, und zwar über EINE Zahl (--marke-hoehe).
   Die Breite steht nirgends: `width: auto` läßt sie der Browser aus der
   viewBox rechnen. Zwei Maße, die zusammenpassen MÜSSEN, gibt es hier also
   nicht mehr — genau die Handarbeit, die den Spulenumbau vom 11.08.2026
   nötig gemacht hat.

   ⚠️ Maßgeblich ist die SICHTBARE Höhe. Das ist hier dasselbe wie die
   viewBox: Beide Dateien tragen keinen transparenten Rand (per getBBox
   gemessen, alle vier Ränder 0,000). Käme je eine Datei mit Rand, wäre der
   Füllausgleich wieder fällig — die Rechnung steht in der Historie.

   ⛔ DIE DUNKLE HÄLFTE NIMMT `currentColor`, die helle --marke-akzent (beides
   als fill im <symbol>, index.html). Deshalb steht hier KEINE Farbe: `.marke`
   erbt die Schriftfarbe ihrer Umgebung (color: inherit, oben), und das SVG
   folgt ihr. Auf der dunklen Seite wird die Marke damit hell, im Druckblock
   von css/basis.css dunkel — ohne eine einzige Fallunterscheidung.

   ⚠️ Das wirkt NUR, weil die Zeichnungen inline stehen. In einem <img> ist
   die SVG ein eigenes Dokument und sieht weder currentColor noch die Custom
   Properties dieser Seite; sie trüge dann ihr eingebautes #001736, und das
   mißt auf dieser Leiste 1,18:1. */
.marke-bild,
.marke-wort {
  display: block;
  flex: 0 0 auto;
  /* ⛔ `auto`, nicht 100%: Die Breite kommt aus dem Seitenverhältnis der
     viewBox. Mit einer Prozentangabe zöge sich das SVG über die Restbreite
     der Marke, und das Motiv stünde verloren in einem zu breiten Kasten. */
  width: auto;
}

/* ⛔ DREI HÖHEN, EIN MASS. --marke-hoehe ist das Versalband des Schriftzugs;
   die Wortmarke braucht darüber hinaus ihre Unterlängen
   (--marke-wort-hoehe), das Symbol steht bewusst über dem Band
   (--marke-bild-hoehe). Beide Rechnungen stehen oben, beide hängen an
   derselben einen Zahl. */
.marke-bild { height: var(--marke-bild-hoehe); }
.marke-wort {
  height: var(--marke-wort-hoehe);
  /* Die halbe Unterlänge nach unten: So liegen die Versalbänder beider
     Teile aufeinander statt ihrer Kästen (Begründung oben). */
  transform: translateY(var(--marke-wort-versatz));
}

/* Der Vorrat zeichnet nichts — er hält nur die beiden <symbol>. Er darf
   NICHT `display: none` bekommen: Ein so ausgeblendetes SVG liefert in
   manchen Browsern keine Symbole mehr an <use>, und dann fehlt die Marke
   ganz, ohne daß irgendwo etwas meldet. Aus dem Fluss genommen wird er
   deshalb über die Lage. */
.marken-vorrat {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ⛔ DIE MARKE BEKOMMT KEINE AKTIV-MARKIERUNG MEHR (11.08.2026).
   Hier stand bis dahin ein 2px-Balken in --primary unter dem Schriftzug
   (`.marke[aria-current="page"] .marke-wort::after`), damit die Startseite
   einen Aufenthaltshinweis hat — sie hat seit dem Wegfall des Menüs „Mehr"
   keinen eigenen Leisteneintrag. Auf Entscheidung vom 11.08.2026 ist die
   Markierung entfallen: Das Logo ist der Weg zur Startseite, aber kein
   Navigationspunkt, der sich als „hier bist du" meldet.

   ⚠️ `aria-current="page"` BLEIBT an der Marke stehen (js/app.js setzt es
   über `[data-ziel]`). Entfernt ist nur die sichtbare Entsprechung. WCAG
   1.3.1 verlangt, dass sichtbar Vermitteltes auch programmatisch verfügbar
   ist — nicht die Umkehrung; eine Auszeichnung ohne sichtbares Gegenstück
   ist zulässig. Und sie ist hier das Einzige, was Vorlesehilfen auf „/"
   überhaupt noch sagen kann, denn die Marke ist der einzige Weg dorthin.
   Wer auch `aria-current` nehmen will, entfernt `data-ziel="start"` an
   index.html — dann trägt auf „/" gar kein Element mehr einen Hinweis.

   ⚠️ Die KATEGORIEN sind davon nicht berührt. Sie teilen sich mit der Marke
   nur die Setz-Funktion (`js/app.js`, über `[data-ziel]`), nicht die
   Darstellung: Ihre Markierung hängt an `.kategorie-ziel[aria-current]` und
   läuft über `border-bottom-color`, nicht über ein Pseudoelement.

   Gemessen nach dem Entfernen, an 10 Breiten (1920 · 1400 · 1280 · 1024 ·
   900 · 768 · 640 · 500 · 479 · 390): keine einzige Geometrie verschiebt
   sich — der Balken lag absolut und hat nie Platz belegt. `position:
   relative` an `.marke-wort` ist mit ihm entfallen; es war allein sein
   Bezugsrahmen, und die beiden Kinder (`.print`/`.deal`) setzen nur `color`.
   Die Spulenbühne ist ein GESCHWISTER, kein Nachfahre. */

/* ---------- Werkzeuge am rechten Rand ----------

   Druckerwähler und Burger stehen seit dem 10.08.2026 in DERSELBEN Zeile wie
   Marke und Kategorien; die frühere zweite Zeile (.bedienzeile) ist ersatzlos
   entfallen. Seit dem 03.09.2026 stehen beide IM FLUSS — das Absolute trug
   allein die Mittigkeit der Kategorien, und die ist mit dem Suchfeld in der
   Mitte gefallen (Begründung oben bei .kopfzeile-inhalt).

   ⚠️ Der Burger bleibt der äußere und behält seine Flucht mit der Icon-Spalte;
   getragen wird sie jetzt vom rechten Innenabstand der Zeile statt von einem
   gerechneten `right`. Die Lücke zwischen Wähler und Burger kommt aus dem
   `gap` der Zeile — eine Rechnung weniger. */
.kopfzeile-inhalt .druckerauswahl {
  /* `relative` und nicht `static`: Das Druckermenü fährt aus diesem Container
     aus (Grundregel .druckerauswahl weiter unten) und braucht ihn als
     Bezugsrahmen. */
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  min-width: 0;
}

/* Die Sicherung gegen einen sehr langen Gerätenamen: Der Wähler wächst nicht
   über sein Maß hinaus, die Kürzung landet im Namen (Ellipse). Vorher stand
   hier `calc(50% - 320px)` — die Grenze zur zentrierten Kategoriereihe. Die
   gibt es nicht mehr; was den Wähler heute begrenzen muss, ist das Suchfeld
   links von ihm, und dafür genügt ein fester Höchstwert.
   ⚠️ NUR ab 1024px, wo der Name überhaupt sichtbar ist. */
@media (min-width: 1024px) {
  .kopfzeile-inhalt .druckerauswahl { max-width: 260px; }
}

/* Das Druckermenü klappt RECHTSbündig unter seinem Knopf aus — der Wähler
   steht jetzt am rechten Zeilenrand, und die Grundregel der Menüs (right: 0)
   trifft damit von selbst zu. Die frühere Ausnahme (left: 0) galt dem Wähler
   am LINKEN Rand der alten Bedienzeile und ist mit ihm entfallen. */

/* ⚠️ Burger in der FLUCHT der Icon-Spalte (ab 640px, wo es sie gibt): Die
   Spalte ist 60px breit, ihre Symbole sitzen mittig — also 30px vor der
   Fensterkante. Der Burger ist 44px breit, seine Mitte liegt 22px vor
   seiner rechten Kante: 30 − 22 = 8px Abstand zur Fensterkante, und die
   Mitten stehen exakt übereinander. Der Wert ist GERECHNET, nicht gewürfelt —
   wer die Spaltenbreite (--leiste-schmal) oder die Burgergröße ändert,
   rechnet ihn nach.

   Als Token, weil ihn seit dem 10.08.2026 zwei Regeln brauchen: der Burger
   selbst und der Druckerwähler, der sich links davor einreiht. */
.kopfzeile { --burger-rechts: var(--abstand-l); }
@media (min-width: 640px) {
  .kopfzeile { --burger-rechts: calc((var(--leiste-schmal) - 44px) / 2); }
}

.kopfzeile-inhalt .burger {
  /* Im Fluss als letztes Kind; seinen Abstand zur Fensterkante trägt der
     rechte Innenabstand der Zeile (--burger-rechts). */
  flex: 0 0 auto;
}

/* ==================================================================
   DIE EINE SUCHE DER SEITE (03.09.2026)
   ==================================================================

   Sie steht zwischen Kategorien und Druckerwähler und nimmt den Platz, der
   dort frei wird. Bis dahin stand in jeder Liste ein eigenes Suchfeld in der
   Werkzeugzeile — zwei Felder, die je nur ihren eigenen Bestand fanden.

   ⚠️ `margin-left: auto` und nicht `justify-content: space-between`: Nur der
   Automatik-Rand schiebt AUSSCHLIESSLICH dieses eine Kind nach rechts. Über
   die Ausrichtung der Zeile bekämen auch Marke und Kategorien Luft
   dazwischen, und die beiden gehören zusammen.

   ⚠️ Die Obergrenze ist kein Geschmack, sondern eine Lesbarkeitsgrenze: Ein
   Suchfeld über 620px bietet Platz für Eingaben, die niemand tippt, und das
   Vorschlagsblatt darunter ist so breit wie das Feld — dort stünden Name und
   Wert dann mit einer halben Bildschirmbreite dazwischen. */
.kopfsuche {
  /* Bezugsrahmen des Blatts, das darunter schwebt. */
  position: relative;
  /* Damit die Container-Abfrage unten am FELD misst und nicht am Fenster: Ob
     der Feldhinweis noch passt, hängt an der Breite dieses Kastens — und die
     ist bei gleichem Fenster verschieden, je nachdem wie lang der Gerätename
     rechts daneben ist. */
  container-type: inline-size;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 620px;
  margin-left: auto;
}

.kopfsuche-form {
  display: flex;
  align-items: center;
  gap: var(--abstand-s);
  /* ⛔ FESTE 40px (22.09.2026). Sie schrumpfte mit der Leiste auf 34px
     über einen eigenen Anteil des Rollfortschritts; mit dem Schrumpfen der
     Leiste ist auch das entfallen. */
  height: 40px;
  padding-inline: var(--abstand-s) var(--abstand-m);
  background: var(--surface-container-lowest);
  /* ⛔ Eigene Kante in --outline, wie beim Suchfeld der Liste und aus
     demselben Grund: Als Fläche trägt das Feld gegen die Leiste nur rund
     1,2:1, und für ein Bedienelement fordert WCAG 1.4.11 3:1. Die Haarlinie
     (--outline-variant) reichte dafür nicht. */
  box-shadow: inset 0 0 0 1px var(--outline);
  border-radius: var(--radius-pille);
  min-width: 0;
}

/* Der Fokusring liegt AUF der Kante statt daneben: Ein zusätzlicher `outline`
   ringsum stieße bei 40px Höhe an die Kanten der Zeile. */
.kopfsuche-form:focus-within {
  box-shadow: inset 0 0 0 2px var(--primary);
}

.kopfsuche-knopf {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pille);
  background: none;
  color: var(--on-surface-variant);
  cursor: pointer;
}
.kopfsuche-knopf:hover { background: var(--zustand-hover); color: var(--on-surface); }
.kopfsuche-knopf svg { width: 18px; height: 18px; }

.kopfsuche-eingabe {
  flex: 1 1 auto;
  /* ⛔ `width: 0` UND `min-width: 0`. `min-width` nimmt dem Feld nur die
     automatische Untergrenze; seine min-content-BREITE bleibt die
     intrinsische Größe (Chrome rechnet mit rund 20 Zeichen). Dieselbe Falle
     wie beim Suchfeld der Startseite — dort waren es gemessen 169px, die die
     ganze Zeile aufdrückten. */
  width: 0;
  min-width: 0;
  background: none;
  border: 0;
  padding: 0;
  color: var(--on-surface);
  font-family: inherit;
  font-size: var(--body-medium);
}
.kopfsuche-eingabe:focus { outline: none; }
.kopfsuche-eingabe::placeholder { color: var(--on-surface-variant); }
/* Das Kreuz, das Chrome in type="search" einbaut: Es sitzt in der Pille auf
   der Kante und doppelt eine Geste, die Escape und die Löschtaste bereits
   erledigen. */
.kopfsuche-eingabe::-webkit-search-cancel-button { display: none; }

/* Der Hinweis rechts im Feld — Schreibmaschinenschrift wie jede technische
   Angabe der Seite, Versalien über text-transform (im Markup steht gemischter
   Text, sonst buchstabieren Vorlesehilfen ihn teilweise). */
/* ⚠️ GROTESK SEIT DEM 03.09.2026, vorher Monospace (auf Ansage). Der Hinweis
   steht zwar in der Kopfleiste und damit auf JEDER Route, gehört optisch aber
   zum oberen Seitenrand — und dort sollten nach der Umstellung des
   Kopfbereichs nicht drei Familien nebeneinander stehen. Er trägt jetzt
   dieselbe Schrift wie das Eingabefeld daneben; Versalien und Sperrung
   bleiben, sie sind es, die ihn als Hinweis und nicht als Eingabe lesbar
   machen.

   ⚠️ Die Monospace ist damit NICHT aus dem Projekt verschwunden: Sie
   kennzeichnet weiterhin technische Werte (Balkenwerte, Badges, Rollendaten,
   Näherungen, Angebotstabelle, Filter, die ganze Wissensseite).
   ⚠️ Die Vorschlagszeilen dieser Suche (.ks-gruppenkopf, .ks-wert) standen
   hier noch als Ausnahme und sind seit dem 22.09.2026 mitgezogen — die ganze
   Kopfleiste trägt jetzt EINE Familie. Begründung dort. */
.kopfsuche-felder {
  flex: 0 0 auto;
  font-family: var(--schrift);
  font-size: var(--label-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--on-surface-variant);
  white-space: nowrap;
}
/* Unter 420px Feldbreite bleibt für die Eingabe selbst zu wenig übrig — dann
   tritt der Hinweis zurück. Er ist eine Starthilfe, kein Etikett. */
@container (max-width: 420px) {
  .kopfsuche-felder { display: none; }
}

/* ---------- Das Vorschlagsblatt ----------

   Es schwebt unter dem Feld und ist so breit wie dieses. Vier Gruppen mit
   eigener Kopfzeile und Trefferzahl, darunter eine Abschlusszeile.

   ⚠️ z-index INNERHALB der Kopfleiste: Die Leiste selbst liegt auf 50 und
   damit über allem Inhalt; das Blatt braucht nur einen Wert über seinen
   Geschwistern. Modale Overlays (60) und die Snackbar (70) bleiben darüber. */
.kopfsuche-blatt {
  position: absolute;
  top: calc(100% + var(--abstand-s));
  left: 0;
  right: 0;
  z-index: 5;
  background: var(--surface-container-high);
  border-radius: var(--radius-l);
  box-shadow: var(--karten-kante), var(--schatten-schwebend);
  /* Ohne Zuschnitt stünde der Gruppenstreifen über die gerundete Ecke hinaus. */
  overflow: hidden auto;
  /* Bei vier vollen Gruppen wird das Blatt hoch; mehr als zwei Drittel der
     Fensterhöhe darf es nicht nehmen — darunter liegt die Seite, auf die es
     sich bezieht. */
  max-height: min(70vh, 560px);
}

/* ⚠️ GROTESK SEIT DEM 22.09.2026, vorher Monospace (auf Ansage) — aus
   demselben Grund wie beim Feldhinweis daneben: Das Blatt hängt an der
   Kopfleiste und gehört optisch zu ihr; die KATEGORIEREITER tragen die
   Grotesk (sie führen gar keine eigene Familie und erben sie vom Dokument),
   und drei Familien nebeneinander lösen die Leiste als Einheit auf.
   Versalien und Sperrung bleiben — sie sind es, die den Gruppenstreifen als
   Kopfzeile und nicht als Eintrag lesbar machen. */
.ks-gruppenkopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--abstand-m);
  margin: 0;
  padding: var(--abstand-s) var(--abstand-l);
  background: var(--surface-container-highest);
  font-family: var(--schrift);
  font-size: var(--label-small);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--on-surface-variant);
}
.ks-gruppenzahl { flex: 0 0 auto; }

.ks-eintrag {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--abstand-l);
  padding: var(--abstand-s) var(--abstand-l);
  text-decoration: none;
  color: inherit;
}
.ks-eintrag:hover,
.ks-eintrag--aktiv { background: var(--zustand-hover); }

.ks-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ks-name {
  font-size: var(--body-medium);
  font-weight: 500;
  color: var(--on-surface);
  /* Ein langer Produktname darf die Wertspalte nicht wegdrücken. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ks-unter {
  font-size: var(--label-medium);
  color: var(--on-surface-variant);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ⚠️ GROTESK SEIT DEM 22.09.2026, vorher Monospace (auf Ansage). Hier steht
   ein ABGELESENER Wert, und die Projektregel gäbe ihm die
   Schreibmaschinenschrift — die Kopfleiste als EINE Fläche wiegt an dieser
   Stelle schwerer: Das Blatt liegt unter dem Suchfeld, zwischen Feldhinweis
   und Kategoriereitern, und beide tragen die Grotesk.
   ⚠️ tabular-nums BLEIBT und trägt jetzt allein, was vorher die Monospace
   mitbrachte: Die Ziffern der untereinanderstehenden Zeilen stehen in einer
   Flucht. Wer sie entfernt, lässt die Preisspalte zittern.
   ⚠️ Die Monospace ist damit NICHT aus dem Projekt verschwunden — sie
   kennzeichnet weiterhin technische Werte überall SONST (Balkenwerte, Badges,
   Angebotstabelle, Filter, die ganze Wissensseite); ausgenommen ist die
   Kopfleiste. */
.ks-wert {
  flex: 0 0 auto;
  font-family: var(--schrift);
  font-size: var(--label-medium);
  font-variant-numeric: tabular-nums;
  color: var(--on-surface);
  white-space: nowrap;
}

.ks-fuss {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--abstand-m);
  padding: var(--abstand-s) var(--abstand-l);
  border-top: 1px solid var(--outline-variant);
  font-size: var(--label-medium);
  color: var(--on-surface-variant);
}
.ks-fuss-link {
  flex: 0 0 auto;
  color: var(--primary);
  font-weight: 500;
  text-decoration: none;
}
.ks-fuss-link:hover { text-decoration: underline; }

.ks-leer {
  margin: 0;
  padding: var(--abstand-l);
  font-size: var(--body-medium);
  color: var(--on-surface-variant);
}

/* ---------- Der Lupenknopf für schmale Fenster ----------
   Ab 768px gibt es ihn nicht: Dort steht das Feld selbst in der Zeile. */
.suchlupe { display: none; }

/* ---------- Burger ----------
   Der Auslöser der rechten Hauptleiste. Er steht in JEDER Größe oben rechts —
   in der Skizze wie im fertigen Bild — und ist damit der einzige Knopf, dessen
   Platz sich zwischen Handy und Desktop nicht ändert. */
.burger {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--radius-pille);
  background: none;
  cursor: pointer;
  color: var(--on-surface-variant);
  transition: background-color var(--dauer-kurz) ease, color var(--dauer-kurz) ease;
}
/* ⛔ Zustandsebene, keine Flächenstufe — und hier ist der Grund am
   deutlichsten: Der Burger sitzt IN der Kopfleiste, und die steht selbst auf
   --surface-container-high. Sein Hover wechselte also auf die Farbe, auf der
   er ohnehin liegt: 1,00:1, in BEIDEN Schemata. Siehe theme.css. */
.burger:hover { background: var(--zustand-hover); color: var(--on-surface); }
.burger:active { background: var(--zustand-aktiv); }

/* Drei Striche aus echten Elementen statt aus einem Symbolpfad: Sie sollen
   sich beim Öffnen bewegen können, und ein <svg>-Pfad ließe sich dafür nicht
   in Teile zerlegen. */
.burger-striche {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 20px;
}
.burger-striche span {
  display: block;
  height: 2px;
  border-radius: var(--radius-pille);
  background: currentColor;
  transition: transform var(--dauer-kurz) ease, opacity var(--dauer-kurz) ease;
}

/* Offen: aus den drei Strichen wird ein Kreuz. Der Knopf sagt damit auch ohne
   Blick auf die Leiste, was ein Klick jetzt bewirkt — aria-expanded allein
   sieht nur, wer vorlesen lässt. */
:root[data-leiste="offen"] .burger-striche span:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}
:root[data-leiste="offen"] .burger-striche span:nth-child(2) { opacity: 0; }
:root[data-leiste="offen"] .burger-striche span:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

/* ---------- Schmalere Fenster: die Wortmarke gibt zuerst nach ----------

   Seit die Werkzeuge absolut rechts liegen (07.08.2026), gibt es in der
   oberen Zeile keinen Umbruch mehr zu verhindern — die früheren Flex-Regeln
   samt ihrer Messprotokolle sind mit dem Layout entfallen. Was bleibt, ist
   die Frage, WO gekürzt wird: im Druckernamen (kann Ellipse) und in der
   Größe von Spule und Wortmarke — nie am Burger (feste Trefferfläche) und
   nie an der Mittigkeit. */
@media (max-width: 1023px) {
  .kopfzeile {
    /* ⛔ HIER STAND EINE KLEINERE MARKE FÜR SCHMALE FENSTER, und sie ist am
       07.09.2026 entfallen. Der Grund war Platznot: Der Schriftzug stand
       neben den Kategorien und ging deshalb eine Stufe zurück. Mit der
       Wortmarke als SVG ist die Marke schmal genug — gemessen 148,5px statt
       187,0px als Text —, und eine Marke, die je Fensterbreite anders hoch
       ist, wäre eine zweite Zahl ohne Anlass. --marke-hoehe gilt überall. */
    /* Beide Endlagen mit: Die Zeile wird niedriger, muss den 44px hohen
       Burger aber weiterhin tragen.
       ⛔ 64/50 statt 84/56 (03.09.2026). Die kompakte Lage ist hier durch ZWEI
       Größen nach unten begrenzt, und beide liegen bei 44px: der Burger (feste
       Trefferfläche) und die Kategoriegrafik, die auf dieser Breite 44px mißt
       und nirgends beschnitten wird. 50px lassen beiden 3px auf jeder Seite. */
    --kopfzeile-hoehe: 64px;
  }
  .druckerauswahl { min-width: 0; }
  .drucker-knopf { max-width: 100%; }

  /* Der Druckerwähler schrumpft auf sein Symbol (Punkt „Handy" des Umbaus,
     hier schon ab 1023px): Neben den groß gesetzten Kategorien in derselben
     Zeile ist für einen Gerätenamen kein verlässlicher Platz — und ein Name,
     der je nach Gerät mal passt und mal nicht, ließe die Knopfkante wandern.
     Der Name bleibt im Markup und damit für Vorlesehilfen erhalten (dieselbe
     sr-only-Technik wie .hl-text); sichtbar steht er im geöffneten Menü. */
  .drucker-name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .kopf-pfeil { display: none; }

  /* ⚠️ Die Verkleinerung der KATEGORIEN steht NICHT hier, sondern weiter
     unten, unmittelbar hinter ihren Grundregeln (Abschnitt „Kategorien: enger
     auf schmalen Fenstern"). Grund siehe dort — an dieser Stelle hätte sie nie
     gegriffen. */
}

/* ⛔ UNTER 768px STEHT DIE LEISTE AUF ZWEI ZEILEN (13.08.2026).

   Alles, was den schmalen Fenstern gilt — Zeilenaufteilung, Zeilenhöhen,
   Schriftgröße der Marke und die Kategorien als Schaltflächen —, steht
   gesammelt im Abschnitt „ZWEI ZEILEN" weiter unten, hinter den Grundregeln
   der Kategorien. Es MUSS dort stehen und nicht hier: `.kategorienav` und
   `.kategorie-ziel` wiegen dort genauso viel wie in den Grundregeln, und eine
   Medienabfrage erhöht die Spezifität nicht — allein die Reihenfolge in der
   Datei entscheidet. Genau daran ist die Verkleinerung der Kategorien schon
   einmal lautlos gescheitert (siehe „Kategorien: enger auf schmalen
   Fenstern").

   Hier bleibt nur, was mit der Icon-Spalte zu tun hat und deshalb an ihrer
   Grenze hängt (640px), nicht an der Grenze der Zeilenzahl (768px). */
@media (max-width: 639px) {
  /* Ohne Icon-Spalte kein Streifen, über den die Leiste laufen müsste —
     und keine Flucht, auf der der Burger stehen könnte. Beidseitig
     zurückgesetzt, weil auch das <body>-Padding hier auf 0 steht. */
  .kopfzeile { margin-inline: 0; }
}

/* ---------- Werkzeug der Kopfleiste ----------
   Der frühere gemeinsame Grundzustand `.kopf-knopf` ist am 06.08.2026
   entfallen: Er kleidete den „Mehr"-Auslöser und den Eintrag
   „Filament-Infos", und beide stehen jetzt in der rechten Hauptleiste. Übrig
   ist die Druckerauswahl, die ihre Form ohnehin selbst mitbringt
   (`.drucker-knopf` weiter unten). */

/* Ohne Rahmen fehlt dem Auslöser das Zeichen, dass etwas ausfährt — das
   Dreieck übernimmt es. Es dreht sich beim Öffnen, damit der Zustand nicht
   allein am Menü selbst hängt. */
.kopf-pfeil {
  display: inline-flex;
  /* Folgt der Schriftfarbe des Knopfes, damit Pfeil und Beschriftung beim
     Überfahren und bei gewähltem Drucker gemeinsam heller werden. */
  color: inherit;
  transition: transform var(--dauer-kurz) ease;
}
.kopf-pfeil svg { width: 18px; height: 18px; }
.drucker-knopf[aria-expanded="true"] .kopf-pfeil { transform: rotate(180deg); }

.symbol-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: var(--radius-pille);
  background: none;
  cursor: pointer;
  color: var(--on-surface-variant);
  transition: background-color var(--dauer-kurz) ease;
}
.symbol-knopf:hover { background: var(--zustand-hover); color: var(--on-surface); }
.symbol-knopf:active { background: var(--zustand-aktiv); }
.symbol-knopf svg { width: 22px; height: 22px; }

/* ---------- Zählmarke (Merkzettel, Produktvergleich) ----------

   Die kleine Zahl an den beiden Sammlungs-Einträgen der Hauptleiste. Der Name
   steckt im aria-label des Verweises, die Zahl ist für Vorlesehilfen
   ausgeblendet — „3" allein wäre keine Auskunft.

   Wo sie liegt, entscheidet die Leiste (siehe dort): im schmalen Zustand auf
   dem Symbol, im breiten am Zeilenende. Hier steht nur ihre Form. */

.zaehlmarke {
  position: absolute;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--abstand-xs);
  border-radius: var(--radius-pille);
  background: var(--primary);
  color: var(--on-primary);
  font-size: var(--label-medium);
  font-weight: 500;
  /* Zeilenhöhe = Höhe: Die Zahl sitzt damit mittig, ohne dass ein
     zweiter Flex-Kasten nötig wäre. */
  line-height: 18px;
  text-align: center;
}
/* Leere Sammlung: keine Marke. Eine „0" im Kreis wäre eine Meldung über
   nichts — und sie stünde dauerhaft in einer Leiste, die ruhig sein soll. */
.zaehlmarke[hidden] { display: none; }

/* ---------- Klappmenüs ----------
   Der Container ist der Bezugspunkt: das Menü fährt darunter aus und ist
   rechtsbündig am Auslöser ausgerichtet. Beide Menüs — Drucker in der
   Kopfzeile, Währung in der Hauptleiste — teilen sich Form und Verhalten
   (PD.komponenten.verbindeMenue). Ein „Mehr" gab es bis zum 05.08.2026, ein
   Benutzermenü bis zum 06.08.2026; beide siehe index.html. */

.menue {
  position: absolute;
  top: calc(100% + var(--abstand-xs));
  right: 0;
  /* Nur gegenüber den Geschwistern in der Kopfzeile relevant — die Kopfzeile
     selbst regelt den Stapel gegenüber dem Rest der Seite. */
  z-index: 1;
  min-width: 208px;
  padding: var(--abstand-xs);
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-l);
  /* Überlagerung, nicht Karte: eigene Flächenstufe plus Schatten tragen die
     Abhebung. Vorher lag die Fläche auf --surface-container-lowest, die sich
     hell wie dunkel nur um 1,05:1 von der Seite unterscheidet — deshalb
     brauchte es damals einen Rahmen. Mit --surface-container-high ist die
     Stufe selbst sichtbar und die Linie überflüssig. */
  background: var(--surface-container-high);
  box-shadow: var(--schatten-schwebend);

  /* Geschlossen: unsichtbar UND nicht fokussierbar (visibility statt display,
     damit das Auf- und Zufahren animierbar bleibt). Die Verzögerung auf
     visibility lässt das Ausblenden zu Ende laufen, bevor es verschwindet. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top right;
  transition:
    opacity var(--dauer-kurz) ease-out,
    transform var(--dauer-kurz) ease-out,
    visibility 0s linear var(--dauer-kurz);
}

.menue--offen {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity var(--dauer-kurz) ease-out,
    transform var(--dauer-kurz) ease-out,
    visibility 0s;
}

/* Ohne Bewegung: sofort da bzw. weg, kein Nachlaufen der Sichtbarkeit. */
@media (prefers-reduced-motion: reduce) {
  .menue,
  .menue--offen { transition: none; }
}

.menue-eintrag {
  display: block;
  width: 100%;
  padding: var(--abstand-m) var(--abstand-l);
  border: 0;
  border-radius: var(--radius-s);
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--on-surface);
  font-size: var(--body-medium);
  text-decoration: none;
}

/* ⛔ Die frühere Fassung stand hier so: „Einträge liegen AUF der Menüfläche
   (--surface-container-high) — ihr Hover muss deshalb eine Stufe weiter
   gehen als bei Bedienelementen auf der Seitenfläche." Die Beobachtung war
   richtig, die Abhilfe trug nur nicht: Eine Stufe weiter war hell
   --highest, und --high wie --highest standen beide auf #FFFFFF. Der Hover
   war damit unsichtbar, und zwar genau in dem Menü, für das die
   Sonderregel gemacht wurde.
   Die Zustandsebene macht die Frage gegenstandslos — sie verdunkelt, was da
   ist, und braucht deshalb gar nicht zu wissen, worauf der Eintrag liegt.
   Gleiche Logik bei Währungs- und Druckereinträgen. */
.menue-eintrag:hover { background: var(--zustand-hover); }
.menue-eintrag:active { background: var(--surface-variant); }

/* ---------- Gruppen im Benutzermenü ----------
   Das Menü trägt seit dem Umbau vier Blöcke (Anmelden, Darstellung,
   Anzeigewährung, Seiten). Getrennt werden sie durch eine Haarlinie: In einem
   schwebenden Menü gibt es keine zweite Fläche, über die sich Blöcke
   absetzen ließen, und ein Abstand allein ließe die Liste auseinanderfallen.
   Das ist die Ausnahme zur Regel „Flächen statt Linien" — sie gilt für die
   Seite, nicht für das Innere einer Überlagerung. */

.menue-gruppe + .menue-gruppe,
.menue-eintrag + .menue-gruppe {
  margin-top: var(--abstand-xs);
  padding-top: var(--abstand-xs);
  border-top: 1px solid var(--outline-variant);
}

.menue-titel {
  padding: var(--abstand-s) var(--abstand-l) var(--abstand-xs);
  font-size: var(--label-medium);
  font-weight: 500;
  color: var(--on-surface-variant);
}

/* Der schaltende Eintrag „Dunkler Modus" stand bis zum 06.08.2026 im
   Benutzermenü. Hell/Dunkel wird jetzt ausschließlich auf der
   Einstellungsseite gewählt — dort als Auswahl aus Hell, Dunkel und
   Systemvorgabe, also feiner als ein Schalter es könnte. */

/* ---------- Anzeigewährung (Auswahlgruppe im Benutzermenü) ----------
   Sie stand bis zum Umbau als eigenes Klappmenü in der Leiste. Dort war sie
   eines von fünf Bedienelementen; ihre Aufgabe — die Näherungen unter den
   Preisen — rechtfertigt keinen Dauerplatz in der Zeile.

   Höhenbegrenzung, weil die Liste nicht der Website gehört: Welche Währungen
   wählbar sind, entscheidet allein die Kurstabelle des Backends. Wächst sie,
   wächst hier ein Rollbereich statt eines Menüs über die Fensterhöhe. */
.waehrung-liste {
  max-height: min(40vh, 240px);
  overflow-y: auto;
}

.waehrung-eintrag {
  display: flex;
  align-items: center;
  gap: var(--abstand-s);
  width: 100%;
  /* Waagerecht wie .menue-eintrag: Alle Einträge des Menüs stehen auf
     derselben linken Kante, sonst zerfiele die Liste in zwei Spalten. */
  padding: var(--abstand-s) var(--abstand-l);
  border: 0;
  border-radius: var(--radius-s);
  background: none;
  cursor: pointer;
  color: var(--on-surface);
  font-size: var(--body-medium);
  text-align: left;
}
.waehrung-eintrag:hover { background: var(--zustand-hover); }
.waehrung-eintrag:active { background: var(--surface-variant); }

/* Feste Spalte, damit Symbole und Kürzel untereinander fluchten. */
.we-symbol { width: 24px; flex: 0 0 auto; font-weight: 500; }
.we-code { width: 40px; flex: 0 0 auto; font-weight: 500; }
.we-name { color: var(--on-surface-variant); overflow: hidden; text-overflow: ellipsis; }

/* Die gewählte Währung trägt Fläche UND Haken — nie nur den Farbton. */
.waehrung-eintrag[aria-checked="true"] {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
}
.waehrung-eintrag[aria-checked="true"] .we-name { color: inherit; }
.we-haken { width: 18px; height: 18px; margin-left: auto; flex: 0 0 auto; }

.waehrung-kein-kurs {
  padding: var(--abstand-s) var(--abstand-l) var(--abstand-m);
  font-size: var(--body-medium);
  color: var(--on-surface-variant);
}

/* ---------- Druckerauswahl ----------
   Das einzige Werkzeug, das sichtbar in der Leiste bleibt: Es filtert die
   Liste und steuert die Kompatibilitäts-Badges, wirkt also auf das, was man
   gerade ansieht. Gleiches Ausklapp-Muster wie die anderen Menüs, zusätzlich
   mit Suchfeld über der Liste. */

.druckerauswahl { position: relative; }

/* ⛔ DER RAHMEN IST ZURÜCK — ALS EINZIGE PILLE DER LEISTE (02.09.2026).

   Der Kopfkommentar dieser Datei begründet, warum die früheren umrandeten
   Pillen um Währung und Drucker gefallen sind: Sie gaben JEDEM Einzelteil
   eine Kante und ließen die Leiste als Ansammlung lesen. Dieser Grund gilt
   unverändert — und trifft genau deshalb nicht mehr zu: Die Währungspille
   ist längst in die rechte Hauptleiste gewandert, und die Kategorien geben
   mit dem Hover ihre letzte Fläche ab. Übrig ist ein einziges umrandetes
   Element in einer sonst rahmenlosen Zeile, und das ist keine Ansammlung,
   sondern eine Auszeichnung: Der Wähler ist das einzige BEDIENELEMENT der
   Leiste, das einen Zustand trägt (welches Gerät gilt gerade) — alles andere
   dort ist ein Verweis.

   ⚠️ --outline, NICHT --outline-variant. Die Haarlinie trägt hell 1,22:1
   gegen die weiße Leiste; ein Bedienelement braucht nach WCAG 1.4.11 aber
   3:1 für seine Grenze, und die Kante IST hier die ganze Grenze (die Füllung
   bleibt durchsichtig, jede Fläche unter 1,15:1 wäre unsichtbar). Gerechnet
   aus den Tokens: #6A6D77 auf #FFFFFF = 5,16:1, dunkel #8C929B auf #22262D =
   4,84:1. Dieselbe Rolle und derselbe Grund wie beim ungewählten Filter-Chip.

   Waagerecht --abstand-l statt --abstand-m: Eine Pille braucht Innenraum,
   sonst sitzt der Name auf der Kante.

   ⚠️ SENKRECHT AB 640px ENGER (03.09.2026, weiter unten): In der schlanken
   Leiste war die Pille mit 40,4px in einer 72px-Zeile das massigste Element.
   Der Grundwert --abstand-s BLEIBT hier stehen, weil er auf dem Handy gilt,
   und dort ist die Höhe kein Gestaltungsmaß, sondern die Trefferfläche für
   den Daumen. */
.drucker-knopf {
  display: inline-flex;
  align-items: center;
  gap: var(--abstand-s);
  max-width: 240px;
  padding: var(--abstand-s) var(--abstand-l);
  border: 1px solid var(--outline);
  border-radius: var(--radius-pille);
  background: none;
  cursor: pointer;
  color: var(--on-surface-variant);
  font-size: var(--label-large);
  font-weight: 500;
  transition:
    background-color var(--dauer-kurz) ease,
    color var(--dauer-kurz) ease;
}
/* ⚠️ Ab 640px flacher, damit die Pille in der schlanken Leiste nicht als
   Block steht: 32,4px statt 40,4px Höhe. Das bleibt über der Untergrenze von
   24px aus WCAG 2.5.8 und betrifft ausdrücklich nur die Breiten mit Maus —
   unter 640px behält der Knopf seine 38,4px, dort ist er ein Daumenziel.
   Der Burger daneben bleibt in JEDER Lage 44 × 44px: Er ist das dokumentierte
   Mindestmaß der Zeile und steht in der Flucht der Icon-Spalte, die sich mit
   der Leistenhöhe nicht ändert. Ein Knopf, der mitschrumpft, verlöre beides. */
@media (min-width: 640px) {
  .drucker-knopf { padding-block: var(--abstand-xs); }
}

.drucker-knopf:hover { background: var(--zustand-hover); color: var(--on-surface); }
.drucker-knopf:active { background: var(--zustand-aktiv); }
.drucker-symbol { display: inline-flex; flex-shrink: 0; }
.drucker-symbol svg { width: 20px; height: 20px; }

/* ---------- Statuspunkt vor dem Gerätenamen (02.09.2026) ----------

   ⛔ PUNKT UND DRUCKERSYMBOL SCHLIESSEN EINANDER AUS — je Fensterbreite gilt
   genau eines, und das ist der Kern dieser Bauart.

   Ab 1024px steht der Name im Knopf; davor genügt ein Punkt, der sagt, OB ein
   Gerät gilt. Das Symbol wäre daneben eine zweite Aussage über dieselbe Sache.

   Darunter ist der Name unsichtbar (sr-only, siehe oben) — dann bleibt vom
   Knopf nur noch sein Vorzeichen übrig, und ein 8px-Punkt sagt niemandem,
   dass hier ein Drucker gewählt wird. Deshalb trägt diese Breite weiterhin
   das Druckersymbol. Wer den Punkt auf alle Breiten ausdehnt, nimmt dem
   schmalen Fenster seinen einzigen Hinweis, wozu der Knopf da ist.

   ⚠️ Der Punkt sagt nichts, was nicht auch als Wort dastünde: Neben ihm steht
   entweder der Modellname oder „Mein Drucker". Er ist damit kein Träger einer
   Aussage allein durch Farbe — und er existiert genau auf den Breiten, auf
   denen dieses Wort sichtbar ist.

   Als grafisches Objekt braucht er 3:1 (WCAG 1.4.11). Gerechnet:
     gewählt      --balken-gruen  hell 6,25:1   dunkel hoch (heller Ton)
     ohne Gerät   --outline       hell 5,16:1   dunkel 4,84:1 */
.drucker-punkt {
  display: none;
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--outline);
  transition: background-color var(--dauer-kurz) ease;
}
.druckerauswahl--gewaehlt .drucker-punkt { background: var(--balken-gruen); }

@media (min-width: 1024px) {
  .drucker-punkt { display: block; }
  .drucker-symbol { display: none; }
}

/* Langer Modellname bricht nicht um, sondern wird gekürzt. */
.drucker-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Mit Auswahl: kräftigere Schrift und ein eingefärbtes Symbol statt der
   früheren gefüllten Pille. Die Füllung war in der aufgeräumten Zeile das
   lauteste Element und zog den Blick auf ein Werkzeug statt auf das Produkt.
   Die Unterscheidung hängt weiterhin nicht am Farbton allein: Im Knopf steht
   der Modellname, ohne Auswahl steht dort „Mein Drucker". */
.druckerauswahl--gewaehlt .drucker-knopf { color: var(--on-surface); }
.druckerauswahl--gewaehlt .drucker-symbol { color: var(--primary); }

.menue--drucker {
  min-width: 288px;
  padding: 0;
  overflow: hidden;
}

.drucker-suchzeile {
  padding: var(--abstand-s);
}

.drucker-suchfeld {
  width: 100%;
  padding: var(--abstand-s) var(--abstand-m);
  border: 1px solid var(--outline);
  border-radius: var(--radius-s);
  background: var(--surface-container-low);
  color: var(--on-surface);
  font-size: var(--body-medium);
}

/* ⛔ OHNE EIGENE REGEL GILT DIE VORGABE DES BROWSERS, und die kennt kein
   Farbschema. Chrome setzt #757575; auf der Feldfläche #F2F4F9 sind das
   4,19:1 und damit unter den 4,5:1 für Normaltext. Gegengeprobt mit drei
   Testfeldern verschiedener Farbe: Der Wert blieb unverändert — er hängt
   weder an der Feldfarbe noch am Theme, sondern allein daran, dass hier
   nichts gesetzt ist. Dieselben zwei Zeilen gibt es für die Hauptsuche und
   das Listen-Suchfeld schon länger (css/seiten.css); diesem Feld und dem
   Hex-Feld des Farbkreises fehlten sie. Mit --on-surface-variant: rund 9:1. */
.drucker-suchfeld::placeholder { color: var(--on-surface-variant); }

.drucker-liste {
  max-height: min(60vh, 420px);
  overflow-y: auto;
  padding: var(--abstand-xs);
}

.drucker-gruppe {
  padding: var(--abstand-s) var(--abstand-m) var(--abstand-xs);
  font-size: var(--label-medium);
  font-weight: 500;
  color: var(--on-surface-variant);
}

.drucker-eintrag {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--abstand-s);
  width: 100%;
  padding: var(--abstand-s) var(--abstand-m);
  border: 0;
  border-radius: var(--radius-s);
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--on-surface);
  font-size: var(--body-medium);
}
/* „nicht mehr erhältlich" am Auslaufmodell. Gedämpft und kleiner, aber als
   WORT vorhanden — eine bloße Ausgrauung wäre eine Aussage, die man raten
   müsste, und für Vorlesehilfen gar keine. */
.drucker-abgekuendigt {
  font-size: var(--label-small);
  color: var(--on-surface-variant);
  white-space: nowrap;
}

.drucker-eintrag:hover { background: var(--zustand-hover); }
.drucker-eintrag:active { background: var(--surface-variant); }
.drucker-eintrag[aria-checked="true"] {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
}
.drucker-haken { width: 18px; height: 18px; flex-shrink: 0; }

.drucker-kein-treffer {
  padding: var(--abstand-m);
  font-size: var(--body-medium);
  color: var(--on-surface-variant);
}

/* Tablet: Der Knopf behält seine inhaltsabhängige Breite bis 240px wie am
   Desktop, darf jetzt aber auch DARUNTER, sobald die Zeile es verlangt.
   Ohne das zweite Glied im min() stünde er starr auf 240px, während sein
   Behälter bei 640px auf 220,8px geschrumpft ist — gemessen: 19,2px Überstand
   quer über das Benutzersymbol. Muss HINTER der Grundregel stehen (siehe
   Hinweis oben in der Kopfleisten-Sektion). */
@media (min-width: 640px) and (max-width: 1023px) {
  .drucker-knopf { max-width: min(240px, 100%); }
}

@media (max-width: 639px) {
  /* Die Breite steckt nicht mehr hier, sondern als flex-basis am Behälter
     `.druckerauswahl` (siehe „Handy: eine Zeile, feste Plätze"). Ein
     max-width am Knopf konnte ihn nur begrenzen, nicht auf einen festen Platz
     stellen — bei kurzem Namen blieb er schmal und die Zeile verschob sich. */
  .drucker-knopf {
    width: 100%;
    max-width: none;
    /* Enger als am Desktop, und das ist gerechnet, nicht geschätzt: Neben dem
       Namen stehen im Knopf 12+12 Innenabstand, das 20px-Symbol, das 18px-
       Dreieck und zweimal 8px Lücke — zusammen 78px, die dem Namen fehlen.
       Bei 360px Fensterbreite (die verbreitetste Android-Breite) bleiben dem
       Knopf 154,5px, dem Namen also 76,5 — „Mein Drucker" braucht 85,8 und
       wurde um ein Zeichen gekürzt. Mit 8/4 sinkt der Vorbau auf 62px und der
       Name hat 92,5px: Er steht vollständig da.
       Senkrecht bleibt es bei --abstand-s: Die Trefferfläche von 38,4px Höhe
       ist das Mindestmaß für den Daumen und wird nicht angetastet. */
    gap: var(--abstand-xs);
    padding-left: var(--abstand-s);
    padding-right: var(--abstand-s);
  }
  /* Der Name füllt den Rest des festen Platzes aus. Ohne das säße das
     Klapp-Dreieck bei „Mein Drucker" mitten im Knopf und rund 40px vor dessen
     rechter Kante — der Abstand zum Benutzersymbol daneben sähe dann größer
     aus als der zwischen den beiden Werkzeugen tatsächlich ist. */
  .drucker-name { flex: 1 1 auto; }
  /* Für ein 288px-Klappmenü neben dem Knopf ist auf einem Handy kein Platz —
     deshalb dort ein Überlagerungsstreifen unter der ganzen Kopfleiste.
     --kopf-hoehe wird zur Laufzeit an der wirklichen Höhe nachgezogen
     (js/app.js), sonst säße der Streifen bei zweizeiliger Leiste zu hoch. */
  .menue--drucker {
    position: fixed;
    top: var(--kopf-hoehe);
    left: var(--abstand-s);
    right: var(--abstand-s);
    min-width: 0;
    transform-origin: top center;
  }
  .drucker-liste { max-height: 60vh; }
}

/* ---------- Hauptnavigation: die Kategorien ----------

   Filament / Resin / Drucker sind das Produkt und stehen deshalb sichtbar
   links, direkt neben der Wortmarke — nicht in einem Menü und nicht rechts
   zwischen den Werkzeugen. Sie sind der einzige Teil der Leiste in
   --title-large; alles andere dort ist --label-large. Dieser Größenunterschied
   ersetzt die eigene Zeile, die sie vorher brauchten.

   Vorher lagen sie in einer zweiten Leiste mit eigener Fläche. Die Fläche ist
   ab 1024px weg: In einer einzigen Zeile wäre sie ein Kasten um einen Teil
   der Zeile — genau die Sorte Umrandung, die hier verschwinden sollte. */

.kategorienav {
  display: flex;
  align-items: center;
  /* Großzügig (07.08.2026): Die drei Kategorien sind die Hauptnavigation und
     sollen als breite Zeile wirken, nicht als gedrängtes Grüppchen. Der
     Abstand trennt, die Trefferflächen der Einträge stoßen nicht aneinander.

     ⛔ 40px (03.09.2026), nachdem am 02.09. auf 80px erhöht worden war. Der
     Grund ist nicht Geschmack, sondern der VIERTE Eintrag — und die Zahl ist
     GEMESSEN, nicht gewählt. Maßgeblich ist immer 1024px, die engste Breite,
     auf der diese Fassung überhaupt gilt; dort steht die Reihe zwischen Marke
     und Druckerwähler:

       Lücke   Reihe endet bei   Pille beginnt bei   Luft
        80px        x = 815            x = 808       −7px  (Überlappung)
        64px        x = 799            x = 798       −0,5px
        40px        x = 763            x = 798       +35px

     Die Einträge selbst summieren sich auf 382px, die Fenstermitte liegt bei
     512 — mehr als rund 53px Lücke kann die Zeile dort nicht tragen. 40px ist
     die nächste Stufe der Abstandsskala darunter und lässt Reserve.

     ⚠️ Enger heißt hier nicht gedrängter: Gegenüber der alten Fassung (64px
     Lücke bei 26px Schrift) ist die Lücke von 2,5 auf 2,2 Schrifthöhen
     gefallen, während die Reihe einen Eintrag mehr trägt. Die reine Pixelzahl
     sagt darüber nichts. */
  /* ⛔ 16px statt 40px (03.09.2026). Die 40px waren für eine Reihe gerechnet,
     die MITTIG in der Zeile stand und den Platz zwischen Marke und Werkzeugen
     füllen sollte. Seit sie links neben der Marke steht und rechts von ihr das
     Suchfeld beginnt, ist derselbe Wert das Gegenteil einer Großzügigkeit: Er
     schiebt die Suche nach rechts aus dem Bild. 16px ist der Abstand der
     Bildvorlage (gemessen 40px von Textkante zu Textkante, abzüglich der
     beidseitigen 12px Innenabstand der Einträge). */
  gap: var(--abstand-l);
  /* ⛔ DIE GEGENSTELLE ZU --marken-luft (22.09.2026). Der Abstand von der
     Marke bis zur SCHRIFT „Filament“ soll genauso groß sein wie der vom
     Fensterrand bis zur Marke. Zwischen beiden liegen drei Stücke: das
     column-gap der Zeile, dieser Rand und das Polster des Eintrags — also
     bleibt für ihn --marken-luft minus die beiden anderen.

     ⚠️ --kategorie-polster und nicht --abstand-m: Unter 1024px ist das
     Polster eine Stufe kleiner, und ohne diese Kopplung wanderte die Marke
     dort um 4px aus der Mitte — zu wenig, um aufzufallen, und genug, um
     schief auszusehen. */
  margin-left: calc(
    var(--marken-luft) - var(--abstand-m) - var(--kategorie-polster)
  );
  /* ⛔ KEIN Scroll-Kasten mehr (20.08.2026). Vorher stand hier overflow-x:
     auto, damit die Reihe auf schmalen Fenstern schiebbar ist statt
     umzubrechen. Das rechnet die Gegenachse ebenfalls auf auto und beschnitt
     damit exakt am Linkkasten — genau dort, wo die Kategoriegrafik jetzt
     hinausragt: Sie ist als Wasserzeichen rund 73px hoch, der Kasten mißt
     47px. Mit dem Scroll-Kasten blieben von den Ringen und der Flasche
     abgeflachte Reste stehen.

     Der Verlust ist keiner: Geschoben werden mußte hier nie. Unter 768px hat
     die Reihe seit dem 13.08.2026 eine eigene Zeile mit drei gleich breiten
     Schaltflächen (dort steht bereits overflow: visible, aus demselben Grund
     — ein Scroll-Kontext schnitte die Rundungen ab), und ab 768px sind
     gemessene 50,5px Luft zur Marke da. Der Scroll-Kasten war ein Rest aus
     der Zeit, als alle vier Gruppen in EINER Zeile gedrängt standen.

     ⚠️ min-width: 0 bleibt trotzdem stehen, nur mit anderer Aufgabe: Ein
     Flex-Kind schrumpft von sich aus nicht unter seine Inhaltsbreite. Gegen
     ein zu breites Dokument schützt jetzt nicht mehr das overflow-x hier,
     sondern das overflow: clip an .kopfzeile-inhalt — die Bühne der rollenden
     Spule, die ohnehin alles Überstehende dieser Zeile einfängt. */
  min-width: 0;
  overflow: visible;
}
/* Zentriert wird die Reihe von ihrer Zeile (.kopfzeile-inhalt,
   justify-content) — sie selbst braucht weder max-width noch eigene Ränder:
   Sie ist dort das einzige Kind im Fluss, alles andere liegt absolut.
   Die Regel, die hier den Rollbalken verbarg (::-webkit-scrollbar), ist mit
   dem Scroll-Kasten am 20.08.2026 entfallen — sie hätte nichts mehr zu
   verbergen. */

.kategorie-ziel {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  /* Enger (03.09.2026): 4/12 statt 8/16. Der Innenabstand war auf eine
     26px-Zeile gerechnet; neben 18px Text wirkte er als Kasten um jedes Wort.
     ⚠️ Waagerecht aus --kategorie-polster: Derselbe Wert hält die Marke
     mittig (siehe .kopfzeile), und zwei Zahlen dafür liefen auseinander. */
  padding: var(--abstand-xs) var(--kategorie-polster);
  /* ⛔ --title-medium (18px) STATT --headline-small (26px) (03.09.2026).
     Die Kategorien sind Wegweiser, keine Überschriften — 26px machten aus
     der Navigation eine zweite Titelzeile neben der Wortmarke. 18px ist die
     Stufe, die im Projekt „benannt, nicht betont" trägt (Kartentitel).

     ⛔ WER DIESE ZAHL ÄNDERT, ZIEHT --kategorie-grafik NACH. Die Grafik hängt
     als em an genau dieser Schriftgröße und schrumpfte sonst stillschweigend
     mit — siehe die Rechnung dort. */
  font-size: var(--title-medium);
  /* Die sichtbare Größe der Kategoriegrafik, ausgedrückt in em DIESER
     Schriftstufe: 3.177em × 18px = 57,19px, exakt das Maß, das die frühere
     Fassung mit 2.2em × 26px ergab. Begründung bei .kategorie-ziel::after. */
  --kategorie-grafik: 3.177em;
  font-weight: 500;
  line-height: var(--zeile-eng);
  /* ⛔ ZURÜCK AUF --on-surface-variant (02.09.2026) — UND DAS IST KEINE
     RÜCKNAHME DER ENTSCHEIDUNG VOM 10.08.2026, SONDERN IHRE FOLGE.

     Damals stand hier --on-surface-variant und kam im HELLEN Schema auf
     2,98:1 gegen die Kopfleiste — AA verfehlt in beiden Lesarten (3:1 für
     großen Text, 4,5:1 für die 20px darunter). Der Grund lag aber nie an der
     Textrolle: Die Kopfleiste trug damals die Fläche der SEITE (#E1E4EC), und
     --on-surface-variant war ein hellerer Ton als heute. Beides hat sich mit
     dem Gestaltungswechsel geändert — die Leiste ist weiß, die Rolle steht
     auf #5A5F6A.

     Nachgerechnet aus den Tokens: #5A5F6A auf #FFFFFF = 6,40:1, dunkel
     #C2C7CF auf #22262D = 8,94:1. Beide über 4,5:1, also auch für die 20px-
     Stufe tragfähig — die Paarung steht ohnehin schon in der Tabelle von
     pruefeTextAufFlaeche und wird dort bei jeder Flächenänderung neu
     gerechnet.

     Was die gedämpfte Fassung leistet: Die Kategorien sind Wegweiser, nicht
     der Inhalt der Seite. In Schwarz standen sie neben der Wortmarke als
     zweite laute Gruppe; ruhiges Grau lässt der aktiven Kategorie ihren
     Auftritt, ohne dass diese lauter werden müsste. Der aktive Eintrag trägt
     weiterhin --primary UND eine Unterstreichung, ist also an Farbe und Form
     erkennbar (Aktiv nie am Farbton allein). */
  color: var(--on-surface-variant);
  text-decoration: none;
  white-space: nowrap;
  border-radius: var(--radius-s);
  /* Die Kante ist immer da, nur meist durchsichtig — sonst sprängen die
     Einträge beim Wechsel um ihre Höhe.
     ⚠️ Aus dem Token: Dieselbe Stärke hält die Marke daneben auf Höhe der
     Schrift (Begründung bei --kategorie-unterstrich). */
  border-bottom: var(--kategorie-unterstrich) solid transparent;
  transition:
    background-color var(--dauer-kurz) ease,
    color var(--dauer-kurz) ease,
    border-color var(--dauer-kurz) ease;
}

/* ⛔ HOVER OHNE FLÄCHE (02.09.2026). Hier stand zusätzlich
   `background: var(--zustand-hover)`. Eine getönte Fläche unter dem Wort ist
   genau die Pille, die diese Zeile nicht mehr haben soll — und sie war das
   einzige gefüllte Element der Leiste. Die Rückmeldung trägt jetzt der
   Farbsprung allein: aus dem ruhigen Grau wird die volle Textfarbe
   (6,40:1 → 17,4:1 hell). Das ist derselbe Weg wie bei jedem Textverweis der
   Seite und braucht keinen Kasten.
   ⚠️ Die Zustandsebene bleibt für alles andere in der Leiste unangetastet —
   Burger, Symbolknöpfe und die Menüeinträge holen ihren Hover weiterhin
   dort (css/theme.css, „Zustandsebene"); nur die Kategorien tun es nicht. */
.kategorie-ziel:hover { color: var(--on-surface); }

/* ⛔ „Wissen" IST SEIT DEM 03.09.2026 EIN GEWÖHNLICHER EINTRAG.

   Hier standen drei Regeln für einen Eintrag ohne Ziel: kein Zeiger, kein
   Hover, dazu die Marke „bald" in Schreibmaschinenschrift. Sie waren die
   richtige Antwort auf „hier steht ein Wort, noch keine Tür" — und sie sind
   ersatzlos entfallen, weil es die Tür jetzt gibt (/infos). Ein Eintrag, der
   führt, braucht keine Kennzeichnung dafür, dass er nicht führt.

   ⚠️ Er bekommt trotzdem KEINE Kategoriegrafik: Die hängt einzeln an
   liste/resin/drucker, und für „Wissen" gibt es keine Datei. Das ergibt sich
   von selbst aus dem Selektor dort — es braucht keine Ausnahme. */

/* Aktiv über Farbe UND Kante — nicht allein über den Farbton. */
.kategorie-ziel[aria-current="page"] {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

/* ---------- Kategoriegrafik hinter dem Wort (14.08.2026) ----------

   Rein dekorativ. Die FORM kommt aus assets/kategorie-<name>.svg, die FARBE aus
   dem Theme: Die Datei dient als Maske, das Pseudoelement trägt currentColor und
   damit genau die Farbe, die der Link ohnehin führt — inaktiv --on-surface,
   aktiv --primary. Deshalb braucht der Dunkelmodus weder eine zweite Datei noch
   eine zweite Regel. Dieselbe Bauart wie .wf-schema-bild in seiten.css; die
   Dateien tragen zwar ein festes #94a3b8, das die Maske aber nie durchlässt —
   sie wertet allein den Alphakanal aus.

   ⛔ Die vier Kategorien stehen EINZELN im Selektor, statt über [data-ziel] zu
   sammeln. Ohne passende Kategorie entsteht so gar kein ::after. Ein Rückfall
   wie mask-image: var(--x, none) wäre das Gegenteil einer Absicherung: `none`
   heißt „keine Maske", und das Pseudoelement stünde als volles Farbrechteck
   hinter dem Wort. Aus demselben Grund der @supports-Block unten.

   ⚠️ ::after, nicht ::before — ::before trägt unter 768px das Häkchen des
   aktiven Eintrags, und das ist dort die einzige Aussage ohne Farbe.

   ⛔ WER EINE KATEGORIE ERGÄNZT, TRÄGT SIE IN BEIDE AUFZÄHLUNGEN NACH: hier
   und in die Abschaltung unter 768px. „Wissen" ist am 22.09.2026 nur in die
   Maskenliste weiter unten geraten und hatte deshalb GAR KEINE Grafik — die
   Maske lag an einem Pseudoelement, das mangels `content` nie entstand. Im
   Bildschirmabzug sah der Reiter aus wie immer: Es fehlte nichts Benanntes,
   nur der Grund dahinter, und der hat keinen Umriß, an dem man ihn vermißt. */
.kategorie-ziel {
  /* Beides gehört zusammen: `relative` macht den Link zum Bezugsrahmen (ohne ihn
     ankerte das Pseudoelement an .kopfzeile-inhalt und läge irgendwo in der
     Zeile), `isolation` zum Stapelkontext. Ohne den rutscht z-index: -1 hinter
     die eigene Fläche des Links — und damit hinter die Hover-Ebene, die die
     Grafik dann verdeckte. Mit ihm liegt sie über der Fläche und unter dem
     Text. */
  position: relative;
  isolation: isolate;
}

.kategorie-ziel[data-ziel="liste"]::after,
.kategorie-ziel[data-ziel="resin"]::after,
.kategorie-ziel[data-ziel="drucker"]::after,
.kategorie-ziel[data-ziel="wissen"]::after {
  content: "";
  position: absolute;
  /* inset + margin: auto zentriert im Polsterkasten, waagerecht wie senkrecht,
     ohne die Maße des Wortes zu kennen. Der Kasten ist symmetrisch gepolstert
     (8/16px bzw. 8/12px) und trägt nichts als den Text — seine Mitte IST die
     Wortmitte, gleich wie lang das Wort ist. Der 2px-Unterrand liegt außerhalb
     des Bezugsrahmens und verschiebt nichts. */
  inset: 0;
  margin: auto;
  z-index: -1;
  /* ⛔ Zentriert wird auf die TINTE, nicht auf den Zeilenkasten — aber der
     nötige Versatz ist WINZIG, und das ist der Punkt.

     Bis zum 20.08.2026 stand hier -0.366em, also die halbe Oberlänge nach
     oben. Der Wert beruhte auf der Annahme, die Mitte des Polsterkastens falle
     auf die GRUNDLINIE; dann müßte man von dort um die halbe Oberlänge
     hochrücken. Die Annahme ist falsch — die Kastenmitte liegt bereits
     praktisch auf der Tintenmitte:

       Δ = (Tintenmitte − Kastenmitte)
         = em · (Ascent − Descent − Oberlänge) / 2
         = em · (1,088 − 0,265 − 0,766) / 2
         = +0,029em                          (nach UNTEN, nicht nach oben)

     Die Zeilenhöhe kürzt sich in der Herleitung heraus (sie geht über das
     Half-Leading mit +L/2 ein und über die Kastenmitte mit −L/2 wieder ab).
     Der Wert gilt deshalb unverändert für alle drei Schriftstufen — genau wie
     der alte, nur ist er um eine Größenordnung kleiner.

     Gegenprobe: (Ascent − Descent)/2 ist --marke-grundlinie = 0,412, die halbe
     Oberlänge 0,383. 0,412 − 0,383 = 0,029 — dieselbe Rechnung, die in
     CLAUDE.md für die Wortmarke steht, gleiche Schrift, gleiches Ergebnis.

     Die alten -0,366em schoben die Grafik damit rund 9,5px bei 26px Schrift zu
     weit nach oben. Solange sie 1.05em klein war, las sich das als leichte
     Unruhe; als Wasserzeichen von 57px stand sie sichtbar über dem Wort und
     lief oben in den Zuschnitt der Leiste.

     ⚠️ Die Metrikwerte hängen an der SCHRIFTART, wie bei der Wortmarke auch:
     Segoe UI (system-ui unter Windows). Und sie hängen daran, daß die drei
     Wörter keine Unterlängen haben — käme je eine Kategorie mit „g", „p" oder
     „y" dazu, ist die Oberlänge nicht mehr das richtige Maß der Tinte. */
  transform: translateY(0.029em);
  /* An der Schriftgröße statt an einer festen Pixelzahl: Die Zeile führt drei
     Schriftstufen (26 / 20 / 16px), und die Grafik soll in jeder dieselbe
     Wirkung haben.
     ⚠️ Bis zum 20.08.2026 war der Linkkasten die harte Obergrenze, und sie lag
     bei 1.037em: .kategorienav war ab 768px ein Scroll-Kasten (overflow-x:
     auto rechnet die Gegenachse ebenfalls auf auto) und beschnitt exakt an ihm
     — gemessen bei 24,0 und 71,9, während die Leiste von 0 bis 97 reicht. Die
     24px Luft darüber waren sichtbar, aber für die Grafik unerreichbar. Diese
     Grenze ist mit dem Scroll-Kasten gefallen (siehe .kategorienav).
     ⛔ Seit dem 20.08.2026 ist die Grafik ein WASSERZEICHEN und kein Symbol
     mehr: 2.2em statt 1.05em. Damit sprengt sie den Linkkasten bewußt — sie
     ist rund 57px hoch bei 26px Schrift, der Kasten mißt 47px. Genau dafür
     steht `.kategorienav` nicht mehr auf overflow-x: auto (Begründung dort).

     ⛔ DIE OBERGRENZE IST DIE LEISTE, NICHT DER GESCHMACK — und sie hängt am
     Versatz darüber. Weil der jetzt nahezu null ist, sitzt die Grafik
     praktisch auf der Mitte des Linkkastens, und der Linkkasten steht mittig
     in der Leiste: Der Platz nach oben und nach unten ist damit gleich. In der
     ruhenden Leiste sind das je 48px (Höhe 96), in der geschrumpften je 30px
     (Höhe 60). `.kopfzeile-inhalt` trägt overflow: clip — die kompakte Lage
     ist also die engere und läßt höchstens 60px = 2.3em zu.

     2.2em bleibt damit in JEDER Rolllage vollständig sichtbar. Das war unter
     dem alten Versatz von -0,366em nicht so: Die Grafik stand dort 9,5px höher
     und lief oben in den Zuschnitt — bei 2.8em sichtbar, bei 2.2em knapp.
     **Eine oben gekappte Grafik liest sich nicht als „zu groß", sondern als
     „sitzt nicht mittig"**, und genau so ist sie zweimal gemeldet worden.

     Der Kasten ist größer als der sichtbare Inhalt, weil die Dateien ringsum
     durchsichtigen Rand tragen — sie füllen nur 68,8 % (Drucker), 75,0 %
     (Filament) und 85,4 % (Resin). Bei 2.2em heißt das sichtbar 39 / 43 /
     49px; die Flasche als höchste der drei füllt damit rund die Hälfte der
     96px hohen Leiste. Gegen den Sollzustand geprüft: dort mißt sie 0,56 der
     Leistenhöhe, hier 0,51 — gleich innerhalb der Ablesegenauigkeit eines
     Bildschirmabzugs.
     Die Breite ist unkritisch: Das schmalste Wort ab 768px ist „Resine" mit
     58,7px Text in einem 82,7px breiten Kasten; die Grafik überragt ihn
     seitlich, und weil sie hinter dem Text liegt und nichts abfängt, stört
     das die Nachbarn nicht — die Lücke zwischen den Einträgen ist
     --abstand-3xl. */
  /* ⛔ NICHT MEHR 2.2em (03.09.2026) — UND DAS IST KEINE GRÖSSENÄNDERUNG,
     SONDERN IHR GEGENTEIL. Die Grafik hing als em an der Schriftgröße der
     Links, und die ist von 26 auf 18px (bzw. 20 auf 16px) gefallen. Bei
     festem Faktor wäre sie lautlos von 57,19 auf 39,3px geschrumpft — eine
     Änderung, die niemand beauftragt hat und die man einer Wasserzeichen-
     grafik nicht ansieht, weil ihr der Vergleichsmaßstab fehlt.

     Der Faktor steht deshalb je Schriftstufe als --kategorie-grafik da und
     ist so gewählt, daß dasselbe PIXELMASS herauskommt wie vorher:

       ab 1024px    3.177em × 18px = 57,19px   (vorher 2.2em × 26px)
       768–1023px   2.75em  × 16px = 44,00px   (vorher 2.2em × 20px)
       unter 768px  keine Grafik (content: none, siehe dort)

     ⚠️ WARUM WEITER IN em UND NICHT IN px. Der Wert bleibt an die Schrift
     gekoppelt, also bleibt der Zusammenhang sichtbar, den man beim nächsten
     Umbau kennen muß: Wer die Schriftgröße anfaßt, sieht den Faktor daneben
     stehen. Eine feste Pixelzahl verlöre genau diese Kopplung und damit den
     Hinweis. */
  width: var(--kategorie-grafik);
  height: var(--kategorie-grafik);
  background-color: currentColor;
  /* Sie ist Grund, nicht Zeichen: Bei 0,12 stand sie mit der Beschriftung in
     Konkurrenz — einzelne Striche stachen als Fragmente hervor und wurden dann
     als eine neben dem Wort sitzende Grafik gelesen, obwohl sie waagerecht
     gemessen auf 0,0px auf der Wortmitte sitzt. 0,05 war die Gegenprobe und im
     Dunkelmodus nahezu unsichtbar, 0,07 der Zwischenstand; 0,14 ist der Stand,
     seit die senkrechte Lage stimmt und die Grafik nicht mehr als Fragment
     unter dem Wort hervorsteht. */
  opacity: 0.14;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  /* Sie liegt hinter dem Text und darf nichts abfangen — die Trefferfläche des
     Links bleibt genau die, die sie ohne Grafik war. */
  pointer-events: none;
  /* Ohne eigene Übergangsliste spränge sie beim Wechsel hart, während Textfarbe
     und Kante daneben in 120ms gleiten. */
  transition:
    opacity var(--dauer-kurz) ease,
    background-color var(--dauer-kurz) ease;
}

/* ⚠️ Der Pfad ist relativ zu DIESER Datei: url() in einem Stylesheet löst gegen
   das Stylesheet auf, nicht gegen die Adresse der Seite. Die zweiteiligen Routen
   (/filament/<slug>-<id>), an denen die relativen Verweise in index.html am
   11.08.2026 gescheitert sind, sind hier deshalb kein Thema. Gleiche
   Schreibweise wie seiten.css. */
.kategorie-ziel[data-ziel="liste"]::after {
  -webkit-mask-image: url("../assets/kategorie-filament.svg");
  mask-image: url("../assets/kategorie-filament.svg");
}
.kategorie-ziel[data-ziel="resin"]::after {
  -webkit-mask-image: url("../assets/kategorie-resin.svg");
  mask-image: url("../assets/kategorie-resin.svg");
}
.kategorie-ziel[data-ziel="drucker"]::after {
  -webkit-mask-image: url("../assets/kategorie-drucker.svg");
  mask-image: url("../assets/kategorie-drucker.svg");
}
/* ⚠️ Der Reiter „Wissen" entfällt unter 768px (display: none am <li>, siehe
   CLAUDE.md „Kategoriereiter"), die Grafik ebenfalls (content: none weiter
   unten). Beide Grenzen liegen bei 768px — das ist kein Zufall, sondern
   dieselbe Entscheidung: Wo der Reiter fehlt, gibt es nichts zu hinterlegen.
   Wer den Reiter auf schmale Fenster zurückholt, prüft die Grafik dort mit.
   ⚠️ „Wissen" hat wie die drei anderen Wörter keine Unterlänge — die Bedingung,
   an der der translateY-Versatz oben hängt, gilt also weiter. */
.kategorie-ziel[data-ziel="wissen"]::after {
  -webkit-mask-image: url("../assets/kategorie-wissen.svg");
  mask-image: url("../assets/kategorie-wissen.svg");
}

/* Die aktive Kategorie zeigt ihre Grafik kräftiger. Sie wechselt dabei zugleich
   auf --primary, weil currentColor mitgeht — Stärke und Farbe sagen dasselbe.
   ⚠️ Gleiche Spezifität wie die Sammelregel oben, es entscheidet also die
   Reihenfolge: Diese Regel muß dahinter stehen. */
.kategorie-ziel[aria-current="page"]::after { opacity: 0.20; }

/* Ohne Maskenunterstützung bliebe von der Grafik die blanke Fläche übrig — ein
   Farbrechteck hinter dem Wort. Dann lieber nichts: Sie ist Zierde, der Link
   trägt seine Aussage im Text. */
@supports not ((mask-image: url("../assets/kategorie-filament.svg")) or
               (-webkit-mask-image: url("../assets/kategorie-filament.svg"))) {
  .kategorie-ziel::after { content: none; }
}

/* ---------- Kategorien: enger auf schmalen Fenstern ----------

   ⛔ DIESE REGELN MÜSSEN HINTER DEN GRUNDREGELN STEHEN, und das ist keine
   Stilfrage: `.kategorienav` und `.kategorie-ziel` wiegen hier genauso viel
   wie oben — eine Medienabfrage erhöht die Spezifität NICHT. Es entscheidet
   allein die Reihenfolge im Stylesheet.

   Bis zum 10.08.2026 standen sie im Kopfleisten-Abschnitt weit oben, also VOR
   den Grundregeln — und haben deshalb nie gegriffen. Gemessen bei 885px
   Fensterbreite: Lücke 64px und Schrift 26px, also unverändert die Werte für
   breite Fenster, obwohl die Medienabfrage seit dem 07.08.2026 etwas anderes
   vorsah. Aufgefallen ist es erst, als die Marke in dieselbe Zeile rückte und
   die zu breite Reihe mit ihr kollidierte.

   Zwei Stufen: ab 1024px abwärts enger, ab 640px abwärts die Drittel-Aufteilung
   weiter unten. */
@media (max-width: 1023px) {
  /* Engere Lücke UND schmalere Innenabstände. Die Schriftgröße bleibt eine
     Stufe unter der großen Fassung; sie trägt die Lesbarkeit der
     Hauptnavigation und ist das Letzte, woran gespart wird. */
  /* ⚠️ Am KOPF und nicht am Eintrag: Der Rand der Reihe rechnet dasselbe
     Polster mit, damit die Marke mittig bleibt (siehe --marken-luft). */
  .kopfzeile { --kategorie-polster: var(--abstand-s); }
  .kategorienav { gap: var(--abstand-l); }
  .kategorie-ziel {
    /* Eine Stufe unter der breiten Fassung, wie eh und je — nur beide Stufen
       tiefer als vor dem 03.09.2026 (war 20px). */
    font-size: var(--title-small);
    /* Nachgezogen: 2.75em × 16px = 44px, exakt das Maß der früheren
       2.2em × 20px. Siehe .kategorie-ziel::after. */
    --kategorie-grafik: 2.75em;
  }
}

/* ═══════════ ZWEI ZEILEN AUF SCHMALEN FENSTERN (13.08.2026) ═══════════

   Zeile 1   Marke links · Druckerwähler und Burger rechts
   Zeile 2   Filament · Resine · Drucker als drei gleich breite Schaltflächen

   Vorbild ist die Kopfzeile der App: die aktive Kategorie als gefüllte Fläche
   mit Häkchen, die übrigen als umrandete Flächen.

   ⛔ DIE GRENZE IST 767px, UND SIE IST GEMESSEN — nicht der Punkt, an dem es
   bricht, sondern mit Abstand davor.

   Gemessen im Rahmen gegen genau diese Stylesheets, Luft zwischen der Marke
   und der HÜLLE der Kategorielinks (nicht dem Kasten der Reihe — der
   schrumpft, seine Links tun es nicht):

     768px  +50,5     700px  +26,7     680px  +16,7     660px   +6,7
     650px   +1,7     647px   +0,2     646px   −0,3     640px   −3,3

   Die Bruchstelle liegt bei 646px. 767px läßt 121px Reserve und ist zugleich
   eine Zahl, die hier schon stand (die Schriftstufe der Marke) — ein eigens
   erfundener Wert um 680 wäre eine Zahl mehr, die niemand nachrechnen kann.
   Die letzte einzeilige Breite behält damit 50,5px Luft; die Zeile läuft nie
   knapper als das.

   ⚠️ WARUM DIE FRÜHERE MESSUNG +4,2px MELDETE, WO −3,3px STEHEN. Der
   Unterschied ist genau ein halber Rollbalken, und das ist kein Zufall:
   Medienabfragen vergleichen in Blink gegen die Fensterbreite EINSCHLIESSLICH
   des klassischen Rollbalkens, das Layout bekommt aber nur die Breite ohne
   ihn. Bei 640px Fenster gilt also noch die einzeilige Fassung, während für
   sie nur 625px da sind. Nachgemessen, dieselbe Leiste:

     Fenster 640px, Seite rollt nicht   Sicht 640   Luft +4,2
     Fenster 640px, Seite rollt         Sicht 625   Luft −3,3

   Die alte Zahl war für eine Prüfseite richtig, die nicht rollt, und für
   jede Liste falsch. Wer hier nachmißt, läßt die Seite rollen.

   ⚠️ Und darunter war es nicht besser, nur anders: Ab 640px stand alles im
   Fluss, die drei Kategorien teilten sich den Rest OHNE Lücke (gemessen 0,0px
   zwischen den Beschriftungen) und liefen bei zu wenig Platz beidseitig aus
   ihrem Kasten — gemessen 8px je Seite bei 360px, 15,4px bei 320px. Rechts
   fiel der Anschnitt genau dort, wo der Druckerwähler steht: „Drucker" wurde
   zu „Druck…", und das las sich als Überlappung. Beides ist mit den beiden
   Zeilen erledigt, nicht gemildert. */
/* ==================================================================
   UNTER 900px: DIE LUPE ÜBERNIMMT
   ==================================================================

   ⛔ DIE SCHWELLE IST GEMESSEN, NICHT GEWÄHLT — und sie liegt bewusst NICHT
   auf 767px, wo die Zeile zweizeilig wird. Was das Feld unbedienbar macht,
   ist nicht die Zeilenzahl, sondern seine Breite. Gemessen an der laufenden
   Seite, was von der Zeile für das Feld übrigbleibt:

     1440px → 590px    1024px → 174px
     1280px → 430px     900px → 206px
     1100px → 250px     800px → 106px
                        768px →  74px

   Bei 74px bleiben nach Lupe, Polsterung und Lücke rund 26px für den Text —
   ein Feld, in dem man tippen kann, ohne zu sehen, was man tippt. Ab 900px
   sind es 206px und damit gut 25 Zeichen.

   ⚠️ Der Sprung bei 900px im Zahlenbild (174 → 206) ist kein Fehler: Bei
   1023px fallen Gerätename und Statuspunkt weg, die Pille wird schmaler und
   gibt ihren Platz an das Feld ab. Die engste Lage der einzeiligen Fassung
   ist deshalb 1024px, nicht 768px.

   Der Lupenknopf klappt DASSELBE Feld als Blatt unter der Leiste auf — ein
   Feld, zwei Darstellungen, entschieden allein hier im CSS. Die Verdrahtung
   in js/kopfsuche.js kennt nur „auf" und „zu". */
@media (max-width: 899px) {
/* ---------- Die Suche als Blatt unter der Leiste ----------

   Dasselbe Feld, dieselbe Verdrahtung — nur an anderer Stelle. Der
   Lupenknopf klappt es auf, Escape und jede Auswahl klappen es zu
   (js/app.js).

   ⛔ `display: none` ist hier RICHTIG, obwohl es die Fokussierbarkeit nimmt.
   Der Weg verschließt sich damit nicht: Der Lupenknopf steht in der Zeile
   und ist immer erreichbar. Das ist der Unterschied zur rechten
   Hauptleiste, wo `visibility: hidden` verboten ist (14.08.2026) — dort
   wäre der einzige Weg zum Aufklappen selbst unfokussierbar geworden. */
.suchlupe {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* ⚠️ Sie tritt an die Stelle des Feldes und übernimmt damit auch dessen
     Platz in der Zeile: Zwischen 768 und 899px steht sie im Fluss und würde
     ohne den Automatik-Rand an den Kategorien kleben statt bei den
     Werkzeugen. Unter 768px ist sie ein Rasterkind in einer auto-Spalte —
     dort tut der Rand nichts. */
  margin-left: auto;
  /* 40px statt 44px: Der Burger daneben ist das dokumentierte Mindestmaß
     der Zeile und soll das größte Ziel bleiben. 40px liegen weit über den
     24px aus WCAG 2.5.8. */
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pille);
  background: none;
  color: var(--on-surface-variant);
  cursor: pointer;
}
.suchlupe:hover { background: var(--zustand-hover); color: var(--on-surface); }
.suchlupe svg { width: 22px; height: 22px; }

.kopfsuche {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  max-width: none;
  margin: 0;
  padding: var(--abstand-s);
  background: var(--surface-container-high);
  border-bottom: 1px solid var(--outline-variant);
  box-shadow: var(--schatten-schwebend);
  /* Über der Kategoriezeile, die unter 768px im Raster darunter liegt. */
  z-index: 4;
}
.kopfsuche[data-offen="ja"] { display: block; }
/* Im Blatt ist die volle Breite da — das Feld behält seine Ruhehöhe, statt
   mit der Leiste zu schrumpfen: Es steht ohnehin außerhalb von ihr. */
.kopfsuche-form { height: 40px; }
.kopfsuche-blatt {
  /* Es sitzt jetzt im Blatt, nicht mehr unter einer Pille in der Zeile —
     der Abstand ist der Innenabstand des Blatts, kein zweiter. */
  top: calc(100% + var(--abstand-s));
  max-height: min(60vh, 420px);
}
}

@media (max-width: 767px) {
  .kopfzeile {
    /* ⛔ AUCH HIER KEINE EIGENE MARKENGRÖSSE MEHR (07.09.2026) — siehe die
       Begründung im 1023px-Zweig. Die Marke steht in dieser Fassung allein in
       ihrer Zeile und hat dort selbst bei 320px reichlich Platz (gemessen). */

    /* ⛔ KEINE UNTERSTREICHUNG IN DIESER FASSUNG. Der aktive Eintrag ist
       hier eine gefüllte Pille (siehe unten), und die Kategorien stehen in
       einer eigenen Zeile — es gibt weder eine Kante, die die Schrift
       versetzt, noch eine Marke daneben, die ihr folgen müsste. Auf 0
       gesetzt statt einzeln zurückgenommen: Beide Leser (die Kante des
       Eintrags und der untere Rand der Marke) sind damit in einem Zug
       erledigt, und ein dritter, der später dazukommt, von selbst mit. */
    --kategorie-unterstrich: 0px;

    /* ---------- Die beiden Zeilenhöhen ----------

       ⛔ FESTE WERTE SEIT DEM 22.09.2026. Hier standen vier Zahlen — je
       Zeile ein großer und ein kompakter Endwert, dazwischen linear über
       --kopf-fortschritt geteilt. Mit dem Schrumpfen der Leiste sind die
       kompakten Endwerte entfallen; geblieben sind die großen.

       Die Untergrenze der ERSTEN Zeile ist weiterhin der 44px hohe Burger,
       56px lassen ihm 6px auf jeder Seite. Die zweite Zeile trägt nur die
       Schaltflächen (rund 20px hoch) und ist darin frei; eine
       Kategoriegrafik gibt es hier nicht (content: none), sie kann also
       auch nichts begrenzen.

       ⚠️ Beide zusammen ergeben 100px — die Leiste ist auf dem Handy die
       höchste Fassung und bleibt es jetzt auf jeder Rollhöhe. */
    --kopfreihe-marke: 56px;
    --kopfreihe-kategorien: 44px;
  }

  /* ⚠️ RASTER statt Fluss, und die Plätze stehen ausdrücklich da. Im Fluss
     müßte die Reihenfolge über `order` gedreht werden, weil die Kategorien im
     Markup VOR den Werkzeugen stehen — dann hinge die Anordnung an einer Zahl,
     die man beim nächsten Eintrag mitzählen muß. Mit `grid-column`/`grid-row`
     steht jede Gruppe an ihrem Platz, gleich wo sie im Markup steht.

     ⛔ height: auto — die Höhe kommt jetzt aus den beiden Zeilen. Bliebe die
     Rechnung der EINEN Zeile stehen, ragte die zweite unten heraus. */
  .kopfzeile-inhalt {
    display: grid;
    /* ⛔ VIER Spalten seit dem 03.09.2026 — die zweite gehört dem Lupenknopf.
       Er ersetzt hier das Suchfeld, für das in einer 320px-Zeile neben Marke,
       Wähler und Burger kein Platz ist; eine dritte Zeile wäre die
       naheliegende Alternative und machte die Leiste auf dem Handy zu hoch
       (Entscheidung vom 03.09.2026). */
    grid-template-columns: 1fr auto auto auto;
    grid-template-rows: var(--kopfreihe-marke) var(--kopfreihe-kategorien);
    align-items: center;
    height: auto;
    column-gap: var(--abstand-xs);
    padding-inline: var(--abstand-s);
  }

  /* Aus dem Fluss in die Rasterplätze. Die Mittigkeit der Kategorien auf der
     SEITENbreite gibt es hier ohnehin nicht: Sie haben eine eigene Zeile und
     füllen sie ganz — mittig ist dort alles. */
  /* ⚠️ justify-self: start ist Pflicht. Als Rasterzelle der 1fr-Spalte zöge
     sich die Marke sonst über die ganze Restbreite — sie ist ein <a>, und ein
     Klick weit rechts neben dem Schriftzug führte auf die Startseite. */
  .kopfzeile-inhalt .marke { grid-column: 1; grid-row: 1; justify-self: start; }
  .kopfzeile-inhalt .suchlupe { grid-column: 2; grid-row: 1; }
  /* ⛔ `position: static` ist hier PFLICHT und keine Aufräumarbeit. Damit
     verliert das Druckermenü seinen Bezugsrahmen und hängt sich an
     `.kopfzeile-inhalt` — es öffnet dadurch unter der GANZEN Leiste statt am
     Knopf. Am Wähler verankert läge es über der Kategoriezeile darunter
     (gemessen am 13.08.2026 bei 767 bis 320px). */
  .kopfzeile-inhalt .druckerauswahl {
    position: static;
    grid-column: 3;
    grid-row: 1;
    max-width: none;
  }
  .kopfzeile-inhalt .burger { grid-column: 4; grid-row: 1; }

  /* ---------- Zeile 2: drei gleich breite Pillen ----------

     ⛔ DER REITER „WISSEN" ENTFÄLLT HIER GANZ (18.09.2026, Bildvorlage).

     `display: none` und nicht `visibility: hidden`: Er soll auch keinen
     Tabstopp mehr tragen — ein unsichtbarer vierter Reiter, den nur die
     Tastatur findet, wäre schlechter als gar keiner.

     ⛔ SEIN WEG IST NICHT VERLOREN: Die rechte Hauptleiste führt unter 768px
     einen Eintrag „Wissen" (index.html, `.hl-nur-schmal`), der am Desktop
     ausgeblendet ist. Je Breite genau eine Stelle. Wer diese Regel hier
     einsetzt und den Leisteneintrag vergisst, macht /wissen auf dem Handy
     unerreichbar — die Seite bleibt bestehen und sieht richtig aus, es führt
     nur nichts mehr hin. */
  .kategorie-ziel[data-ziel="wissen"] { display: none; }

  .kategorienav {
    grid-column: 1 / -1;
    grid-row: 2;
    /* ⛔ KEIN Rand — und das ist eine BERICHTIGUNG (22.09.2026).

       Die Grundregel trägt einen linken Rand, der die Marke in der EINEN
       Zeile mittig hält (siehe --marken-luft). Hier gibt es nichts mittig
       zu halten: Die Reihe hat ihre eigene Zeile und füllt sie ganz. Der
       Rand stand bis hierher unbemerkt mit und schob die drei Pillen um
       40px nach rechts — links 48px Luft, rechts 8px. Aufgefallen ist es
       erst, als der Rand mit dem Zentrieren der Marke seinen Wert änderte
       und die Asymmetrie mit ihm. */
    margin-left: 0;
    display: grid;
    /* minmax(0, 1fr) statt 1fr: Eine Rasterspur wird von sich aus nie
       schmaler als ihr Inhalt — mit blankem 1fr drückte die längste
       Beschriftung die drei Spuren auseinander, und „gleich breit" wäre eine
       Behauptung. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    /* ⛔ FESTE Lücke und Luft (22.09.2026). Sie folgten dem Rollfortschritt
       und rückten beim Rollen zusammen; mit ihm sind sie fest geworden.
       Die Werkzeugzeile der Liste darunter schrumpft weiterhin — sie hängt
       an --werkzeug-roll und nie an der Kopfleiste. */
    gap: var(--abstand-s);
    align-self: stretch;
    padding-block: var(--abstand-xs);
    /* Sie passen jetzt — das Schieben der einzeiligen Fassung entfällt.
       ⚠️ Es MUSS entfallen: Ein Scroll-Kontext schnitte die Schaltflächen an
       ihren Rundungen ab, und der aktive Chip verlöre seine Kante. */
    overflow: visible;
  }

  .kategorie-ziel {
    justify-content: center;
    gap: var(--abstand-xs);
    min-width: 0;
    /* ⛔ DIE PILLE FÜLLT IHRE ZEILE (18.09.2026, Bildvorlage).

       Sie war rund 20px hoch in einer 44–52px hohen Zeile und saß darin als
       schmaler Streifen. Gestreckt ist sie zugleich ein Tippziel von über
       40px Höhe — weit über den 24px aus WCAG 2.5.8 und ohne dass die Zeile
       dafür wachsen müsste.

       ⚠️ `align-self` am Kind und NICHT `align-items: stretch` am Raster: Die
       Grundregel `.kategorienav` setzt `align-items: center`, und eine
       Medienabfrage erhöht die Spezifität nicht — am Raster gesetzt gewänne
       je nach Reihenfolge in der Datei mal das eine, mal das andere. Am Kind
       gibt es diese Frage nicht. */
    align-self: stretch;
    /* ⛔ 2px statt 4px seit dem 03.09.2026, und das ist gerechnet: Mit dem
       vierten Eintrag teilen sich vier Spuren die Breite, die vorher drei
       hatten. Bei 320px sind das 66px statt 91px je Spur, und das aktive
       „Filament" braucht samt Häkchen und Lücke 70px — es lief also über,
       und zwar unsichtbar, weil der Chip beschneidet. Mit 2px Polsterung
       sinkt der Bedarf auf 66px, mit der engeren Lücke unten stehen 69px zur
       Verfügung. */
    /* Mit drei Spuren statt vier ist wieder Platz: Bei 320px sichtbarer
       Breite misst eine Spur 91px statt 66px, „Filament" braucht bei 16px
       63px. 8px Polsterung je Seite passen damit mit Reserve — vorher waren
       hier 2px nötig, und das sah aus wie Platznot, weil es welche war. */
    padding: 0 var(--abstand-s);
    /* 16px statt 20px: Bei 320px ist eine Spur 96px breit, davon bleiben nach
       Rand und Innenabstand 86px. „Filament" mißt dort 63px, mit Häkchen und
       Lücke 76px — es paßt, und zwar mit Reserve. 20px sprengten es.
       ⛔ FEST seit dem 22.09.2026: Sie ging beim Rollen auf 14px zurück,
       und mit dem Schrumpfen der Leiste ist auch das entfallen. */
    font-size: var(--title-small);
    /* ⛔ Die Kante ist die Grenze des Bedienelements (WCAG 1.4.11) und ersetzt
       die Unterstreichung der breiten Fassung. --outline, nicht
       --outline-variant: gemessen 5,03:1 gegen die Fläche der Kopfleiste
       gegenüber 1,7:1. */
    border: 1px solid var(--outline);
    border-radius: var(--radius-pille);
    color: var(--on-surface);
  }

  /* ⛔ Hier trägt keine Kategorie eine Grafik. Der Knopf ist in dieser Fassung
     nur rund 20px hoch — er wird im Raster nicht gestreckt (align-items: center
     der Grundregel gilt weiter) —, und bei 320px bleiben in einer 91px breiten
     Spur neben dem aktiven „Filament" samt Häkchen noch 7,7px übrig. Hinter das
     Wort gequetscht wäre sie kein Schmuck mehr, sondern Unruhe.
     Der aktive Eintrag trägt hier ohnehin eine deckende Chipfläche
     (--secondary-container), hinter der von ihr nichts zu sehen wäre.
     `content: none` statt `display: none`: Das Pseudoelement entsteht so gar
     nicht erst.

     ⛔ Die vier Kategorien müssen hier EINZELN stehen, so wie oben. Ein
     schlichtes `.kategorie-ziel::after` wiegt (0,1,0) und verliert gegen die
     Attributselektoren der Grundregel (0,2,0) — die Medienabfrage ändert daran
     nichts, sie erhöht die Spezifität NICHT. Beim Bauen genau so passiert: Die
     Grafik stand unter 768px weiterhin da, 25,6px hoch in einem 20,4px hohen
     Knopf, und der Fehler war im Bild kaum zu sehen. Gefunden hat ihn erst die
     Messung von getComputedStyle(link, "::after"). */
  /* ⚠️ „Wissen" steht hier mit, obwohl sein Reiter unter 768px ohnehin
     display: none trägt (siehe dort) — die Zeile ist damit heute wirkungslos.
     Sie steht trotzdem da: Die Abschaltung ist die Spiegelung der Grundregel,
     und eine Liste, die drei von vier Kategorien nennt, sieht vollständig aus.
     Käme der Reiter auf schmale Fenster zurück, brächte er sonst eine 25,6px
     hohe Grafik in einen 20,4px hohen Knopf mit. */
  .kategorie-ziel[data-ziel="liste"]::after,
  .kategorie-ziel[data-ziel="resin"]::after,
  .kategorie-ziel[data-ziel="drucker"]::after,
  .kategorie-ziel[data-ziel="wissen"]::after { content: none; }

  /* ⛔ DIESELBE Auszeichnung wie beim Filter-Chip (komponenten.css): Füllung
     aus --secondary-container, Rand im Vollton derselben Rolle, davor das
     Häkchen. Nicht neu erfunden, sondern übernommen — zwei Auswahlen, die
     dasselbe sagen, sollen nicht verschieden aussehen.

     Der Rand BLEIBT stehen und wird eingefärbt, statt zu verschwinden: Sonst
     hätte der gewählte Eintrag weniger erkennbare Form als der nicht
     gewählte, dessen Kante bei 5,03:1 steht. Das Häkchen trägt die Aussage
     ohne Farbe, der Rand die Grenze. */
  /* ⛔ DIE AKTIVE PILLE TRÄGT DIE AKZENTFARBE IM VOLLTON (18.09.2026,
     Bildvorlage) — vorher die gedämpfte Containerstufe derselben Rolle.

     ⛔ DAS HÄKCHEN IST DAMIT ENTFALLEN, und das nimmt die Regel „Farbe allein
     trägt keine Aussage" nicht zurück, sondern erfüllt sie anders: Die
     gewählte Pille ist die einzige mit einer FÜLLUNG, die übrigen sind
     Konturen. Das ist ein Unterschied der Form und bleibt auch ohne
     Farbwahrnehmung sichtbar — das Häkchen war dafür die richtige Antwort,
     solange sich beide Zustände nur im Farbton unterschieden.

     ⚠️ `aria-current="page"` bleibt unberührt. Es ist das, was eine
     Vorlesehilfe liest, und hing nie am Häkchen. */
  .kategorie-ziel[aria-current="page"] {
    background: var(--secondary);
    color: var(--on-secondary);
    border-color: var(--secondary);
    font-weight: 600;
  }
}

/* ⚠️ HIER STAND BIS ZUM 18.09.2026 EIN 400px-BLOCK, der Lücke und Schrift
   der Kategoriezeile noch einmal verkleinerte. Sein Gegenstand war der VIERTE
   Reiter: Mit ihm teilten sich vier Spuren die 289px, die bei 320px zur
   Verfügung stehen, und dem aktiven „Filament" samt Häkchen blieben 66,25px —
   ein Viertelpixel Reserve, also keine.

   Seit „Wissen" mobil entfällt, sind es DREI Spuren zu 91px, und das Häkchen
   ist mit der gefüllten Pille gegenstandslos geworden. Die Enge, die der
   Block behob, gibt es nicht mehr; wer ihn zurückholt, verkleinert ohne
   Anlass. */

/* ---------- Rechte Hauptleiste (06.08.2026) ----------

   Sie ersetzt die frühere untere Leiste des Handys UND die Ziele der
   Kopfzeile. EIN Zustand (data-leiste am <html>), drei Darstellungen:

     ab 640px, „zu"     schmale Spalte, nur Symbole
     ab 640px, „offen"  dieselbe Spalte mit Beschriftung
     unter 640px        Menü über die volle Höhe, das der Burger einfährt

   ⚠️ ZWEI Breiten, und der Unterschied ist der Punkt (07.08./06.08.2026):

     --leiste-schmal   die dauerhafte Icon-Spalte — NUR sie bekommt Platz
                       im Layout (padding am <body>)
     --leiste-breite   die tatsächliche Breite der Leiste im Moment

   Die ausgefahrene Leiste LEGT SICH ÜBER den Inhalt, statt ihn zur Seite zu
   drücken. Vorher las das <body>-Padding die dynamische Breite mit — beim
   Auf- und Zuklappen floss der gesamte Seiteninhalt um 164px hin und her,
   und jede Zeile brach neu um. Eine Leiste, die man kurz aufklappt, um ein
   Ziel zu wählen, darf die Seite dahinter nicht umbauen. */

:root {
  --leiste-schmal: 60px;
  --leiste-breite: var(--leiste-schmal);
}
:root[data-leiste="offen"] { --leiste-breite: 224px; }

/* Der Inhalt endet dort, wo die SCHMALE Spalte beginnt — fest, ohne
   Übergang: Dieser Wert ändert sich im Betrieb nie mehr. Am <body> statt an
   <main>, weil auch Fußbereich und Testmodus-Band betroffen sind.

   ⛔ BEIDSEITIG, und das ist keine Verschwendung, sondern die Mitte
   (08.08.2026). Bis dahin stand hier nur `padding-right`. Die Folge war
   nicht etwa ein um 60px schmalerer Inhalt, sondern ein SCHIEFER: Der
   Inhaltskasten begann am linken Fensterrand und endete 60px vor dem
   rechten. Gemessen bei 1285px Fensterbreite, quer über alle Ansichten —
   Startseite, Filament-, Harz- und Druckerliste, Vergleich, Infos, Über —
   ausnahmslos **links 16px, rechts 76px**. Die Differenz war exakt
   --leiste-schmal, an jeder einzelnen Stelle.

   Die Icon-Spalte ist eine sichtbare Fläche am rechten Rand. Ihr Platz muss
   links gespiegelt werden, sonst ist „mittig" die Mitte des Restplatzes und
   nicht die der Seite — derselbe Fehler, den die Kopfleiste über ihr
   negatives margin-right vermeidet (siehe dort). Der Preis sind 60px
   Inhaltsbreite; der Gewinn ist, dass jede Ansicht der Seite auf derselben
   Achse steht wie die Wortmarke darüber. */
body { padding-inline: var(--leiste-schmal); }

.hauptleiste {
  position: fixed;
  /* Unter der Kopfleiste, deren Höhe js/app.js an --kopf-hoehe fortschreibt.
     Ein fester Wert liefe beim kompakten Zustand aus dem Tritt. */
  top: var(--kopf-hoehe);
  /* ⚠️ Nicht schlicht 0: Solange ein Overlay offen ist, sperrt
     `:root[data-modal="offen"]` das Rollen der Seite, und dabei verschwindet
     der klassische Rollbalken. Das Sichtfenster wird um dessen Breite
     BREITER — und ein fest am rechten Rand verankertes Element wandert mit,
     weil sein Bezugsrahmen das Sichtfenster ist und nicht der Inhaltskasten
     der Wurzel (den gleicht dort das padding-right aus). Gemessen sprang die
     Leiste bei 900px Fensterbreite um 15px nach rechts, hinter dem Schleier
     sichtbar. Dieselbe Variable hält sie an Ort und Stelle; ohne Overlay ist
     sie nicht gesetzt und der Rückfall 0px gilt. */
  right: var(--modal-rollbalken, 0px);
  bottom: 0;
  /* Unter der Kopfzeile (50), über der schwebenden Vergleichsleiste (40):
     Das Druckermenü der Kopfzeile fährt über die Leiste hinweg aus. */
  z-index: 45;
  width: var(--leiste-breite);
  background: var(--surface);
  border-left: 1px solid var(--outline-variant);
  /* ⚠️ KEIN overflow-y: auto in der Spalte. Ein Scroll-Kontext macht auch die
     Querrichtung zum Zuschnitt (visible neben auto gibt es nicht), und das
     Währungsmenü fährt aus der 60px-Spalte heraus nach links — es wäre bis
     auf einen Streifen abgeschnitten. Die sieben Einträge (~330px) passen
     senkrecht auf jedes reale Gerät; rollbar ist nur die Handy-Darstellung,
     in der das Menü innerhalb der Fläche bleibt (siehe unten). */
  overflow: visible;
  transition:
    width var(--dauer-mittel) ease,
    box-shadow var(--dauer-mittel) ease,
    opacity var(--dauer-mittel) ease;
}

/* ---------- Ab 640px: eine KURZE Fläche statt voller Höhe (14.08.2026) ----------

   Die Fläche reichte bis zum Fensterboden, obwohl die sieben Symbole nur ihr
   oberes Drittel brauchen. Jetzt umschließt sie die Symbolgruppe und hört
   darüber wie darunter auf.

   ⛔ `bottom: auto` IST die ganze Änderung an der Höhe. Die Grundregel setzt
   `top` UND `bottom`, und zwei gegenüberliegende Kanten bestimmen die Höhe
   zusammen — der Inhalt hat dann nichts mehr zu sagen. Mit `bottom: auto`
   entscheidet wieder der Inhalt, und die Gruppe sitzt unverändert an
   derselben Stelle: `top` bleibt `var(--kopf-hoehe)`, die Symbole rücken
   keinen Pixel.

   ⚠️ NUR ab 640px. Darunter ist die Leiste ein Menü über die volle Höhe, das
   der Burger einfährt — dort MUSS `bottom: 0` bleiben. Deshalb steht das hier
   als eigener Zweig und nicht in der Grundregel.

   ⛔ SIE BRAUCHT EINE EIGENE FLÄCHE, sonst ist sie nach dem Kürzen unsichtbar.
   `--surface` und `--background` sind in BEIDEN Schemata derselbe Wert
   (#DCDFE9 hell, #0F1115 dunkel) — die Leiste war bisher gar nicht durch ihre
   Fläche zu erkennen, sondern allein durch die Trennlinie links. Nimmt man
   die Linie weg und kürzt die Fläche, bliebe eine Symbolgruppe ohne alles.

   ⛔ UND ZWAR `--surface-container-HIGH`, nicht die Kartenstufe. Gemessen,
   nicht gewählt — es ist derselbe Fall wie bei der Kopfleiste am 10.08.2026,
   und die Zahlen sind dieselben:

                              hell      dunkel
     --surface-container     1,20:1    1,10:1   ← dunkel unter der Schwelle
     --surface-container-high 1,29:1   1,24:1

   Unterhalb von etwa 1,15:1 ist eine Fläche ohne Rahmen nicht mehr
   wahrnehmbar. Die Kartenstufe kommt im Dunkelmodus nicht darüber, und dort
   steht `--karten-kante` auf `none` — die Fläche hätte also weder Stufe noch
   Kante und wäre genau das wieder, was sie vorher war: unsichtbar. Eine
   Leiste, die man nur im hellen Schema sieht, erfüllt die Anforderung nicht.
   Beim ersten Bauen stand hier die Kartenstufe und ist an dieser Messung
   gescheitert.

   ⛔ DIE TRENNLINIE ENTFÄLLT, und das ist eine Entscheidung, keine
   Auslassung. Ein `border-left` war die richtige Antwort für eine Spalte, die
   vom Fensterdach bis zum Boden lief: Sie hatte keine eigene Gestalt, also
   brauchte sie eine Kante gegen den Inhalt. Eine kurze, gerundete Fläche mit
   eigenem Grund HAT eine Gestalt — die Linie liefe an ihr nur noch auf einem
   Teilstück entlang und läse sich als Rest. An ihre Stelle tritt
   `--karten-kante`, dieselbe Haarlinie samt weichen Schatten, mit der jede
   Karte des Projekts im Hellmodus ihre Grenze zeigt (im Dunkelmodus steht sie
   auf `none`, dort trägt die Flächenstufe allein).

   ⚠️ Nicht in die Sammelliste in css/komponenten.css eintragen: Die gilt
   ohne Breitenbedingung und träfe damit auch das Handy-Menü, das seine volle
   Höhe und seine Trennlinie behält.

   ⚠️ Nur die LINKEN Ecken sind gerundet. Die Fläche schließt bündig mit dem
   Fensterrand ab — eine Rundung rechts ließe dort einen Spalt stehen, in dem
   die Seite durchscheint. So bleibt sie ein Element, das am Rand ansetzt,
   und die Symbole behalten ihre Lage auf den Pixel. */
@media (min-width: 640px) {
  .hauptleiste {
    bottom: auto;
    background: var(--surface-container-high);
    border-left: 0;
    border-radius: var(--radius-m) 0 0 var(--radius-m);
    box-shadow: var(--karten-kante);
  }
}

/* Ausgefahren ist die Leiste eine ÜBERLAGERUNG — sie liegt über dem Inhalt,
   der seine Breite behält. Der Schatten folgt der Projektregel „Schatten nur
   für echte Überlagerungen": Die schmale Spalte ist Teil des Gerüsts und
   trägt keinen; die breite schwebt und braucht die Kante zum Inhalt darunter.
   Über dem Inhalt (und der Vergleichsleiste, 40), unter Overlays/Sheets (60),
   Snackbar (70) und Ladeoverlay (80) — der z-index 45 oben leistet das. */
:root[data-leiste="offen"] .hauptleiste {
  box-shadow: var(--schatten-schwebend);
}

/* ---------- Einblenden bei Mausannäherung (14.08.2026) ----------

   Die Leiste ruht unsichtbar am rechten Rand und kommt, wenn der Zeiger sich
   ihr nähert (js/app.js, `verbindeLeistenNaehe` — Schwelle 100px, Nachlauf
   400ms gegen das Flackern an der Grenze).

   ⛔ DIE BEDINGUNG IST ZWEITEILIG, und beide Teile tragen:

     min-width: 640px          Darunter ist die Leiste ein Burger-Menü. Ein
                               Menü, das auf Mausnähe reagiert, gäbe es dort
                               nicht — und es wäre auch nichts da, dem man
                               sich nähern könnte.
     :root[data-maus="ja"]     Es hat eine ECHTE Mausbewegung gegeben
                               (js/app.js setzt es beim ersten
                               pointermove mit pointerType === "mouse").

   ⛔ HIER STANDEN BIS ZUM 03.09.2026 STATT DESSEN `hover: hover` UND
   `pointer: fine`, und das hat die Leiste auf Geräten mit
   Berührungsbildschirm FÜR IMMER SICHTBAR gelassen. Chromium leitet die
   Zeigefähigkeit dort vom Display ab, nicht von der angeschlossenen Maus;
   gemessen auf dem betroffenen Gerät sind alle drei Abfragen falsch —
   `hover: hover` nein, `pointer: fine` nein, `any-pointer: fine` nein. Die
   Regel griff also nie. Dieselbe Ursache wie bei der Rollspule
   (css/komponenten.css), nur mit anderem Ausgang.

   ⛔ EINE GESEHENE FÄHIGKEIT STATT EINER BEHAUPTETEN. Nur die Breite zu
   nehmen — wie bei der Rollspule — ginge hier nicht: Dort ist der Rückfall
   harmlos (die Systemleiste kommt zurück), hier verschwände die Leiste auf
   einem reinen Tastgerät ab 640px dauerhaft, weil `data-nah` ausdrücklich nur
   für eine Maus gesetzt wird, `:hover` an `pointer-events: none` scheitert
   und ein Tastaturfokus fehlt. `data-maus` kann dagegen nicht falsch gemeldet
   werden: Es gab eine Maus, sonst hätte niemand ihre Bewegung gesehen.

   Fällt eine der beiden Bedingungen weg, gilt der bisherige Zustand
   unverändert: Die Leiste steht dauerhaft da. Das ist ausdrücklich die
   sichere Seite — wer sie nicht einblenden kann, darf sie nicht ausblenden.

   ⚠️ Beim ersten Bild ist `data-maus` noch nicht gesetzt, die Leiste steht
   also da und verschwindet mit der ersten Mausbewegung. Das ist die richtige
   Reihenfolge: Sie zeigt sich einmal, statt unsichtbar zu beginnen.

   ⛔ KEIN `visibility: hidden` UND KEIN `display: none`. Beide nähmen den
   Einträgen die Fokussierbarkeit, und damit fiele die Tastaturbedienung aus:
   Man könnte die Leiste nicht mehr antabben, also auch nie den Zustand
   herstellen, der sie sichtbar macht. `opacity` allein läßt sie im
   Tabfluß — `:focus-within` unten holt sie dann ins Bild.

   ⚠️ `pointer-events: none` ist dafür Pflicht. Eine unsichtbare, aber
   klickbare 60px-Spalte am rechten Rand finge Klicks ab, die dem Inhalt
   darunter galten — ein Fehler, den niemand sich erklären könnte, weil dort
   nichts zu sehen ist.

   Vier Gründe, sichtbar zu sein — sie ergänzen sich, keiner ersetzt einen
   anderen:

     [data-nah="ja"]     der Zeiger ist nah (setzt js/app.js)
     :hover              er steht auf der Leiste selbst. Greift erst, wenn sie
                         schon sichtbar ist (vorher sperrt pointer-events),
                         ist also kein Auslöser, sondern hält sie. Nötig für
                         die ausgefahrene Leiste: die ist mit 224px breiter
                         als die Näheschwelle, ihr linker Teil läge sonst
                         außerhalb.
     :focus-within       ein Eintrag hat den Tastaturfokus
     data-leiste="offen" der Nutzer hat sie über den Burger ausgeklappt. Eine
                         ausdrücklich geöffnete Leiste verschwindet nicht,
                         weil die Maus woanders steht.

   ⚠️ Der Übergang steht in der Grundregel oben (opacity, --dauer-mittel).
   Bei `prefers-reduced-motion` schaltet er ohne Zutun hart um: css/basis.css
   setzt `transition-duration` dort mit `!important` auf 0,01ms — für JEDES
   Element. Eine eigene Regel dafür wäre nicht nur überflüssig, sie könnte
   dem globalen Block auch nur widersprechen. */
@media (min-width: 640px) {
  :root[data-maus="ja"] .hauptleiste {
    opacity: 0;
    pointer-events: none;
  }
  /* ⚠️ Die drei ersten Gründe brauchen `data-maus` mit: Ohne die Maus gibt es
     die versteckte Fassung gar nicht, also auch nichts zurückzuholen. Der
     vierte NICHT — eine über den Burger ausdrücklich geöffnete Leiste ist
     sichtbar, gleich womit sie bedient wird. */
  :root[data-maus="ja"] .hauptleiste[data-nah="ja"],
  :root[data-maus="ja"] .hauptleiste:hover,
  :root[data-maus="ja"] .hauptleiste:focus-within,
  :root[data-leiste="offen"] .hauptleiste {
    opacity: 1;
    pointer-events: auto;
  }
}

/* ⛔ EINTRÄGE, DIE ES NUR AUF DEM HANDY GIBT (18.09.2026).

   Heute genau einer: „Wissen". Ab 768px trägt der Kategoriereiter der
   Kopfleiste diesen Weg; darunter entfällt er dort (siehe „Zwei Zeilen unter
   768px"), und die Leiste übernimmt ihn. Je Breite genau EINE Stelle.

   ⚠️ `display: none` ist hier richtig und nimmt dem Eintrag auch die
   Fokussierbarkeit — gewollt: Am Desktop gibt es den Reiter, der Weg
   verschließt sich also nicht. Genau deshalb MUSS der Reiter unter 768px
   ebenso verschwinden und nicht bloss unsichtbar werden: Sonst gäbe es zwei
   Tabstopps zum selben Ziel, von denen einer unsichtbar ist.

   ⚠️ Die Regel sitzt am `<li>`, nicht am Verweis: Die Liste ist eine
   Flex-Spalte mit `gap`, und ein ausgeblendetes Kind darf keine Lücke
   hinterlassen. `display: none` am Verweis ließe das leere `<li>` samt seiner
   Lücke stehen. */
@media (min-width: 768px) {
  .hl-nur-schmal { display: none; }
}

.hl-liste {
  list-style: none;
  margin: 0;
  padding: var(--abstand-m) 0;
  display: flex;
  flex-direction: column;
  gap: var(--abstand-xxs);
}

.hl-eintrag {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--abstand-m);
  width: 100%;
  /* 18px waagerecht = (60 − 24) / 2: Im schmalen Zustand sitzt das Symbol
     damit genau mittig in der Spalte. Wächst die Leiste, bleibt derselbe
     Abstand als linker Rand stehen und die Symbole stehen untereinander —
     die Beschriftung wandert dahinter, das Symbol nicht. */
  padding: var(--abstand-s) 18px;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--on-surface-variant);
  font-size: var(--label-large);
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dauer-kurz) ease, color var(--dauer-kurz) ease;
}

.hl-eintrag:hover { background: var(--zustand-hover); color: var(--on-surface); }
.hl-eintrag:active { background: var(--zustand-aktiv); }

.hl-symbol {
  flex: 0 0 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
}
.hl-symbol svg { width: 22px; height: 22px; }
/* Das Währungszeichen ist Text, kein Pfad — es soll dieselbe Fläche füllen
   wie die Symbole darüber und darunter. */
.hl-symbol--text { font-size: var(--title-medium); font-weight: 500; }

/* ⚠️ Im schmalen Zustand wird die Beschriftung UNSICHTBAR gemacht, nicht
   entfernt. display:none nähme sie auch den Vorlesehilfen weg — und dort ist
   sie in beiden Zuständen die einzige Auskunft, was der Eintrag tut. Für
   sehende Nutzer trägt der Eintrag im schmalen Zustand den title. */
.hl-text {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.hl-zusatz { display: none; }

/* Aktiver Eintrag: Farbe plus eine Kante am linken Rand — dieselbe Regel wie
   überall auf der Seite, nie eine gefüllte Fläche. Die Kante liegt am Rand
   der Leiste und ist damit auch im schmalen Zustand zu sehen, wo für eine
   Unterstreichung unter der Beschriftung kein Platz wäre. */
.hl-eintrag[aria-current="page"] { color: var(--primary); }
.hl-eintrag[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: var(--abstand-xs);
  bottom: var(--abstand-xs);
  width: 3px;
  border-radius: var(--radius-pille);
  background: var(--primary);
}

/* „Anmelden" ist angelegt, aber ohne Ziel: Es gibt keine Benutzerkonten.
   Gedämpft statt versteckt — wer danach sucht, soll sehen, daß es vorgesehen
   ist; den Grund nennt die Meldung beim Klick. */
/* ⚠️ 0,75 statt 0,55 (10.08.2026). Der Eintrag trägt zwar aria-disabled und
   wäre damit formal von der Kontrastregel ausgenommen — er ist aber
   tatsächlich BEDIENBAR: Der Klick löst die Snackbar „Bald verfügbar" aus.
   Was man anfassen kann, muss man auch lesen können. Gemessen mit 0,55:
   2,72:1 gegen den Seitengrund, weit unter den 4,5:1 für Normaltext.
   Die Deckkraft liegt bewusst am ganzen Eintrag und nicht an der Beschriftung:
   Sie dämpft das Symbol mit, und eine reine Farbänderung an .hl-text löste
   nur die Hälfte. ⚠️ Im Vorgabezustand (schmale Spalte) ist die Beschriftung
   per sr-only-Technik 1×1px groß — der Fall wird erst mit dem Burger sichtbar
   und ist deshalb einem Ruhe-Durchlauf entgangen. */
.hl-eintrag--gesperrt { opacity: 0.85; cursor: not-allowed; }

/* Die Zählmarke sitzt im schmalen Zustand auf dem Symbol und wandert im
   breiten ans Zeilenende. Ihre Grundform (Kreis, Farbe, Größe) steht bei den
   übrigen .zaehlmarke-Regeln — hier steht nur, wo sie liegt. */
.hl-eintrag .zaehlmarke { top: 4px; left: 34px; right: auto; }

.hl-waehrung { position: relative; }
.menue--waehrung { min-width: 240px; }

/* ---------- Ausgeklappt ---------- */

:root[data-leiste="offen"] .hl-text {
  position: static;
  width: auto;
  height: auto;
  overflow: visible;
  clip-path: none;
}

:root[data-leiste="offen"] .hl-zusatz {
  display: inline;
  margin-left: auto;
  color: var(--on-surface-variant);
  font-size: var(--label-medium);
}

/* Am Zeilenende statt auf dem Symbol: Neben der Beschriftung wäre die Marke
   auf dem Symbol eine zweite Zahl mitten im Wort. */
:root[data-leiste="offen"] .hl-eintrag .zaehlmarke {
  position: static;
  margin-left: auto;
}

/* ---------- Inhalt ---------- */

main {
  /* Deutlich mehr Fläche auf großen Bildschirmen; die Liste bekommt den
     gesamten Platz rechts der Filterleiste. Waagerecht derselbe Wert wie
     Kopfzeile, Banner und Fußbereich — alle vier stehen dadurch in der
     1600px-Spalte auf derselben Kante. Senkrecht mehr Luft, damit der
     Inhalt nicht an der Kopfzeile klebt. */
  max-width: 1600px;
  margin: 0 auto;
  padding: var(--abstand-xl) var(--abstand-l);
}

/* ---------- Breite der Textseiten ----------

   ⛔ DIE TEXTSEITEN STEHEN AUF 1120px, AUF DERSELBEN ACHSE WIE DER REST
   (11.08.2026). Vorher lagen sie hier bei calc(--lesebreite + 2 * --abstand-l)
   = gemessen 618,5px, und das war der eigentliche Befund hinter der Meldung
   „Inhalte links versetzt, rechts große Flächen leer":

     Der Inhalt war NICHT links versetzt — main steht bei jeder Breite auf
     0,00px genau auf der Fenstermitte (margin-left = margin-right auf 0,01px).
     Auch die rechte Icon-Spalte erklärt es nicht: Sie verschiebt die optische
     Mitte um 30px, und zwar nach RECHTS, also mit dem falschen Vorzeichen.

     Es war die BREITE. 618,5px sind bei 1920px Fenster 32,7 % — 635px
     Leerraum auf JEDER Seite. Dazu fehlte jeder Bezug zum Rahmen: Die Marke
     beginnt bei x=16, der Fußbereich bei x=144,5, der Text erst bei x=651,25.
     Ein 586px-Textblock in einem 1889px-Rahmen liest sich als eingerückte
     Insel, nicht als Seite.

   1120px ist keine neue Zahl, sondern das Maß von .detail (seiten.css) und
   .material-seite — die Textseiten stehen damit in derselben Flucht wie
   Angebots- und Materialseiten. Die Zeilenlänge bleibt trotzdem ruhig, weil
   der FLIESSTEXT innerhalb der Karten eigene Grenzen trägt; das ist dieselbe
   Bauart, die .material-seite seit jeher benutzt („Eine Lesespalte ist kein
   ausgefranster Rand", seiten.css).

   ⛔ OHNE MEDIENABFRAGE, und das behebt einen echten Fehler: Die alte Regel
   griff erst ab 900px. Darunter band .ueber-seite { max-width: 720px }, also
   war die Spalte 720px breit — und ab 900px sprang sie auf 586,5px. Sie
   wurde beim VERBREITERN des Fensters um 133,5px SCHMALER. Gemessen. Mit
   1120px kann das nicht mehr passieren: Unterhalb von 1152px bindet ohnehin
   die Fensterbreite, die Spalte wächst monoton und kappt erst oben.

   ⚠️ /einstellungen und die Nicht-gefunden-Ansicht bleiben bei der alten
   Lesespalte (Block darunter). Sie sind KEINE Textseiten in diesem Sinn:
   Die Einstellungen sind ein Formular aus kurzen Zeilen, und eine
   Fehlermeldung soll schmal stehen. Beide unverändert zu lassen war
   ausdrücklich verlangt. */
main[data-ansicht="impressum"],
main[data-ansicht="datenschutz"],
main[data-ansicht="affiliate"],
main[data-ansicht="ueber"] {
  max-width: 1120px;
}

/* ---------- Lesespalte von /einstellungen und /nicht-gefunden ----------

   Die Regel hängt am data-ansicht des Routers und NICHT an den
   Container-Klassen der einzelnen Seiten (.einstellungs-seite,
   .nicht-gefunden). Grund: Überschrift, Einleitung und die Kursstand-Fußnote
   der Einstellungen liegen neben diesen Containern, nicht darin. Eine Regel
   je Container hätte die Karten eingerückt und die Überschrift darüber am
   linken Rand stehen lassen.

   Die Breite wird gerechnet statt geschätzt: --lesebreite ist die gewünschte
   Zeichenzahl im Text selbst, dazu kommt der Innenabstand des <main> auf
   beiden Seiten (border-box). Vorher stand hier eine geschätzte 78ch.

   Erst ab 900px, damit Handy und Tablet unverändert bleiben — unterhalb ist
   die Spalte ohnehin breiter als das Fenster und die Begrenzung wirkungslos.
   Zentriert wird über das margin: 0 auto, das <main> schon trägt. */
@media (min-width: 900px) {
  /* ⚠️ „ueber" gehört hier NICHT mehr her — es steht im 1120px-Block darüber.
     Beide Regeln wiegen gleich schwer; diese steht später und würde die
     1120px stillschweigend wieder auf 618,5px kappen. */
  main[data-ansicht="einstellungen"],
  main[data-ansicht="nichtGefunden"] {
    max-width: calc(var(--lesebreite) + 2 * var(--abstand-l));
  }
}

/* ---------- Fußbereich ---------- */

/* Die Freihaltefläche für die fixierte untere Navigationsleiste und die
   schwebende Vergleichsleiste sitzt jetzt hier statt an <main>. Beide liegen
   über dem Dokumentende — läge der Abstand weiter an <main>, klaffte eine
   Lücke zwischen Inhalt und Fußbereich, und der Fußbereich verschwände
   trotzdem unter der Leiste. */
.fusszeile {
  max-width: 1600px;
  margin: var(--abstand-3xl) auto 0;
  padding: var(--abstand-l);
  /* Untere Leiste plus schwebende Vergleichsleiste, aus den Gerüstmaßen
     gerechnet statt als 132px hingeschrieben. */
  padding-bottom: calc(var(--nav-hoehe) + var(--abstand-3xl));
  /* Keine Trennlinie: Der große Abstand darüber trennt bereits, und der
     gedämpfte Text setzt den Bereich zusätzlich ab. */
  color: var(--on-surface-variant);
}

.fusszeile-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--abstand-m) var(--abstand-l);
}

.fusszeile-links a {
  font-size: var(--body-medium);
  /* Unterstrichen, nicht nur eingefärbt: Im Fußbereich fehlt der Kontext,
     der einen Link sonst als solchen erkennbar macht. */
  text-decoration: underline;
  /* Trefferfläche für den Daumen, ohne die Zeile auseinanderzuziehen. */
  padding: var(--abstand-xs) 0;
}

.fusszeile-hinweis {
  margin-top: var(--abstand-l);
  font-size: var(--body-small);
  max-width: var(--lesebreite);
}

/* Weicher Seitenübergang beim Routenwechsel (js/router.js setzt die Klasse). */
.seite { animation: seite-einblenden var(--dauer-mittel) ease-out; }

@keyframes seite-einblenden {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* Dieselbe Bewegung für die beiden schwebenden Leisten am unteren Rand
   (Snackbar, Vergleichsleiste).

   ⛔ SIE DARF KEIN translateX TRAGEN (18.09.2026). Beide liegen seit diesem
   Tag über ihre RÄNDER mittig (`left`/`right` plus `margin-inline: auto`),
   nicht mehr über `left: 50%` plus `translateX(-50%)` — sie stehen also
   bereits an ihrem Platz. Eine Verschiebung um die halbe Eigenbreite rückte
   sie für die Dauer der Einblendung nach links aus dem Bild.

   ⚠️ Bis dahin galt hier das GENAUE GEGENTEIL, und die Begründung ist
   lehrreich genug, um sie zu behalten: Solange die Leisten über einen
   Transform mittig lagen, MUSSTE das translateX(-50%) in jeder Bildstufe
   stehen — `transform` ist eine Eigenschaft, keine Liste, die Bildfolge
   ersetzt den Wert des Elements, statt ihn zu ergänzen. Mit
   seite-einblenden sprang die Leiste deshalb für die Dauer der Einblendung
   um ihre halbe Breite, auf schmalen Fenstern halb aus dem Bild. Wer die
   mittige Lage je wieder an einen Transform hängt, holt beides zurück.

   ⚠️ EINE Bildfolge für beide, nicht zwei: Zwei Fassungen derselben
   Bewegung liefen beim nächsten Nachjustieren auseinander, und die falsche
   sähe man nur an der Leiste, die man gerade nicht auslöst. */
@keyframes schwebend-einblenden {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Testmodus- und Fehler-Banner (unter der Kopfzeile) ---------- */

/* Ruhige, schmale Hinweiszeile statt farbigem Vollbreiten-Balken: sichtbar,
   aber nicht beherrschend. Sobald echte Daten geladen sind, blendet js/app.js
   sie ganz aus. */
.testmodus-banner {
  display: flex;
  align-items: center;
  gap: var(--abstand-s);
  /* Auf die Inhaltsbreite ausgerichtet, damit die Zeile bündig zum Text
     darunter beginnt. */
  width: min(100%, 1600px);
  margin: var(--abstand-s) auto 0;
  padding: 0 var(--abstand-l);
  font-size: var(--body-small);
  color: var(--on-surface-variant);
}
/* Kleines Symbol fester Größe, das nicht mitschrumpft. */
.testmodus-banner svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--warnung-erhoeht);
}
.testmodus-banner strong { font-weight: 500; color: var(--on-surface); }
.testmodus-banner[hidden] { display: none; }

/* ---------- Responsiv ----------
   Handy: einspaltig, app-artig (untere Leiste).
   Tablet (ab 640px): zweispaltige Liste, Navigation oben.
   Desktop (ab 1024px): mehrspaltig plus dauerhafte Filterleiste. */

/* Platz für die schwebende Vergleichsleiste über dem Fußbereich. Früher
   stand hier zusätzlich das Umschalten zwischen unterer Leiste und Zielen in
   der Kopfzeile — beide gibt es nicht mehr, ihre Ziele stehen in der rechten
   Hauptleiste. */
.fusszeile { padding-bottom: calc(var(--abstand-3xl) + var(--abstand-xl)); }

/* ---------- Handy: die Leiste wird zum Menü über die volle Höhe ----------

   Unter 640px kostete eine dauerhafte Spalte am rechten Rand zu viel Breite —
   selbst schmal wären es 60 von 320 Pixeln, also fast ein Fünftel. Derselbe
   Zustand fährt dort deshalb als Menü über die ganze Seite ein, und ein
   angetippter Eintrag schließt es wieder (js/app.js).

   ⚠️ Geschlossen ist die Leiste nicht nur verschoben, sondern auch
   `visibility: hidden`. Ohne das bliebe sie neben dem Bildschirm in der
   Tab-Reihenfolge und würde vorgelesen — ein Menü, das man erreichen kann,
   ohne es zu sehen. Die Verzögerung im Übergang hält sie sichtbar, solange
   sie noch hinausfährt. */
@media (max-width: 639px) {
  /* Unter 640px ist die Leiste ein Menü über die volle Höhe und belegt im
     Layout gar nichts — also gibt es auch nichts zu spiegeln. Beide Seiten
     auf 0: Der Inhalt bekommt hier jeden Pixel, und die Ränder sind schon
     dadurch gleich. */
  body { padding-inline: 0; }

  .hauptleiste {
    width: min(320px, 88vw);
    border-left: 1px solid var(--outline-variant);
    transform: translateX(100%);
    visibility: hidden;
    /* Hier DARF gerollt werden: Das Menü ist 320px breit, das Währungsmenü
       (240px) bleibt innerhalb dieser Fläche und wird nicht beschnitten.
       Im Querformat eines Handys sind es sonst mehr Einträge als Höhe. */
    overflow-y: auto;
    overscroll-behavior: contain;
    transition:
      transform var(--dauer-mittel) ease,
      visibility 0s linear var(--dauer-mittel);
  }

  :root[data-leiste="offen"] .hauptleiste {
    transform: translateX(0);
    visibility: visible;
    transition: transform var(--dauer-mittel) ease;
  }

  /* Im Menü ist immer Platz für die Beschriftung — ein Menü aus sieben
     namenlosen Symbolen wäre auf dem Handy ein Rätsel. */
  .hl-text {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
  }
  .hl-eintrag .zaehlmarke { position: static; margin-left: auto; }
  .hl-zusatz {
    display: inline;
    margin-left: auto;
    color: var(--on-surface-variant);
    font-size: var(--label-medium);
  }
}

/* ---------- HIER STAND DAS SCHRUMPFEN BEIM SCROLLEN ----------

   ⛔ ERSATZLOS ENTFALLEN AM 22.09.2026. js/app.js schrieb --kopf-roll (0…1)
   im rAF-Takt an .kopfzeile, die Leiste leitete daraus --kopf-fortschritt
   ab und daraus Zeilenhöhe, Luft, Schriftgröße und Markenskala. Mit ihm
   sind `@property --kopf-roll` und jede dieser Ableitungen gegangen.

   ⚠️ WAS DAVON BLEIBT UND WARUM:

     --kopf-hoehe    bleibt. Die Leiste ist je Fensterbreite verschieden
                     hoch (72 / 64 / zwei Zeilen), und daran hängen die
                     klebenden Spalten. Gemessen wird jetzt EINE Lage statt
                     zweier Endlagen mit linearer Teilung dazwischen.
     --werkzeug-roll bleibt. Die Werkzeugzeile der Listen schrumpft auf dem
                     Handy weiterhin beim Rollen (css/seiten.css). Sie hing
                     am selben Rollzähler in js/app.js, nie an der
                     Kopfleiste — der Zähler ist deshalb geblieben.

   ⛔ DIE MESSBANK BLEIBT GÜLTIG, auch wenn sie hier nichts mehr misst: Wer
   je wieder einen Wert im rAF-Takt schreibt, schreibt ihn AM ELEMENT und
   nie am <html>. Gemessen auf /filamente (4012 Elemente), 300 Runden,
   nach jedem Schreibvorgang ein erzwungenes Layout:

     beide Werte geerbt am <html>                  27,46 ms je Bild
     eng gefasst                                    4,67 ms je Bild
     --kopf-hoehe am <html>                        11,97 ms
     --kopf-hoehe in die Empfängerregel unten       4,02 ms
     --kopf-roll an .kopfzeile                      0,31 ms
     reine Layoutänderung ohne Custom Property       0,05 ms

   Teuer war nie das Layout, sondern die Stilberechnung. */

/* ---------- Empfänger der gemessenen Kopfhöhe ----------

   ⛔ WER var(--kopf-hoehe) BENUTZT, GEHÖRT IN DIESE LISTE. Sie ist die
   einzige Stelle, an der die gemessene Höhe ankommt; js/app.js schreibt den
   Wert in genau diese Regel (gefunden über den Handgriff .pd-kopfhoehe, der
   auf kein Element passt und nur dazu da ist, die Regel wiederzufinden).

   Warum nicht einfach am <html>, wo der Startwert steht: Seit dem 22.09.2026
   ändert sich die Kopfhöhe nur noch beim Umbruch des Fensters, nicht mehr in
   jedem Bild des Rollens — der Kostenunterschied ist damit nicht mehr die
   Begründung. Geblieben ist die Regel trotzdem: Am <html> kostete jeder
   Schreibvorgang gemessen 11,97 ms gegen 4,02 ms hier, und das gilt auch für
   den einen beim Umbruch. Zurückzubauen wäre eine Änderung ohne Gewinn, die
   die Empfängerliste als Wächter mit wegnähme.

   ⚠️ Gemessen und NICHT genommen: Denselben Wert inline an die Empfänger-
   ELEMENTE zu schreiben kostet nur 2,08 ms — eine Regel im Stylesheet zu
   ändern ist teurer, als Elemente zu beschreiben. Der Weg scheitert an etwas
   anderem: .listen-kopf und .filter-sidebar entstehen
   bei JEDEM Routenwechsel neu. Eine Sammlung von Elementen müsste nach jedem
   Zeichnen erneuert werden, und wer das einmal vergisst, beschreibt Elemente,
   die nicht mehr im Dokument stehen — ohne Fehlermeldung. Die Regel gilt
   dagegen von selbst weiter. Zwei Millisekunden je Bild sind dieser
   Unterschied wert; bei 4,67 ms Gesamtaufwand ist Platz dafür.

   ⚠️ `inherit` ist der Rückfall und kein Füllwert: Kommt das Skript nicht an
   die Regel heran (über file:// verweigert Chrome den Zugriff auf
   cssRules), schreibt es wie früher ans <html> — und dann MUSS der Wert von
   dort durchgereicht werden. Stünde hier eine feste Zahl, klebten
   Filterspalte und Suchzeile in diesem Fall auf 56px statt auf der wirklichen
   Höhe, also unter der Kopfleiste. Genau dieser Fehler ist schon einmal
   dagewesen (siehe --kopf-hoehe in css/theme.css). */
.pd-kopfhoehe,
.hauptleiste,
.menue--drucker,
.listen-kopf,
.filter-sidebar,
/* Die Sprungziele von /wissen: Ihr scroll-margin-top hält den Anker unter der
   klebenden Kopfleiste hervor. Ohne den Eintrag hier bekämen sie den
   Startwert 56px, und der Sprung landete bei jeder anderen Leistenhöhe an der
   falschen Stelle — dieselbe Falle wie bei Filterspalte und Suchzeile. */
/* Die klebende Auswahlleiste des Merkzettels (18.09.2026). Sie klebt auf
   DEMSELBEN Maß wie die Werkzeugzeile der Listen; ohne diesen Eintrag bekäme
   sie den Startwert 56px und rutschte unter die Kopfleiste.

   ⚠️ SIE STEHT VOR DEM PAAR .wissen-abschnitt / .wf-zeile, und das ist kein
   Zufall: Ein Prüffall (C34) liest die beiden als unmittelbar aufeinander
   folgendes Paar samt der öffnenden Klammer. Wer dahinter anhängt, schiebt
   die Klammer weg und lässt ihn fallen — ohne dass an der Empfängerliste
   etwas falsch wäre. Neue Einträge also HIER einfügen, nicht am Ende. */
.mz-auswahlleiste,
.wissen-abschnitt,
.wf-zeile {
  --kopf-hoehe: inherit;
}
