/* Öffentliches Stylesheet.
 *
 * Aufbau: Tokens, dann fünf Kaskadenschichten. Die Schichtreihenfolge ersetzt
 * das Spezifitäts-Wettrüsten — eine Blockregel muss nie `!important` oder einen
 * längeren Selektor bemühen, um eine Basisregel zu überschreiben.
 *
 * Die Blockstile tragen einen eigenen Namensraum `block-<typ>__element`, weil
 * hier das Scoping von Vue fehlt und Klassen wie `.inner` sonst kollidieren
 * würden.
 *
 * Der Token-Block unten ist eine KOPIE aus `design/tokens.css` und absichtlich
 * nicht eingerückt, damit `scripts/check-tokens.sh` ihn zeichengleich mit der
 * Quelle vergleichen kann. Änderungen dort vornehmen, nicht hier.
 */

/* ==== TOKENS START ==== */
:root {
  color-scheme: light;

  /* --- Flächen ---
     Aus der Palette des Bestands-Themes (`--theme-palette-color-4…8`), mit
     einer Abweichung: der Grund ist **weiß**.

     Der Bestand stellt `body` und Kopfzeile auf `--theme-palette-color-7`
     (#FAFBFC) und benutzt Weiß (`palette-color-8`) für die Flächen, die *auf*
     dem Grund liegen. Diese 1,5 % Unterschied sind 1,026:1 und auf keinem
     Bildschirm zu sehen — sie kosten aber die Bedienfarbe als Schrift:
     #DB3C00 erreicht auf #FAFBFC nur 4,35:1 und verfehlt die Schwelle knapp,
     auf reinem Weiß sind es 4,51:1. Deshalb steht der Grund jetzt auf Weiß,
     und Eyebrow, Links und Zeichen tragen wieder die Bedienfarbe (Regel C in
     docs/branding/farben.md).

     `--c-raised` führt damit denselben Wert. Der Name bleibt, weil er eine
     Rolle benennt und nicht einen Farbwert: gehobene Flächen — Karten,
     Eingabefelder, Kopfzeile, die Paneele des Editors — heben sich über Rahmen
     und Schatten ab, nicht über die Füllung. Das taten sie bei 1,026:1 auch
     vorher schon.

     Eingesenkt trägt die Bedienfarbe mit 4,12:1 keine Schrift, und einen
     eingesenkten Ton, der sie trägt, gibt es nicht: er müsste heller als
     #fefefe sein. Das Band weicht deshalb aus.

     **Der eingesenkte Ton ist warm, nicht kühl.** Hier stand #f2f5f7, der
     Wert aus dem Bestands-Theme (--theme-palette-color-5 … -6). Seit dem
     17.09.2026 steht #F7F4F2 — die Wechselfläche der CI-Vorlage
     n1-testseite-thermaldrones.html, die dort `--bg-alt` heißt und genau
     diese Aufgabe hat: Abschnitte gliedern, ohne eine Farb- oder
     Kontrastentscheidung anzutasten.

     Der Tausch ist **photometrisch folgenlos**. Die beiden Werte sind
     Spiegelbilder (f2f5f7 rückwärts gelesen ist f7f5f2) und haben dieselbe
     Helligkeit: L* 96,36 gegen 96,37, Verhältnis 1,000116:1. Über alle neun
     Paarungen, die auf diesem Grund gemessen sind, beträgt die größte
     Abweichung 0,0015 — jede veröffentlichte Zahl bleibt auf zwei
     Nachkommastellen wörtlich wahr. Was sich ändert, ist allein die
     Richtung: a-Stern und b-Stern kippen von (−0,63 / −1,32) auf
     (+0,65 / +1,30). ΔE 2,92,
     also nebeneinander gerade eben zu sehen, einzeln nicht.

     Der dunkle Satz führt mit #1b1b1b längst den Wert der Vorlage; der
     Tausch schließt damit die Lücke im hellen Satz.

     **Achtung beim Nachjustieren.** Der Farbton liegt mit 24,0° INNERHALB
     des Orangebands, das scripts/check-brand-color.py überwacht (8° bis
     28°). Still bleibt die Prüfung nur wegen der geringen Buntheit: 5, und
     die Schwelle liegt bei 8. Wer den Ton sättigt — #F0E8E2 wäre schon 14 —
     löst eine Meldung aus, und das zu Recht: ein warmer, gesättigter
     Hellton ist eine Aufhellung der Marke. */
  --c-bg: #ffffff;
  --c-raised: #ffffff;
  --c-sunken: #F7F4F2;

  /* Die Tabellenzeile unter dem Zeiger. Kein fester Wert, sondern 4 % der
     Schriftfarbe über dem, was darunter liegt: eine Tabelle kann in jedem
     Band stehen (K-LAYOUT-04.1–.4), und ein fester heller Ton ließe die Zeile
     im Kontrastband aufleuchten. `currentColor` löst sich an der Zeile auf,
     nicht hier — ein Custom Property wird als Text eingesetzt. Auf --c-bg mit
     --c-ink ergibt das #F8F8F8, im dunklen Satz #292929; beide Sätze teilen
     damit die Formel. Nur in Selektoren mit :hover. */
  --c-row-hover: color-mix(in srgb, currentColor 4%, transparent);

  /* Das **Kontrastband** — die Flaeche, die sich am staerksten vom Grund
     absetzt (K-LAYOUT-04.4, `[data-tone="contrast"]`). Es ist die eine
     Rolle, die **die Richtung wechselt**: hell setzt sie sich nach unten ab,
     dunkel nach oben. Deshalb heisst sie nicht mehr `--c-dark` — der Name
     behauptete im dunklen Satz das Gegenteil dessen, was die Flaeche tut.

     Hier stand das Navy #192a3d aus der Palette des Bestands-Themes
     (--theme-palette-color-4). Es ist am 18.09.2026 dem neutralen Grau
     #222222 gewichen, dem `bgInvert` der CI-Vorlage. Der Grund ist derselbe,
     aus dem der dunkle Satz von Anfang an unbunt ist: eine grosse Flaeche in
     Navy ist kein Kontrast, sondern ein Farbstich, und die Bedienfarbe
     stuende darauf auf einem blauen statt auf einem neutralen Grund. Was man
     an Farbe sieht, soll eine Nachricht sein. Die Abweichung vom Bestand ist
     in docs/theme-abgleich.md als die vierte eingetragen. */
  --c-contrast: #222222;

  /* Der **dunkle Grund** — und der bleibt in beiden Saetzen dunkel: der
     Platzhalter hinter einem ladenden Abschnittsbild, der Bezug des
     Schleiers, die Redaktionsleiste, die Seitenleiste des Editors. Ein Bild
     wird durch den Schleier dunkel und nicht durch das Band; deshalb sind es
     zwei Token und nicht eins.

     Ebenfalls von Navy auf Grau gezogen, damit ueber einem Foto nicht
     plotzlich ein blauer Schleier liegt. */
  --c-dark: #222222;
  --c-dark-deep: #101010;

  /* Abdunklung über einem Hintergrundbild. Ohne sie steht heller Text auf einem
     hellen Bildausschnitt, und der Kontrast ist Glückssache — auf der
     Bestandsseite steht der Aufmacher über hellem Gras.

     Hier stand, 0,55 sei der Wert, bei dem `--c-on-dark` über jedem
     Bildausschnitt 4,5:1 hält; genannt war eine Fläche von #8a9099 mit 4,6:1.
     Beides ist falsch nachgerechnet. Der Schleier über einer weißen Fläche
     ergibt #7C7C7C (0,55·16 + 0,45·255 je Kanal), und darauf erreicht #EDEDED
     nur 3,57:1. Für 4,5:1 wäre 0,62 nötig (#6B6B6B, 4,55:1) — der Wert, den
     der dunkle Satz bereits führt.

     Der Wert bleibt bis zur Entscheidung auf 0,55: kein Inhalt trägt heute ein
     Abschnittsbild (0 von 171 Übersetzungen), und 0,65 verdunkelt jedes solche
     Bild sichtbar. Notiert unter »Offen« in docs/branding/farben.md.

     Kein Markenwert und damit nicht von Regel A betroffen. */
  --c-scrim: rgb(16 16 16 / 0.55);

  /* --- Text ---
     `#444444` ist die Textfarbe **und** die Überschriftenfarbe des Bestands
     (`--theme-text-color` und `--theme-headings-color` zeigen beide auf
     `--theme-palette-color-3`) — 9,74:1 auf `--c-bg`.

     Hier stand `#16222e` mit 15,6:1. Beide bestehen AAA, es gibt also keine
     Zahl, die entscheidet; dann gilt die Treue zum Bestand. Wer die Seite
     wieder vom Original lösen will, ändert es hier und nirgends sonst.

     `muted` und `on-dark-muted` haben im Theme keine Entsprechung — es kennt
     nur eine Textfarbe. Sie bleiben, weil Bildunterschriften und Datumszeilen
     sonst so schwer wögen wie der Fließtext: 6,48:1 auf `--c-bg`, 7,34:1 auf
     `--c-dark`. `muted-strong` ist die Stufe für Beschriftungen und Glyphen,
     die auf `--c-control` sitzen und dort mehr Luft brauchen als der
     Fließtext — 6,78:1 gegen 4,96:1.

     **Beide sind am 18.09.2026 von blaugrau auf neutral gezogen worden**:
     `muted` von #5b6b7b auf #5E5E5E (der `muted`-Wert der CI-Vorlage),
     `muted-strong` von #4d5f70 auf #4A4A4A. Beide Zahlen steigen dabei —
     die Vorlage setzt ihre Zweitschrift dunkler, als der Bestand sie hatte. */
  --c-ink: #444444;
  --c-muted: #5E5E5E;
  --c-muted-strong: #4A4A4A;
  --c-on-dark: #EDEDED;
  --c-on-dark-muted: #B0B0B0;

  /* Schrift **auf dem Kontrastband**. Im hellen Satz sind das dieselben
     Werte wie auf dem dunklen Grund — das Band ist dort dunkel. Im dunklen
     Satz kehrt es sich um, und genau dafuer gibt es die zwei Namen. */
  --c-on-contrast: var(--c-on-dark);
  --c-on-contrast-muted: var(--c-on-dark-muted);

  /* --- Marke ---
     #FF4000 ist die Marke. Sie steht an **Logo und Wortmarke, sonst
     nirgends** — kein Knopf, kein Link, kein Zeichen. Wo sie steht, steht
     sie exakt so: kein Abdunkeln, kein Aufhellen, kein color-mix, keine
     Deckkraft unter 100 %. Die Regel samt Begründung:
     docs/branding/farben.md.

     Die Trennung ist am 17.09.2026 eingezogen und entspricht der Regel
     R-61 aus POI Cloud („Die Marke ist keine Bedienfarbe"). Der Grund ist
     eine Zahl: weiße Schrift auf #FF4000 erreicht nur 3,51:1 und fällt als
     Fließtext durch. Solange die Marke auch die Bedienfarbe war, musste
     entweder die Schrift dunkel werden (#101010, 5,42:1) oder die
     Schriftgröße die Schwelle tragen. Mit #DB3C00 als Bedienfarbe trägt die
     Fläche weiße Schrift mit 4,51:1 — und die Marke bleibt unangetastet, wo
     WCAG 1.4.3 sie ohnehin von der Anforderung ausnimmt: am Logo.

     --c-brand gehört deshalb in genau zwei Regeln (.brand__light in
     Kopf- und Fußzeile). Jede weitere Verwendung ist ein Fehler, den
     scripts/check-brand-color.py nicht sehen kann — sie ist über den Token
     erlaubt, aber nicht über die Regel. */
  --c-brand: #FF4000;

  /* --- Akzent, also die Bedienfarbe ---
     #DB3C00 trägt alles Bedienende: Knöpfe, Links, Zeichen, Kanten, aktive
     Zustände. Sie ist **keine Markenfarbe**; Regel A gilt für sie nicht,
     und sie darf deshalb eigene dauerhafte Stufen haben — das ist der
     Unterschied zum Zustand vorher.

     Hier stand bis zum 17.09.2026 die Marke selbst (zuerst #f26522, dann
     #FF4000). #DB3C00 ist aus der Marke abgeleitet: derselbe Farbton in
     OKLCH bis auf 1,4° (35,9° statt 34,5°), nur dunkler — genau so weit,
     dass weiße Schrift 4,5:1 hält. Heller geht nicht, ohne die Schwelle zu
     verlieren; kräftiger auch nicht, weil sRGB bei dieser Helligkeit keine
     höhere Buntheit mehr zulässt.

     Drei Ableitungen, alle in OKLCH bei gehaltenem Farbton:

       * --c-accent-hover = Akzent mit L −0,034 → #CA3700. Die Richtung ist
         nach **unten**, weil die Schrift auf der Fläche weiß ist: Weiß
         erreicht auf #CA3700 5,18:1, auf dem Akzent selbst 4,51:1. Der
         Hover trägt die Schrift also bequemer als der Ruhezustand. Solange
         die Schrift dunkel war, musste er umgekehrt aufhellen — die
         Richtung hängt an der Schriftfarbe, nicht am Geschmack.
       * --c-accent-soft = Akzent mit L 0,963 und Buntheit 0,017 → #FEEFEB.
         Absolute Helligkeit statt Abstand: die Fläche soll so hell bleiben
         wie bisher, sonst wäre sie plötzlich eine andere Stufe. --c-ink
         erreicht darauf 8,70:1.
       * --c-accent-on-dark = Akzent mit L +0,10 → #FF6034, für Akzentschrift
         auf --c-dark und --c-dark-deep. Der Akzent selbst käme dort nur auf
         3,24:1 und wäre als Text unzulässig; #FF6034 erreicht 4,84:1 auf
         --c-dark und 5,48:1 auf --c-dark-deep. Ein solcher Wert stand hier
         früher schon einmal (#ff8a4c) und war zu Recht entfallen — damals
         war er eine dauerhafte Abwandlung der **Marke**. Jetzt ist er eine
         Stufe der Bedienfarbe und damit zulässig.

     Nur --c-accent-hover und --c-accent-soft gehören in Selektoren mit
     :hover, :active, :focus-visible oder :focus-within; das prüft
     scripts/check-tokens.sh mit. --c-accent-on-dark ist dauerhaft und
     deshalb nicht in dieser Liste.

     Was der Akzent trotzdem nicht kann: als Schrift auf --c-bg steht er bei
     4,35:1 und damit knapp unter der Schwelle — auf reinem Weiß sind es
     4,51:1. Fließtext in der Bedienfarbe bleibt deshalb aus, es gilt weiter
     Regel C: neutrale Schrift, daneben ein farbiges Zeichen. Als Zeichen,
     Kante, Linie und Aufzählungspunkt genügen 3:1, und die hält er
     überall. */
  --c-accent: #DB3C00;
  --c-accent-hover: #CA3700;
  --c-accent-soft: #FEEFEB;
  --c-accent-on-dark: #FF6034;

  /* Die Bedienfarbe **als Schrift**, aufgeloest je nach Grund. Sie ist der
     einzige Token, den ein Bauteil fuer farbige Schrift nennen darf.

     Regel C aus docs/branding/farben.md sagt: auf dem Seitengrund traegt die
     Bedienfarbe Schrift (4,51:1 auf Weiss), auf --c-dark nicht (3,24:1) —
     dort steht --c-accent-on-dark (4,84:1). Bisher musste jeder Selektor
     diese Unterscheidung selbst treffen. Mit diesem Token trifft sie der
     Tokensatz: hell zeigt er auf den Akzent, dunkel auf die Stufe fuer
     dunkle Gruende. Die Regel bleibt woertlich dieselbe, sie wird nur an
     **einer** Stelle aufgeloest statt in zwanzig.

     Kein neuer Farbwert — ein Alias auf zwei bestehende. */
  --c-accent-text: var(--c-accent);

  /* Die Bedienfarbe **als Zeichen** — Kante, Balken, Punkt,
     Aufzaehlungszeichen, Unterstreichung. Der Zwilling von --c-accent-text,
     und der Unterschied ist allein die Schwelle: Schrift braucht 4,5:1, ein
     Zeichen 3:1.

     Genau daran haengt, warum es zwei Token braucht. Auf dem eingesenkten
     Band erreicht die Bedienfarbe 4,12:1 — als Schrift zu wenig, als Zeichen
     genug. --c-accent-text weicht dort aus, --c-mark bleibt stehen. Das ist
     R-02 woertlich: neutrale Schrift traegt den Text, ein Zeichen in der
     Bedienfarbe daneben traegt die Bedeutung.

     Zwei Gruende verlangen trotzdem ein Ausweichen, und beide loest site.css
     am getoenten Abschnitt selbst auf (R-15): das Kontrastband auf
     --c-accent-on-dark und das Abschnittsbild auf --c-on-dark, wo die
     Bedienfarbe auf 1,07:1 faellt.

     Im dunklen Satz steht hier nichts: --c-accent haelt dort auf allen drei
     Gruenden ueber 3:1 (3,53 / 3,10 / 4,22). Das Zeichen muss also nicht
     umgelegt werden — anders als die Schrift.

     Kein neuer Farbwert — ein Alias. */
  --c-mark: var(--c-accent);

  /* Die beiden Zwillinge **fuer das Kontrastband**. Sie loesen dieselbe
     Frage wie --c-accent-text und --c-mark, nur fuer die eine Flaeche, die
     die Richtung wechselt.

     Im hellen Satz ist das Band dunkel (#222222): farbige Schrift nimmt dort
     --c-accent-on-dark (5,28:1), das Zeichen ebenso.

     Im dunklen Satz ist das Band hell (#EDEDED), und dort **weicht die
     Schrift aus**: die Bedienfarbe erreicht 3,85:1 — als Schrift zu wenig,
     als Zeichen genug. Das ist wortgleich die Lage des eingesenkten Bandes
     im hellen Satz (4,12:1), und die Antwort ist dieselbe: neutrale Schrift
     traegt den Text, der Doppelpfeil daneben bleibt orange (R-02).

     Aufgeloest wird beides hier im Tokensatz und nicht in zwanzig
     Selektoren — wie bei --c-accent-text. Kein neuer Farbwert. */
  --c-accent-on-contrast: var(--c-accent-on-dark);
  --c-mark-on-contrast: var(--c-accent-on-dark);

  /* --- Schrift auf gefüllter Fläche ---
     Beide tragen Schrift auf satten Füllungen, bleiben aber getrennt:
     on-fill gilt für dunkle und neutrale Füllungen (Gefahr, Umschalter,
     Kontrastband), on-accent allein für die Bedienfarbe. Zwei Fragen, zwei Token —
     sonst zieht eine spätere Antwort die andere mit. Dass beide derzeit
     denselben Wert tragen, ist ein Ergebnis, keine Vereinfachung.

     Hier stand zuerst #ffffff mit 3,2:1 auf dem alten Orange — bewusst
     unter der Schwelle, begründet als Marken-Entscheidung, und von jedem
     Lighthouse-Lauf zuverlässig gemeldet. Danach --c-dark (4,63:1), dann
     --c-dark-deep (4,70:1 auf #FF4000), weil die Marke dunkle Schrift
     brauchte.

     Mit #DB3C00 als Bedienfarbe ist wieder Weiß möglich: 4,51:1, AA ohne
     Größenbedingung. Genau darum wurde die Farbe so gewählt. */
  --c-on-accent: #ffffff;
  --c-on-fill: #ffffff;

  /* --- Linien ---
     `--theme-border-color` zeigt auf `--theme-palette-color-5`. Eine Linie
     trägt keinen Text, also gibt es keine Kontrastanforderung, die gegen den
     Bestandswert spräche — hier stand #dde5ec.

     `--c-border-strong` ist etwas anderes: die **Kante eines Eingabefeldes**,
     und die muss als Begrenzung eines Bedienelements 3:1 halten (WCAG 1.4.11).
     Hier stand bis zum 04.10.2026 #C9C4C1 mit 1,73:1 auf Weiß — Befund 1 in
     docs/design/design-system.md § 7. #767676 ist der `control`-Wert der
     CI-Vorlage: 4,54:1 auf --c-raised, 4,15:1 auf --c-sunken. Entschieden, als
     die Redaktion dieselbe Feldkante bekam (K-FORM-11) und der Mangel sonst an
     über hundert Feldern gestanden hätte. Wer eine Zierlinie braucht, nimmt
     --c-border; diese Kante ist für das, was man bedient. */
  --c-border: #E6E1DE;
  --c-border-strong: #767676;
  --c-border-dark: #3A3A3A;

  /* Die Linie **im Kontrastband** — kehrt mit dem Band um (dunkler Satz:
     #E6E1DE). Rein dekorativ, traegt keine Information, keine Schwelle. */
  --c-border-contrast: #3A3A3A;

  /* --- Bedienflächen ---
     Eigene Stufe, absichtlich nicht --c-sunken: dieser Wert ist an mehreren
     Stellen Panel-Hintergrund — etwa die Fußleiste des Block-Inspektors, in
     der Symbolknöpfe sitzen. Knopf und Panel auf derselben Fläche ergäbe
     1,0:1. --c-control behält gegen --c-bg, --c-raised und --c-sunken je
     einen Unterschied. */
  --c-control: #E1E1E1;
  --c-control-hover: #D2D2D2;

  /* Der Zweitknopf **im Kontrastband**. Wechselt mit dem Band die Richtung,
     traegt deshalb dessen Namen und nicht mehr `dark`. Die Schrift darauf
     ist --c-on-contrast: hell #EDEDED auf #3E3E3E (9,14:1), dunkel #333333
     auf #E1E1E1 (9,66:1). */
  --c-control-contrast: #3E3E3E;
  --c-control-contrast-hover: #4A4A4A;

  /* Deaktiviert wird flach gefüllt statt durchscheinend gestellt: 50 %
     Deckkraft ergibt effektiv nur 1,9:1 zwischen Schrift und Fläche,
     --c-muted-strong auf --c-disabled dagegen 7,1:1. */
  --c-disabled: #E6E6E6;

  /* --- Zustände ---
     error 6,5:1 auf --c-bg; error-soft ist die Ruhefläche des Gefahr-Knopfs,
     --c-error darauf 5,7:1. */
  --c-error: #b3261e;
  --c-error-soft: #fdeceb;
  --c-success: #1c7c4a;

  /* --- Schrift ---
     Die Skala des Bestands ist **fest**, nicht fließend: h1 38px auf jeder
     Breite, h2 28px und unter 1000px 25px, h3 26px, h4 24px, h5 22px, h6 18px,
     alle mit Zeilenhöhe 1,35 und ohne Laufweitenkorrektur. Fließtext 16px bei
     1,65.

     Unsere Rollen sind weniger als sechs Ebenen, weil das CMS die Ebene selbst
     vergibt: `display` ist die h1, `h2` jede weitere Abschnittsüberschrift,
     `h3` die Überschrift darin. Die Werte sind die des Bestands für genau
     diese drei Ebenen.

     `h2` bleibt als `clamp` und nicht als Medienabfrage: 25px unter 1000px und
     28px darüber ist derselbe Verlauf, nur ohne Sprung. `display` ist fest —
     der Bestand skaliert die h1 nirgends. */
  --font-sans: 'Catamaran', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  --fs-display: 2.375rem;
  --fs-h2: clamp(1.5625rem, 2.6vw, 1.75rem);
  --fs-h3: 1.625rem;
  --fs-lead: clamp(1.0625rem, 1.4vw, 1.25rem);
  --fs-body: 1rem;
  --fs-small: 0.875rem;
  --fs-eyebrow: 0.8125rem;
  /* Derselbe Wert wie der Eyebrow, eine andere Rolle: Zweitschrift und
     Bedienschrift der Redaktion — Feldhinweise, Zeilen der Gliederung, kleine
     Knöpfe, Reiter der Werkzeugspalte. Ohne eigenen Namen stand er 54-mal als
     Literal in der Redaktion, und ein Eyebrow ist er nicht (K-TXT-01 trägt
     Versalien und die Bedienfarbe). Seit dem 04.10.2026, R-18. */
  --fs-meta: 0.8125rem;
  /* Der kleinste Grad: Kennzeichen (K-TAG-01), Tabellenköpfe, Beschriftungen
     der Redaktion — fast immer in Versalien mit Laufweite. Stand bis zum
     23.09.2026 neunzehnmal als Literal in der Redaktion. */
  --fs-tag: 0.6875rem;

  --lh-display: 1.35;
  --lh-heading: 1.35;
  --lh-body: 1.65;

  --ls-display: 0em;
  --ls-heading: 0em;
  --ls-eyebrow: 0.08em;

  /* --- Abstände, Basis 0.25rem --- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;
  --space-8: 3rem;
  --space-9: 4rem;
  --space-10: 5rem;
  --space-11: 6rem;
  --space-12: 8rem;

  /* Abschnittsrhythmus. Ein Wert je Dichte, nicht je Block — sonst driften
     die Abstände zwischen den Blocktypen auseinander.

     Der Bestand setzt `--theme-content-vertical-spacing` auf 80px, unter
     1000px auf 60px und unter 690px auf 50px. Die drei Stufen sind hier ein
     `clamp` von 50 bis 80 Pixeln; bei 1000px Breite trifft es 60px. */
  --section-y: clamp(3.125rem, 6vw, 5rem);
  --section-y-tight: clamp(2rem, 4vw, 3.125rem);
  --section-y-loose: clamp(3.75rem, 7.5vw, 6.25rem);

  /* --- Maße ---
     1290px ist `--theme-normal-container-max-width`, 750px die schmale
     Fassung (`--theme-narrow-container-max-width`), die im Bestand den
     Fließtext trägt. */
  --width-max: 80.625rem;
  --width-prose: 46.875rem;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);

  --radius-sm: 3px;
  --radius-md: 8px;
  --radius-lg: 16px;

  --shadow-sm: 0 1px 2px rgb(26 26 26 / 0.06), 0 2px 8px rgb(26 26 26 / 0.05);
  --shadow-md: 0 2px 4px rgb(26 26 26 / 0.06), 0 12px 32px rgb(26 26 26 / 0.1);

  --dur: 180ms;
  --dur-slow: 320ms;
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
}
/* ═══════════════════════════════════════════════════════════════════════
   Der dunkle Satz
   ═══════════════════════════════════════════════════════════════════════

   Greift **nur** ueber `[data-theme="dark"]`, absichtlich nicht ueber
   `prefers-color-scheme`. Fuer Besucher aendert sich damit heute nichts; die
   Werte stehen aber real, einmalig und in allen drei Fassungen gleich. Das
   Einschalten fuer Besucher ist eine eigene Entscheidung und braucht einen
   Umschalter, eine zweite Lighthouse-Messung und eine Durchsicht der 27
   Bausteine — nicht nur diesen Block.

   **Die Gruende sind neutrales Grau.** Die Werte kommen aus der
   CI-Vorlage `n1-testseite-thermaldrones.html`, die fuer den dunklen Modus
   eine eigene, bewusst unbunte Palette fuehrt: bg #222222, surface #2C2C2C,
   bgAlt #1B1B1B, bgInvert #101010, text #EDEDED, muted #B0B0B0, line #3A3A3A,
   control #8C8C8C. Sie sind hier zeichengleich uebernommen.

   Bis zum 18.09.2026 galt das nur fuer den dunklen Satz, und der helle fuehrte
   daneben das Navy #192a3d des Bestands-Themes. Beide Saetze sind jetzt
   unbunt, aus demselben Grund: eine grosse Flaeche in Navy ist kein Kontrast,
   sondern ein Farbstich, und die Bedienfarbe stuende darauf auf einem blauen
   statt auf einem neutralen Grund. Jede Farbe, die man sieht, soll eine
   Nachricht sein.

   **Das Band kehrt die Richtung wirklich um.** Hier stand, `[data-tone="dark"]`
   sei auch im dunklen Satz dunkler als der Grund und gehe nach #101010; eine
   Aufhellung sei verworfen worden, weil `--c-accent-on-dark` als Schrift
   darauf fiele. Das war eine Verwechslung von Name und Aufgabe: Aufgabe des
   Bandes ist der **staerkste Gegensatz zum Grund**, nicht „dunkel sein".
   Zweimal dunkel ist kein Gegensatz, sondern eine zweite Abstufung nach
   unten — und daneben steht mit `--c-sunken` schon eine.

   Seit dem 18.09.2026 heisst die Rolle deshalb `--c-contrast` und geht im
   dunklen Satz nach oben: #EDEDED, der Wert, den dieser Satz als --c-ink
   ohnehin fuehrt. Der Einwand von damals war richtig und ist geblieben — die
   Bedienfarbe erreicht darauf 3,85:1 und traegt dort keine Schrift. Er ist
   kein Grund gegen die Aufhellung, sondern die Beschreibung des eingesenkten
   Bandes im hellen Satz (4,12:1), und die Antwort ist dieselbe: die Schrift
   weicht auf neutral aus, das Zeichen bleibt orange (R-02). Aufgeloest ist
   das in --c-accent-on-contrast und --c-mark-on-contrast.

   `--c-dark` bleibt daneben bestehen und meint jetzt nur noch, was der Name
   sagt: einen Grund, der in **beiden** Saetzen dunkel ist — der Platzhalter
   hinter einem ladenden Abschnittsbild, der Bezug des Schleiers, die
   Redaktionsleiste. Ein Bild wird durch den Schleier dunkel und nicht durch
   das Band.

   **Kein einziger neuer Orangewert.** Die Akzentflaeche bleibt #DB3C00 und
   traegt weiter weisse Schrift mit 4,51:1 — dieser Wert haengt am Knopf, nicht
   am Seitengrund. Die Akzentschrift nimmt ueber `--c-accent-text` das bereits
   bestehende #FF6034 (4,64:1 auf dem hellsten der vier Gruende). Einzige
   Ausnahme ist `--c-accent-soft`: eine weiche Flaeche kann im dunklen Satz
   nicht fast weiss sein.

   Kontraste gemessen, nicht geschaetzt; die Tabelle steht in
   docs/design/design-system.md Paragraph 3.2 und wird von
   backend/app/static/styleguide.html im Browser nachgerechnet. */
:root[data-theme="dark"] {
  color-scheme: dark;

  /* --- Flaechen ---
     Die Leiter der Vorlage, Wert fuer Wert. `--c-bg` ist bg, `--c-raised` ist
     surface, `--c-sunken` ist bgAlt. Der Abstand zwischen Grund und gehobener
     Flaeche ist 1,139:1 — mehr als im hellen Satz, wo beide denselben Wert
     tragen und die Abhebung ganz ueber Rahmen und Schatten laeuft. */
  --c-bg: #222222;
  --c-raised: #2c2c2c;
  --c-sunken: #1b1b1b;

  /* Das Kontrastband, aufgehellt: #EDEDED ist der Wert, den dieser Satz als
     --c-ink ohnehin fuehrt — kein neuer Farbwert. Es setzt sich mit 13,59:1
     vom Grund ab; das Band des hellen Satzes erreicht 15,91:1. Die tiefere
     Stufe geht entsprechend nach Weiss. */
  --c-contrast: #EDEDED;

  --c-dark: #101010;
  --c-dark-deep: #080808;

  /* Der Schleier steht hier auf 0,62 und nicht auf 0,55, und er ist neutral
     statt blaeulich. Ueber einer weissen Bildflaeche ergibt das #6b6b6b, und
     --c-on-dark erreicht darauf 4,55:1 — die Schwelle, die der helle Satz mit
     0,55 um 0,91 verfehlt (3,59:1, siehe »Offen« in docs/branding/farben.md).
     Der dunkle Satz ist neu und hat keinen Bestand zu schonen. */
  --c-scrim: rgb(16 16 16 / 0.62);

  /* --- Text ---
     text und muted der Vorlage. --c-ink erreicht 13,59:1 auf --c-bg und
     11,93:1 auf --c-raised, --c-muted 7,34:1 und 6,44:1. --c-muted-strong ist
     die Stufe fuer Beschriftungen auf --c-control und haelt dort 7,67:1. */
  --c-ink: #ededed;
  --c-muted: #b0b0b0;
  --c-muted-strong: #d4d4d4;
  --c-on-dark: #ededed;
  --c-on-dark-muted: #afafaf;

  /* Schrift auf dem Kontrastband — hier kehrt sie sich um. Die Werte sind
     text und muted der CI-Vorlage aus deren **hellem** Satz: #333333 haelt
     auf #EDEDED 10,79:1, #5E5E5E 5,54:1. */
  --c-on-contrast: #333333;
  --c-on-contrast-muted: #5E5E5E;

  /* --- Akzent ---
     Farbige Schrift weicht auf die Stufe fuer dunkle Gruende aus: 5,28:1 auf
     --c-bg, 4,64:1 auf --c-raised, 5,72:1 auf --c-sunken, 6,32:1 auf --c-dark.
     Das ist Regel C, ohne dass ein Selektor sie kennen muss.

     --c-accent-soft ist aus der Bedienfarbe bei gehaltenem Farbton (16,8deg)
     auf Helligkeit 0,10 und halber Buntheit abgeleitet; --c-ink erreicht
     darauf 15,10:1. Sie bleibt an dieselbe Bedingung gebunden wie im hellen
     Satz: nur in Selektoren mit :hover, :active, :focus-visible oder
     :focus-within. */
  --c-accent-text: var(--c-accent-on-dark);

  /* Auf dem hellen Kontrastband weicht die Schrift aus und das Zeichen
     bleibt stehen — dieselbe Teilung wie im eingesenkten Band des hellen
     Satzes, nur mit vertauschten Rollen. Die Bedienfarbe erreicht auf
     #EDEDED 3,85:1: unter 4,5 fuer Schrift, ueber 3 fuer ein Zeichen. */
  --c-accent-on-contrast: var(--c-on-contrast);
  --c-mark-on-contrast: var(--c-accent);

  --c-accent-soft: #26140d;

  /* --- Linien ---
     line und control der Vorlage. --c-border-strong traegt die Kante eines
     Eingabefeldes und muss 3:1 gegen die Flaeche halten (WCAG 1.4.11);
     #8c8c8c erreicht 4,15:1 auf --c-raised und 4,73:1 auf --c-bg.

     Der helle Satz traegt seit dem 04.10.2026 #767676 (4,54:1, Befund 1 in
     docs/design/design-system.md Paragraph 7 erledigt). */
  --c-border: #3a3a3a;
  --c-border-strong: #8c8c8c;
  --c-border-dark: #333333;

  /* Die Linie **im Kontrastband** kehrt mit ihm um: hell #3A3A3A auf
     #222222, dunkel #E6E1DE auf #EDEDED. Rein dekorativ, keine Schwelle. */
  --c-border-contrast: #E6E1DE;

  /* --- Bedienflaechen ---
     --c-ink erreicht auf --c-control 9,72:1, --c-on-contrast auf
     --c-control-contrast 9,66:1. Dass die Knopfflaeche selbst sich mit 1,40:1
     kaum vom Grund abhebt, ist kein neuer Mangel — im hellen Satz sind es
     1,31:1. Notiert als Befund 10. */
  --c-control: #3a3a3a;
  --c-control-hover: #474747;

  /* Der Zweitknopf im Kontrastband, mit dem Band aufgehellt. --c-on-contrast
     erreicht auf #E1E1E1 9,66:1. */
  --c-control-contrast: #E1E1E1;
  --c-control-contrast-hover: #D2D2D2;
  --c-disabled: #2e2e2e;

  /* --- Zustaende ---
     Beide aus dem hellen Wert bei gehaltenem Farbton und gehaltener Buntheit
     aufgehellt, bis auf dem hellsten der Gruende (--c-raised) 4,8:1 stehen —
     also mit Luft ueber der Schwelle statt knapp darauf. Auf --c-bg sind es
     5,47:1 und 5,50:1. */
  --c-error: #e7766f;
  --c-error-soft: #331715;
  --c-success: #27ad67;

  /* --- Schatten ---
     Auf dunklem Grund traegt ein blaeulicher Schatten nicht: #16222e liegt zu
     nah an der Flaeche. Hier ist es Schwarz mit hoeherer Deckkraft. Die
     Geometrie bleibt Zeichen fuer Zeichen dieselbe, damit sich nur die Farbe
     aendert und nicht die Hoehe. */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.30), 0 2px 8px rgb(0 0 0 / 0.26);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 0.32), 0 12px 32px rgb(0 0 0 / 0.46);
}

/* ==== TOKENS END ==== */

@layer base, layout, components, blocks, content, utils;

/* --- Schrift -----------------------------------------------------------------
   Catamaran ist die Marken-Schrift und wird selbst ausgeliefert: kein
   Drittanbieter-Request, keine zweite Verbindung, kein Datenschutz-Thema.

   Der Pfad trägt bewusst KEINEN `?v=`-Stempel, obwohl `/static` ein Jahr
   `immutable` ausgeliefert wird. Grund: `partials/head.html` lädt dieselbe
   Datei vorab, und ein Preload greift nur bei zeichengleicher URL — mit
   Stempel hier und ohne dort würde die Schrift zweimal geladen. Beim Austausch
   der Schrift daher den Dateinamen ändern. */

@font-face {
  font-family: 'Catamaran';
  src: url('fonts/catamaran-var.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@layer base {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
  }

  /* --- Der Doppelpfeil ------------------------------------------------------

     Die Form des Pfeilverweises, einmal für beide Stellen, die ihn tragen:
     `.arrow-link` (K-BTN-05) und den Videoverweis ohne Standbild (K-MEDIA-03).
     Zwei Regeln mit demselben Pfad wären zwei Pfeile, die irgendwann
     auseinanderlaufen.

     Material Symbols Outlined `keyboard_double_arrow_right`, wght 400, opsz 24,
     Apache-2.0. **Eingebettet und nicht geladen** — R-13 verbietet den Aufruf
     beim Dritten, nicht das Übernehmen eines Pfades. Dieselbe Linie wie bei den
     vier Sozialzeichen der Fußzeile.

     Nicht in `design/tokens.css`: dort stehen Farb- und Maßwerte, die
     zeichengleich in zwei weitere Dateien kopiert werden, und ein Glyphenpfad
     hat in der Redaktionsoberfläche nichts verloren.

     Als **Maske** und nicht als Bild: ein `background-image` trüge eine feste
     Farbe und verstieße gegen R-08. Über `background: currentColor` nimmt der
     Pfeil die Farbe seines Links mit — auf Weiß die Bedienfarbe, im
     eingesenkten Band `--c-dark`, im Kontrastband `--c-accent-on-dark`, über
     einem Bild `--c-on-dark`. Vier Gründe, keine einzige Sonderregel. */
  :root {
    --icon-doppelpfeil: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M383-480 200-664l56-56 240 240-240 240-56-56 183-184Zm264 0L464-664l56-56 240 240-240 240-56-56 183-184Z'/%3E%3C/svg%3E");
  }

  body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    font-family: var(--font-sans);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    color: var(--c-ink);
    background: var(--c-bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    /* R-20: Ein Wort, das breiter ist als seine Spalte, bricht notfalls
       mitten im Wort, statt die Seite zu verbreitern. Sonst greift das nie —
       `break-word` gilt erst, wenn kein anderer Umbruch mehr möglich ist. Bei
       200 % Systemschrift stand „Organisationsmitglieder/Ehrenamtlichen/…"
       644 px breit, und Chrome zoomte die ganze Seite heraus. */
    overflow-wrap: break-word;
  }

  /* R-20: Silbentrennung auf dem Handy. Deutsche Komposita („Seeadler-
     monitoring", 556 px bei 200 % Systemschrift) passen dort sonst nicht in
     eine Zeile. Trennt erst ab zehn Zeichen und lässt mindestens vier
     stehen, damit kein „Wär-me…" entsteht. `lang` setzt `base.html`. */
  @media (width < 40rem) {
    body {
      hyphens: auto;
      hyphenate-limit-chars: 10 4 4;
    }
  }

  main {
    flex: 1;
  }

  h1,
  h2,
  h3,
  h4 {
    font-weight: 700;
    line-height: var(--lh-heading);
    letter-spacing: var(--ls-heading);
    text-wrap: balance;
    margin: 0;
  }

  p {
    text-wrap: pretty;
    margin: 0;
  }

  /* Links tragen die Bedienfarbe, wie in der Vorlage. Möglich ist das durch
     den weißen Grund: #DB3C00 erreicht darauf 4,51:1 und ist damit als
     Schrift jeder Größe zulässig. Auf dem alten Grund #fafbfc waren es
     4,35:1, und die Regel hieß deshalb: neutrale Schrift, akzentfarbene
     Linie. Hier stand davor sogar `--c-accent-text`, ein abgedunkeltes
     Orange — das ist nicht wiedergekommen und muss es nicht.

     Zwei Bänder weichen weiter aus, jedes mit eigener Regel: das dunkle auf
     `--c-accent-on-dark`, das eingesenkte auf die neutrale Schrift. Regel C
     in docs/branding/farben.md. */
  a {
    color: var(--c-accent);
    text-decoration-color: var(--c-mark);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
  }

  a:hover {
    text-decoration-color: var(--c-mark);
    text-decoration-thickness: 2px;
  }

  ul,
  ol {
    margin: 0;
  }

  img,
  svg,
  video {
    max-width: 100%;
    height: auto;
  }

  /* Hier stand eine Ladefläche (`background: var(--c-sunken)`) hinter jedem
     Bild: eine ruhige Fläche, bis das Bild da ist, statt eines weißen Lochs.
     Sie ist entfernt, und zwar ersatzlos.

     CSS kennt keinen Zustand „geladen". Die Fläche verschwindet also nie, sie
     liegt dauerhaft hinter dem Bild — bei einem deckenden Foto unsichtbar, bei
     einem transparenten PNG als graues Motivumfeld. Genau das war der Fehler.

     Ein Selektor, der die Fläche nur den „sicheren" Bildern gibt, existiert
     nicht. Naheliegend wäre der von der Vorlage beschnittene Kasten — feste
     `aspect-ratio` plus `object-fit: cover` —, aber `cover` füllt den Kasten
     nur geometrisch, nicht deckend: transparente Pixel bleiben transparent.
     Im Bestand steht der Gegenbeweis, transparente PNGs in `.card__image` auf
     `/kuenstliche-intelligenz/` und `/unsere-produkte/`. Und jedes Bild dieser
     Seite kommt aus der Mediathek, also aus der Redaktion — deckend ist
     nirgends zugesichert.

     Verloren geht dabei nichts als das Grau während des Ladens: `width` und
     `height` stehen an jedem `<img>` der Vorlagen, der Platz bleibt also
     reserviert, das Layout springt nicht.

     Soll die Ladefläche zurück, dann nicht über einen Selektor, sondern über
     Wissen, das nur der Server hat: `media.mime_type` liegt in `blocks.py`
     bereits an der Vorlage, echte Alphaprüfung beim Hochladen wäre genauer.
     Das Bild sagt dann selbst, ob es eine Fläche verträgt. */

  blockquote,
  figure {
    margin: 0;
  }

  :focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 3px;
    border-radius: 2px;
  }

  ::selection {
    background: var(--c-accent);
    color: var(--c-on-accent);
  }

  /* Bewegung ist hier durchweg Zierde, nie Information — sie darf komplett
     entfallen, ohne dass etwas fehlt. */
  @media (prefers-reduced-motion: reduce) {
    html {
      scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
    }
  }
}

@layer layout {
  /* Ein Container für alles. Vorher wiederholte jeder Block dieselben drei
     Zeilen, was die Breite pro Block driften ließ. */
  .shell {
    width: 100%;
    max-width: var(--width-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }

  .shell--prose {
    max-width: calc(var(--width-prose) + 2 * var(--gutter));
  }

  /* Die Dichte eines Abschnitts — K-LAYOUT-03, gewählt von der Redaktion über
     `density` und ausgegeben von `flaeche()` als `data-density`.

     **Sie steht in einer Custom-Property und nicht in einer Nachfahren-Regel**
     (R-15). Der Unterschied ist die ganze Absicht: eine Custom-Property erbt
     von selbst an jedes eingesetzte Kind, und ein Kind, das sie neu
     deklariert, gewinnt für seinen eigenen Teil. `[data-density='loose'] .block`
     täte das Erste auch — aber das Kind könnte sich nicht daraus lösen, und
     genau das soll es können.

     Kein Wert an `:root` und keiner an `.block`: eine Vorbelegung am Baustein
     selbst zerstörte die Vererbung, weil jedes Kind sie zurücksetzte. Der
     Regelfall steht deshalb als Rückfall in der `var()`-Kette unten. */
  /* `none` ist eine Null und kein fehlender Wert: sie muss als Wert dastehen,
     sonst griffe der Rückfall in der `var()`-Kette und es gälte der Regelwert. */
  [data-density='none'] {
    --rhythm: 0px;
    --rhythm-inner: 0px;
  }

  [data-density='tight'] {
    --rhythm: var(--section-y-tight);
    --rhythm-inner: var(--space-4);
  }

  [data-density='normal'] {
    --rhythm: var(--section-y);
    --rhythm-inner: var(--space-5);
  }

  [data-density='loose'] {
    --rhythm: var(--section-y-loose);
    --rhythm-inner: var(--space-6);
  }

  /* Der Rhythmus steht in einer Variablen, damit ein Kontext ihn als Ganzes
     ändern kann, ohne die Rücknahmen darunter anzufassen: im Beitrag trennt der
     Abstand Absätze eines Artikels und nicht Abschnitte einer Landingpage
     (siehe `.post`).

     Die Kette liest sich von innen nach außen: was ein Kontext setzt
     (`--block-y`, etwa `0` für einen eingesetzten Baustein), schlägt die
     gewählte Dichte, und die schlägt den Regelwert. */
  .block {
    padding-block: var(--block-y, var(--rhythm, var(--section-y)));
  }

  /* Zwei Abschnitte derselben Fläche hintereinander sollen nicht die doppelte
     Luft ergeben — der zweite rückt auf. Bei einem Farbwechsel bleibt der
     Abstand, denn dort trennt er zwei Flächen und ist keine leere Lücke.
     Die Fälle stehen einzeln, weil CSS Attributwerte zweier Geschwister nicht
     miteinander vergleichen kann.

     Ein Abschnitt mit Bild ist keine Fläche des Kontrastbandes, auch wenn er
     `data-tone="contrast"` trägt — der Aufmacher bringt sein Foto über
     `data-has-media` statt über `data-bg`. Ohne ihn in der Ausnahme klebte
     ein Kontrastband darunter ohne Abstand an der Unterkante des Fotos. */
  .block:not([data-tone]) + .block:not([data-tone]),
  [data-tone='raised'] + [data-tone='raised'],
  [data-tone='sunken'] + [data-tone='sunken'],
  [data-tone='contrast']:not([data-bg], [data-has-media])
    + [data-tone='contrast']:not([data-bg], [data-has-media]) {
    padding-block-start: 0;
  }

  [data-tone='raised'] {
    background: var(--c-raised);
  }

  [data-tone='sunken'] {
    background: var(--c-sunken);
  }

  /* Das eingesenkte Band ist der eine helle Grund, der die Bedienfarbe als
     Schrift nicht trägt: #DB3C00 erreicht auf #f2f5f7 4,12:1. Einen
     eingesenkten Ton, der sie trägt, gibt es nicht — er müsste heller als
     #fefefe sein und wäre damit nicht mehr eingesenkt. Also wird
     ausgewichen, wie im dunklen Band, nur in die andere Richtung: dort
     `--c-accent-on-dark`, hier die neutrale Schrift.

     Die Regel steht hier in `layout` und gewinnt damit gegen `a` aus `base`.
     `.archive__item h2 a` und `.block-post-list__title a` stehen in `content`
     und damit später — Titel-Links bleiben neutral wie überall. Die Ausnahmen
     für Eyebrow, Stern und Zeitstrahlmarke stehen jeweils bei der Regel, die
     sie überschreiben; von hier aus erreichten sie sie nicht, weil die
     Schichtenfolge über der Spezifität steht. */
  [data-tone='sunken'] a {
    color: var(--c-ink);
  }

  /* Das Zeichen weicht hier aus wie die Schrift, nur eine Stufe frueher:
     #DB3C00 haelt auf --c-dark 3,24:1 und waere als Kante zulaessig, aber der
     Eyebrow-Text daneben steht laengst in --c-accent-on-dark. Ein Strich in
     einem anderen Orange als seine Beschriftung liest sich als Fehler.

     Die Deklaration steht am getoenten Abschnitt selbst und nicht an seinen
     Nachfahren (R-15): ein eingesetzter Baustein kann sie damit zuruecknehmen.
     Die uebrigen Toenungsregeln koennen das nicht — Befund 12. */
  [data-tone='contrast'] {
    background: var(--c-contrast);
    color: var(--c-on-contrast);
    --c-mark: var(--c-mark-on-contrast);
    /* Gedämpfte Schrift im Band. 27 Regeln nehmen `color: var(--c-muted)`,
       und nur fünf hatten eine eigene Umkehr fürs Band — die übrigen stünden
       dort mit #5E5E5E auf #222222 (2,6:1; Lighthouse am 06.10.2026: Text im
       Bild-Text-Abschnitt, Beschriftungen im Kontaktblock). Das Token am
       Band selbst umzustellen erreicht alle auf einmal (R-15, Befund 12). */
    --c-muted: var(--c-on-contrast-muted);
  }

  /* Ein eingesetzter Baustein mit eigener heller Fläche nimmt die Umstellung
     zurück — eine Karte (`raised`) im Band hat wieder den Grund des Bandes
     nicht unter sich. `--c-muted-grund` ist der Wert am Wurzelelement, also
     der des gewählten Satzes. */
  :root {
    --c-muted-grund: var(--c-muted);
  }

  [data-tone]:not([data-tone='contrast']) {
    --c-muted: var(--c-muted-grund);
  }

  [data-tone='contrast'] :is(h1, h2, h3) {
    color: var(--c-on-contrast);
  }

  /* Auf Navy reicht die Bedienfarbe als Schrift nicht: #DB3C00 erreicht auf
     --c-dark nur 3,24:1. Dafür gibt es `--c-accent-on-dark` (#FF6034,
     4,84:1) — eine dauerhafte Stufe der Bedienfarbe, keine Abwandlung der
     Marke; der Unterschied steht in tokens.css. */
  [data-tone='contrast'] a {
    color: var(--c-accent-on-contrast);
  }

  /* --- Hintergrundbild eines Abschnitts -----------------------------------

     Jeder Abschnitt kann ein Bild hinter seinem Inhalt tragen
     (`partials/flaeche.html`). Das Bild ist ein `<img>` und kein
     CSS-`background-image` — nur so greifen `srcset` und damit AVIF und die
     Breitenwahl. Es wird hier hinter den Inhalt gelegt statt davor.

     Die Textfarben kommen NICHT von hier: der Helfer setzt bei einem Bild
     immer `data-tone="contrast"`, und damit gelten die siebzehn Regeln darüber und
     darunter unverändert weiter — Überschrift, Link, Eyebrow, Vorspann,
     Schaltflächen. Eine zweite Umkehrung für den Bildfall wäre eine zweite
     Wahrheit über dieselbe Frage. */
  /* Ueber einem Bild faellt die Bedienfarbe auf 1,07:1 — dort traegt auch das
     Zeichen die neutrale helle Schrift. Steht nach dem Kontrastband, weil ein
     Abschnitt mit Bild beides ist. Eine Textebene ueber einem Bild im
     Ebenen-Block traegt `data-ueber-bild`; dieselbe Klammer wie beim Eyebrow
     weiter unten. */
  /* Ein Abschnitt mit Bild ist in **beiden** Saetzen dunkel — dunkel macht ihn
     der Schleier und nicht das Kontrastband. `flaeche()` setzt ihm zwar
     `data-tone="contrast"` auf, damit die siebzehn Regeln des Bandes ohne
     zweite Umkehrung gelten; im dunklen Satz zeigt das Band aber nach oben,
     und dann stuende dunkle Schrift auf einem abgedunkelten Foto.

     Die vier Rollen-Token werden hier deshalb auf ihre Grund-gebundenen
     Zwillinge zurueckgenommen. Das geht, weil sie Custom-Properties sind und
     am Abschnitt selbst stehen — R-15 in einer Zeile: ein Nachfahre liest
     `var(--c-on-contrast)` wie zuvor und bekommt hier einen anderen Wert.
     Mit Nachfahren-Regeln waere dafuer jede der siebzehn Regeln ein zweites
     Mal zu schreiben (Befund 12).

     Die Flaeche selbst nimmt --c-dark: sichtbar ist sie nur, solange das Bild
     laedt, und ein Aufblitzen in Hellgrau waere genau das, was der
     Platzhalter an `.block__bg` verhindern soll. */
  :is([data-bg], [data-ueber-bild]) {
    --c-mark: var(--c-on-dark);
    --c-on-contrast: var(--c-on-dark);
    --c-on-contrast-muted: var(--c-on-dark-muted);
    --c-accent-on-contrast: var(--c-on-dark);
    --c-contrast: var(--c-dark);
  }

  [data-tone='contrast'][data-bg] {
    background: var(--c-dark);
  }

  [data-bg] {
    position: relative;
    /* Ohne `isolation` reicht ein `z-index` im Inhalt aus dem Abschnitt heraus
       und legt sich über die Redaktionsleiste. */
    isolation: isolate;
    overflow: hidden;
  }

  .block__bg {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
    /* Bis das Bild da ist, steht die Fläche schon dunkel — heller Text auf Weiß
       für den Bruchteil einer Sekunde ist sonst ein Aufblitzen. */
    background: var(--c-dark);
    z-index: -2;
  }

  /* Abdunklung. Ohne sie steht heller Text über einem hellen Bildausschnitt,
     und der Kontrast ist Glückssache. Ein gleichmäßiger Schleier und kein
     Verlauf: wo der Text im Abschnitt sitzt, weiß diese Regel nicht — der
     Ebenen-Block (K-LAYOUT-11.T2) hat seinen eigenen Verlauf, weil er seinen
     Text kennt. */
  [data-bg]::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--c-scrim);
  }

  /* Über einem Bild gibt es keinen bekannten Grund mehr, und der Schleier ist
     auf `--c-on-dark` gerechnet und nicht auf das Orange: über einem hellen
     Bildausschnitt bleibt eine Fläche von #8a9099, und darauf erreicht
     `--c-accent-on-dark` 1,07:1 — die Bedienfarbe liegt zu dicht an einem
     mittleren Grau. Auf einem Bild tragen Links und Eyebrow deshalb die
     neutrale helle Schrift (4,6:1 im schlechtesten Fall, so ist 0,55 am
     Schleier bemessen). Farbe hat hier ohnehin das Bild.

     Der Aufmacher trägt sein Bild nicht über `[data-bg]`, sondern über
     `[data-has-media]` und einen eigenen Verlauf; er steht deshalb mit in der
     Regel. Heute kann er keinen Link enthalten — seine Felder sind Eyebrow,
     Überschrift, Unterzeile und eine Schaltfläche —, aber die Regel soll
     nicht davon abhängen, welche Felder ein Baustein gerade hat.

     Die Regel steht hinter `[data-tone='contrast'] a` und gewinnt bei gleicher
     Spezifität als die spätere; `.btn` steht in `components` und bleibt
     unberührt. Die Ausnahmen für Eyebrow, Stern und Zeitstrahlmarke stehen
     bei deren eigenen Regeln. */
  :is([data-bg], [data-ueber-bild]) a {
    color: var(--c-on-dark);
  }
}

@layer components {
  /* --- Eyebrow ---
     Das kurze Label über der Überschrift, das Element, das die Farbe am
     stärksten trägt. Es steht in der Bedienfarbe: 13 px sind normaler Text
     und brauchen 4,5:1, auf dem weißen Grund sind es 4,51:1. Eine Zeit lang
     war es neutral, weil der Grund #fafbfc nur 4,35:1 hergab. Auf dunklem
     Grund trägt es `--c-accent-on-dark` (4,84:1), im eingesenkten Band
     neutrale Schrift — beides ein paar Regeln weiter oben. */
  .eyebrow {
    font-size: var(--fs-eyebrow);
    font-weight: 600;
    letter-spacing: var(--ls-eyebrow);
    text-transform: uppercase;
    color: var(--c-accent);
    margin-block-end: var(--space-3);
  }

  /* Der Doppelpfeil davor — das Zeichen, das die Bedienfarbe traegt, wo die
     Schrift sie nicht tragen darf. Auf dem eingesenkten Band weicht der Text auf
     --c-muted-strong aus (4,12:1 sind fuer Schrift zu wenig); der Pfeil bleibt
     orange, weil ein Zeichen nur 3:1 braucht. Genau das ist R-02, und genau das
     fehlte dem Band bisher.

     `inline-block` und nicht `flex`: der Eyebrow eines Textabschnitts wird ueber
     `text-align` mittig oder rechts gestellt (`[data-align]` in der Schicht
     `content`), und `text-align` richtet keine Flex-Zeile aus. Im Textfluss
     wandert der Strich mit, ohne dass eine der beiden Regeln davon weiss.

     Als Pseudoelement und nicht als Element — wie der Punkt der Zeitleiste: es
     ist Zierde, ein Vorleseprogramm muesste ein Element vorlesen. Die
     Inline-Bearbeitung fasst `data-field="eyebrow"` an und sieht es nicht. */
  .eyebrow::before {
    content: '';
    display: inline-block;
    vertical-align: middle;
    /* Dieselben 1,725em wie am Pfeil-Link (K-BTN-05) und am Videoverweis
       (K-MEDIA-03). Der Wert ist ein Vielfaches des **eigenen** Schriftgrads,
       also traegt der Eyebrow bei 13 px dasselbe Groessenverhaeltnis zwischen
       Zeichen und Schrift wie „Mehr erfahren" bei 14 px — gemessen 1,26 mal die
       Versalhoehe an beiden Stellen. Vorher waren es 1,15em und damit 0,83: der
       Pfeil blieb unter der Versalhoehe und las sich als anderes Zeichen.

       Sichtbar ist nur die Haelfte davon. Der viewBox der Material Symbols ist
       960 x 960, die Keilform darin misst 480 x 560 und steht mittig — der
       Kasten ist also doppelt so hoch wie der Pfeil, den man sieht. */
    inline-size: 1.725em;
    block-size: 1.725em;
    margin-inline-end: var(--space-2);
    background: var(--c-mark);
    -webkit-mask: var(--icon-doppelpfeil) center / contain no-repeat;
    mask: var(--icon-doppelpfeil) center / contain no-repeat;
    /* Derselbe Ausgleich wie am Pfeil-Link, und hier stimmt er sogar genauer:
       der Eyebrow steht in Versalien, hat also gar keine x-Hoehe, an der
       `vertical-align: middle` sich ausrichten koennte.

       Der Wert haengt an der Schrift und nicht an der Groesse des Kastens —
       deshalb blieb er beim Vergroessern von 1,15em auf 1,725em stehen. Am
       gerenderten Text nachgemessen: die Mitte des Pfeils liegt 0,10 px ueber
       der Mitte des Versalbandes, vorher waren es 0,15 px. Ohne den Ausgleich
       waeren es 1,25 px. */
    transform: translateY(-0.09em);
  }

  [data-tone='contrast'] .eyebrow {
    color: var(--c-accent-on-contrast);
  }

  /* Im eingesenkten Band trägt die Bedienfarbe keine Schrift (4,12:1) und es
     gibt keine hellere Stufe von ihr — also neutral, 6,02:1. Begründung bei
     `[data-tone='sunken']` in der Schicht `layout`. */
  [data-tone='sunken'] .eyebrow {
    color: var(--c-muted-strong);
  }

  /* Über einem Bild die neutrale helle Schrift — Begründung bei `[data-bg]`
     in der Schicht `layout`. Der Aufmacher bringt sein Bild nicht über
     `[data-bg]`, sondern über `[data-has-media]` und einen eigenen Verlauf;
     er braucht die Regel genauso. Dort, wo sein Text sitzt, deckt der Verlauf
     0,74 und `--c-on-dark` erreicht 6,25:1 — `--c-accent-on-dark` käme über
     einer hellen Bildfläche auf 2,33:1. */
  :is([data-bg], [data-ueber-bild]) .eyebrow {
    color: var(--c-on-dark);
  }

  /* --- Vorspann --- */
  .lead {
    font-size: var(--fs-lead);
    line-height: 1.5;
    color: var(--c-muted);
    max-width: 46ch;
  }

  [data-tone='contrast'] .lead {
    color: var(--c-on-contrast-muted);
  }

  /* --- Schaltflächen --- */
  .btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.8rem 1.5rem;
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    border: 0;
    /* 8px wie im Bestand (`--theme-button-border-radius`), nicht der kleine
       Radius der Eingabefelder. */
    border-radius: var(--radius-md);
    /* Mindesthöhe statt reiner Polsterung, damit primär und sekundär auch
       bei ungleichen Schriftgrößen auf einer Linie sitzen. */
    min-block-size: 2.75rem;
    justify-content: center;
    cursor: pointer;
    transition:
      background var(--dur) var(--ease),
      box-shadow var(--dur) var(--ease),
      transform 90ms var(--ease),
      color var(--dur) var(--ease);
  }

  /* Kleiner Schnitt für die Kopfzeile. Die Höhe bleibt bei 2.5rem und damit
     über der Zielflächen-Untergrenze; nur die Polsterung schrumpft. */
  .btn--sm {
    padding: 0.5rem 1rem;
    font-size: var(--fs-small);
    min-block-size: 2.25rem;
    border-radius: 6px;
  }

  /* Die Fläche trägt die Bedienfarbe #DB3C00, und darauf ist weiße Schrift
     wieder möglich: 4,51:1. Genau dafür wurde die Farbe von der Marke
     getrennt — die Begründung steht in tokens.css.

     Der Ruheschatten war orange eingefärbt (`rgb(242 101 34 / 0.28)`, noch
     im alten Markenton):
     über Weiß ein dauerhaft sichtbares, aufgehelltes Orange. Er ist jetzt
     neutral wie --shadow-sm. */
  .btn--primary {
    background: var(--c-accent);
    color: var(--c-on-accent);
    box-shadow:
      0 1px 2px rgb(26 26 26 / 0.16),
      0 3px 8px rgb(26 26 26 / 0.12);
  }

  /* Der Hover dunkelt ab — die Richtung hängt an der Schriftfarbe: Weiß
     erreicht auf #CA3700 5,18:1 statt 4,51:1 auf der Ruhefläche. Der farbige
     Schein darf hier bleiben, er vergeht mit dem Zeiger. */
  .btn--primary:hover {
    background: var(--c-accent-hover);
    color: var(--c-on-accent);
    box-shadow:
      0 2px 4px rgb(26 26 26 / 0.14),
      0 8px 20px rgb(219 60 0 / 0.32);
  }

  /* `ghost` ist der in Inhalten gespeicherte Name dieser Rolle
     (`button_style` in core/constants.py). Beide Selektoren tragen deshalb
     dieselbe Gestalt — sonst würden bestehende Bausteine stillos. */
  .btn--secondary,
  .btn--ghost {
    background: var(--c-control);
    color: var(--c-ink);
  }

  .btn--secondary:hover,
  .btn--ghost:hover {
    background: var(--c-control-hover);
    color: var(--c-ink);
  }

  [data-tone='contrast'] .btn--secondary,
  [data-tone='contrast'] .btn--ghost {
    background: var(--c-control-contrast);
    color: var(--c-on-contrast);
  }

  [data-tone='contrast'] .btn--secondary:hover,
  [data-tone='contrast'] .btn--ghost:hover {
    background: var(--c-control-contrast-hover);
    color: var(--c-on-contrast);
  }

  /* Der Druck ist fühlbar: der Knopf senkt sich um ein Pixel und legt den
     Schatten ab. Das ersetzt die Rand-Umkehr des alten Systems. */
  .btn:active {
    transform: translateY(1px);
  }

  .btn--primary:active {
    box-shadow: 0 1px 1px rgb(26 26 26 / 0.2);
  }

  .btn:disabled,
  .btn[aria-disabled='true'] {
    background: var(--c-disabled);
    color: var(--c-muted-strong);
    box-shadow: none;
    transform: none;
    cursor: not-allowed;
  }

  /* Zweischichtiger Ring: die Fuge in Grundfarbe trennt ihn von der
     Knopffläche (3,0:1), damit er auch auf dem Orange steht. Der Ring selbst
     erreicht 5,0:1 gegen den Grund. */
  .btn:focus-visible,
  .arrow-link:focus-visible {
    outline: none;
    box-shadow:
      0 0 0 2px var(--c-bg),
      0 0 0 4px var(--c-accent);
  }

  [data-tone='contrast'] .btn:focus-visible,
  [data-tone='contrast'] .arrow-link:focus-visible {
    box-shadow:
      0 0 0 2px var(--c-contrast),
      0 0 0 4px var(--c-accent);
  }

  /* --- Pfeil-Link ---
     „Mehr erfahren →" statt einer flächigen Schaltfläche. Der Pfeil ist ein
     Pseudo-Element, damit er nicht im Text- oder Vorlesefluss landet. */
  /* Kein Flex-Kasten. Der Pfeil steht **im Textfluss** und nicht als zweites
     Flex-Kind daneben — aus zwei Gruenden, die beide erst am gerenderten Text
     sichtbar wurden.

     Erstens der Umbruch: ein Verweis, dessen Beschriftung zweizeilig wird,
     haengte seinen Pfeil mit `align-items: center` genau zwischen die beiden
     Zeilen, freischwebend neben dem Text. Im Textfluss folgt er dem letzten
     Wort, wie jedes andere Zeichen.

     Zweitens der Sitz: `align-items` richtet an der Zeilenbox aus, und die
     reserviert unter der Grundlinie Platz fuer Unterlaengen. `vertical-align`
     richtet an der Schrift aus. Der Wert haengt damit an der Schrift und nicht
     an der Groesse des Zeichens — vergroessert man den Pfeil, sitzt er weiter
     richtig. */
  /* Fließtextgröße wie der Text, unter dem er steht. Mit 14 px war er kleiner
     als die Knöpfe der Bestandsseite (15 px); seit dem 05.10.2026. */
  .arrow-link {
    display: inline;
    font-weight: 600;
    font-size: var(--fs-body);
    text-decoration: none;
  }

  /* Der Doppelpfeil, ohne Scheibe. Die Form steht als `--icon-doppelpfeil` in
     `@layer base`; hier steht nur, wie groß sie ist und wohin sie geht.

     Vorher saß ein `→` in einer runden Fläche von 1,4 rem, die beim Überfahren
     in der Bedienfarbe vollief. Mit ihr sind vier Regeln entfallen — die
     Ruhefläche, ihre Füllung im Hover und die beiden Fassungen für das dunkle
     Band.

     Die Farbe kommt aus `--c-mark` und nicht aus `currentColor`. Auf drei der
     vier Flächen ist das derselbe Wert wie die Beschriftung daneben — auf Weiß
     die Bedienfarbe, auf Navy `--c-accent-on-dark`, über einem Abschnittsbild
     `--c-on-dark`, wo früher eine deckende Scheibe die 4,84:1 sicherte.

     Auseinander gehen die beiden nur im eingesenkten Band: dort weicht die
     **Schrift** auf `--c-dark` aus, weil die Bedienfarbe auf #F7F4F2 nur 4,12:1
     erreicht — für Schrift zu wenig. Ein **Zeichen** braucht 3:1 und darf
     stehen bleiben. Genau das ist R-02, und der Eyebrow darüber macht es seit
     jeher so; der Pfeil zog bisher als einziger nicht mit.

     `-webkit-mask` daneben, weil Safari die ungepräfixte Kurzform erst ab 15.4
     kennt. Es ist die einzige Präfix-Zeile im Stylesheet. */
  .arrow-link::after {
    content: '';
    display: inline-block;
    vertical-align: middle;
    margin-inline-start: var(--space-2);
    inline-size: 1.725em;
    block-size: 1.725em;
    background: var(--c-mark);
    -webkit-mask: var(--icon-doppelpfeil) center / contain no-repeat;
    mask: var(--icon-doppelpfeil) center / contain no-repeat;
    /* `vertical-align: middle` setzt die Mitte des Kastens auf die Mitte der
       **x-Hoehe**. Neben einer Beschriftung mit Versalien sitzt er dort eine
       Spur zu tief; 0,09 em heben ihn auf die Mitte der **Versalhoehe**.

       Der Wert ist die halbe Differenz zwischen Versal- und x-Hoehe der
       Catamaran (0,678 em gegen 0,498 em, am gerenderten Text gemessen). Er ist
       damit eine Eigenschaft der Schrift und gilt in jeder Groesse — wer den
       Pfeil groesser stellt, muss ihn nicht neu suchen. */
    transform: translateY(-0.09em);
    transition: transform var(--dur) var(--ease);
  }

  /* Die Bewegung ist die ganze Rückmeldung: der Pfeil rückt in die Richtung, in
     die der Verweis führt (§ 2.6, „Bewegung erklärt oder sie ist falsch"). Der
     Text steht still — ein wandernder Textblock neben ruhigen Nachbarn in einer
     Karte fiele auf.

     Bei `prefers-reduced-motion: reduce` bleibt damit beim Überfahren nichts zu
     sehen; der Block in `@layer base` dreht jede Dauer auf 0,01 ms. Das ist
     entschieden und kein Versehen — der **Fokus** trägt weiter seinen
     zweischichtigen Ring, und nur der ist eine Anforderung (R-09, 2.4.7). */
  .arrow-link:hover::after {
    transform: translateY(-0.09em) translateX(0.35em);
  }

  /* --- Abschnittskopf --- */
  .section-head {
    max-width: 34ch;
    margin-block-end: var(--space-8);
  }

  .section-head__title {
    font-size: var(--fs-h2);
  }

  .section-head__intro {
    margin-block-start: var(--space-4);
    color: var(--c-muted);
    max-width: 58ch;
  }

  /* --- Redaktionsleiste ---------------------------------------------------

     Sichtbar nur für angemeldete Redakteure; `site.js` hängt sie über der
     Kopfzeile ein, das ausgelieferte HTML kennt sie nicht (Begründung im Kopf
     von `web/adminbar.py`).

     Warum die Regeln trotzdem hier stehen und nicht in einem eigenen, nur bei
     Bedarf nachgeladenen Stylesheet: die Höhe muss VOR dem ersten Zeichnen
     feststehen. `site.js` stellt den leeren Kasten sofort hin und füllt ihn,
     wenn die Antwort eintrifft — käme die Höhe erst mit einem zweiten
     Stylesheet, spränge die ganze Seite genau dann nach unten. Der Preis sind
     rund 300 Byte in einer ein Jahr `immutable` ausgelieferten Datei.

     Kein Gegenstück mehr: die Redaktion trug einmal dieselbe Leiste als
     Vue-Bauteil und damit dieselben Klassen. Sie ist dort in die Seitenleiste
     aufgelöst (`frontend/src/views/admin/AdminLayout.vue`), und dieser Block ist
     seither die einzige Fassung. Was hier steht, gilt nur noch öffentlich. */
  /* Die Höhe steht am Wurzelelement und nicht an der Leiste selbst: die
     Kopfzeile ist ihr Geschwister und braucht denselben Wert, um sich darunter
     zu heften. Nicht im Tokenblock oben — den vergleicht
     `scripts/check-tokens.sh` zeichengleich gegen `design/tokens.css`. */
  .has-adminbar {
    --td-adminbar-h: 2.5rem;
  }

  .td-adminbar {
    position: sticky;
    inset-block-start: 0;
    /* 10 ist die Kopfzeile, 100 der Sprunglink: die Leiste liegt über jener
       und unter diesem. */
    z-index: 11;
    block-size: var(--td-adminbar-h, 2.5rem);
    background: var(--c-dark);
    color: var(--c-on-dark);
    font-size: 0.8125rem;
  }

  .td-adminbar__inner {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    block-size: 100%;
    padding-inline: var(--gutter);
    /* Waagerecht schieben statt umbrechen: ein Umbruch sprengte die feste Höhe
       und holte den Sprung zurück, den sie gerade verhindert. */
    overflow-x: auto;
    white-space: nowrap;
    scrollbar-width: none;
  }

  .td-adminbar__inner::-webkit-scrollbar {
    display: none;
  }

  .td-adminbar__link,
  .td-adminbar__logout {
    color: var(--c-on-dark);
    text-decoration: none;
  }

  .td-adminbar__logout {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    cursor: pointer;
  }

  /* Die Leiste steht auf --c-dark, also die dunkle Stufe der Bedienfarbe. */
  .td-adminbar__link:hover,
  .td-adminbar__link:focus-visible,
  .td-adminbar__logout:hover,
  .td-adminbar__logout:focus-visible {
    color: var(--c-accent-on-dark);
    text-decoration: underline;
  }

  .td-adminbar__link--edit {
    font-weight: 600;
  }

  .td-adminbar__status,
  .td-adminbar__who {
    color: var(--c-on-dark-muted);
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
  }

  /* Der Punkt trägt die Aussage doppelt — Farbe UND Position neben dem Wort.
     Allein über die Farbe wäre „Entwurf" gegen „veröffentlicht" für rund jeden
     zwölften Mann nicht unterscheidbar. */
  .td-adminbar__dot {
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: 50%;
    background: currentColor;
  }

  .td-adminbar__status--published .td-adminbar__dot {
    background: var(--c-success);
  }

  .td-adminbar__status--draft {
    color: var(--c-accent-on-dark);
  }

  .td-adminbar__spacer {
    flex: 1;
  }

  /* Unter 40rem wird der Platz knapp. Zuerst geht die E-Mail-Adresse — wer
     angemeldet ist, weiß in aller Regel, wer er ist; der Bearbeiten-Link und
     das Abmelden sind der Zweck der Leiste. */
  @media (width < 40rem) {
    .td-adminbar__who,
    .td-adminbar__date {
      display: none;
    }
  }

  /* Auf Papier hat ein Bedienelement nichts zu suchen. Betrifft auch den
     PDF-Ausdruck und jede Bildschirmaufnahme über die Druckvorschau. */
  @media print {
    .td-adminbar {
      display: none;
    }
  }

/* Das Kennzeichen kommt aus design/tag.css, geschrieben von
   `bash scripts/check-tokens.sh --write`. Hier nichts von Hand ändern. */
/* ==== KENNZEICHEN START ==== */
/* --- Kennzeichen (K-TAG-01) ---
   Wort und Punkt. Das Wort trägt die Aussage, der Punkt verdoppelt sie — und
   nur der Punkt ist farbig (Regel C in docs/branding/farben.md): die Schrift
   ist immer `--c-ink`, der Punkt muss als Zeichen nur 3:1 erreichen. Das tun
   alle drei Punktfarben auf beiden Gründen; der knappste Wert ist die
   Bedienfarbe im dunklen Satz mit 3,53:1.

   Ein Kennzeichen steht, solange die Seite steht. Nach Regel B ist es damit
   dauerhaft, und dauerhaft heißt: keine weiche Fläche, keine abgewandelte
   Bedienfarbe. Die eigene Fläche in `--c-bg` ist kein Schmuck — auf der
   eingesenkten, geöffneten Tabellenzeile stünde es sonst nicht mehr als
   Gegenstand da.

   Die Ausprägungen setzen nur Custom Properties und keine Nachfahren-Regeln
   (R-15): so kann eine Ansicht ein einzelnes Kennzeichen umfärben, ohne mit
   der Spezifität zu ringen. */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.16rem 0.45rem;
  border: 1px solid var(--tag-edge, var(--c-border));
  border-radius: var(--radius-sm);
  background: var(--tag-fill, var(--c-bg));
  color: var(--tag-ink, var(--c-ink));
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.35;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Der Punkt. Ohne Ausprägung gibt es ihn nicht — K-TAG-01.1 ist eine
   neutrale Angabe, und ein grauer Punkt davor wäre ein Zeichen ohne
   Nachricht. */
.tag::before {
  content: '';
  display: var(--tag-dot, none);
  flex: none;
  inline-size: 0.45rem;
  block-size: 0.45rem;
  border-radius: 50%;
  background: var(--tag-mark);
}

/* K-TAG-01.2 — erledigt: veröffentlicht, aktiv. Erfolg. */
.tag--done {
  --tag-dot: block;
  --tag-mark: var(--c-success);
}

/* K-TAG-01.3 — offen: Entwurf, ungelesen. Die Bedienfarbe, weil der Zustand
   auf eine Handlung wartet; § 2.1 kennt keine fünfte Bedeutung von Farbe. */
.tag--pending {
  --tag-dot: block;
  --tag-mark: var(--c-mark);
}

/* K-TAG-01.4 — gesperrt: inaktiv, verborgen. Gefahr. */
.tag--blocked {
  --tag-dot: block;
  --tag-mark: var(--c-error);
}

/* K-TAG-01.5 — betont: die Standardsprache. Betonung ohne Farbe — eine
   gefüllte Fläche in der Bedienfarbe sähe aus wie ein Knopf. Die Umkehrung
   aus Schrift und Grund hält in beiden Sätzen denselben Kontrast wie die
   Schrift selbst (9,74:1 hell, 13,59:1 dunkel). */
.tag--strong {
  --tag-fill: var(--c-ink);
  --tag-edge: var(--c-ink);
  --tag-ink: var(--c-bg);
}
/* ==== KENNZEICHEN END ==== */

  /* Die Bauteile der Redaktion (§ 4.13) — hier nur, damit der Styleguide sie
     mit echtem CSS zeigt. Keine Vorlage der Website setzt diese Klassen.
     Quelle ist design/redaktion.css, geschrieben von
     `bash scripts/check-tokens.sh --write`. Hier nichts von Hand ändern. */
/* ==== REDAKTION START ==== */
/* --- Knöpfe der Redaktion (K-BTN-06 bis 08) ---
   Gebaut auf `.btn` (K-BTN-01/02) und `.btn--sm` (K-BTN-03, 36 px). Die drei
   setzen nur, was sie von dort unterscheidet. 36 px sind die Höhe der
   Werkzeuge in Zeilen und Spalten — die Ausnahme zu R-10, die R-10 selbst
   nennt. */

/* K-BTN-06 — leise: ein Weg, der da sein muss, aber nichts anstößt. */
.btn--quiet {
  background: transparent;
  color: var(--c-muted);
  box-shadow: none;
}

.btn--quiet:hover:not(:disabled) {
  background: var(--c-control);
  color: var(--c-ink);
}

/* K-BTN-07 — Gefahr: entfernen, löschen. Ruhe getönt (5,72:1), Hover satt
   mit weißer Schrift (6,54:1 umgekehrt) — dunkle Schrift erreichte auf der
   roten Fläche nur 2,7:1. */
.btn--danger {
  background: var(--c-error-soft);
  color: var(--c-error);
  box-shadow: none;
}

.btn--danger:hover:not(:disabled) {
  background: var(--c-error);
  color: var(--c-on-fill);
}

/* K-BTN-08 — Symbol: ein Werkzeug ohne Wort. Trägt immer `aria-label` und
   `title`. Das Zeichen ist ein Strich-SVG (Material Symbols Outlined), nie ein
   Textzeichen wie ↑ oder ✕ — die stehen in jeder Schrift anders. Der Strich
   steht in --c-muted-strong, weil --c-muted auf --c-control nur 4,2:1 hält.
   `.btn--toggle` ist derselbe Knopf als Umschalter: eingeschaltet kehrt er um. */
.btn--icon,
.btn--toggle {
  inline-size: 2.25rem;
  min-block-size: 2.25rem;
  padding: 0;
  gap: 0;
  color: var(--c-muted-strong);
  background: var(--c-control);
  border-radius: 6px;
}

.btn--icon svg,
.btn--toggle svg {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.btn--icon:hover:not(:disabled),
.btn--toggle:hover:not(:disabled) {
  color: var(--c-ink);
  background: var(--c-control-hover);
}

/* Ohne Fläche, wo viele Symbolknöpfe in einer Zeile stehen (Gliederung,
   Faltstreifen): eine Reihe grauer Kacheln sähe aus wie ein Raster. */
.btn--icon.btn--quiet {
  background: transparent;
  color: var(--c-muted);
}

.btn--icon.btn--quiet:hover:not(:disabled) {
  background: var(--c-control);
  color: var(--c-ink);
}

.btn--toggle[aria-pressed='true'] {
  background: var(--c-ink);
  color: var(--c-on-fill);
}

/* --- K-FORM-11 Feld der Redaktion ---
   Dieselben Werte wie das Formularfeld der Website (`.block-form__input`):
   Fläche --c-raised, Kante --c-border-strong (4,54:1), Radius --radius-sm.
   44 px hoch — ein Feld ist kein Werkzeug in einer Zeile, sondern das, was
   man bearbeitet. Die Gestalt hängt an `.field` oder `.input`, nicht am Ort:
   Blatt und Werkzeugspalte zeigen dasselbe Feld.

   `:where()`, damit die Regel keine Spezifität mitbringt — ein Bauteil, das
   ein Feld wirklich anders braucht (der Titel als Überschrift), setzt sich mit
   einer einzigen Klasse durch. */
.field {
  margin-block-end: 1.25rem;
}

/* `:not(.check)`: ein Ankreuzfeld mit Wort daneben (K-FORM-05) steht oft
   selbst als Beschriftung in einem `.field` und behält seine Gestalt. */
.field > label:not(.check),
.field-label {
  display: block;
  margin-block-end: 0.4rem;
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.3;
  color: var(--c-ink);
}

.input,
.field :where(input:not([type='checkbox'], [type='radio'], [type='range'], [type='color'], [type='file'], [type='hidden']), textarea, select) {
  inline-size: 100%;
  min-block-size: 2.75rem;
  padding: 0.55rem 0.75rem;
  font: inherit;
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--c-ink);
  background: var(--c-raised);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  transition:
    border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}

.input:hover,
.field :where(input, textarea, select):hover {
  border-color: var(--c-muted);
}

/* Der Ring aus R-09, dazu die Kante in der Bedienfarbe. `:focus` und nicht
   `:focus-visible`: in ein Feld schreibt man auch nach einem Klick, und wer
   schreibt, soll sehen, wo. */
.input:focus,
.field :where(input, textarea, select):focus {
  outline: none;
  border-color: var(--c-accent);
  box-shadow:
    0 0 0 2px var(--c-bg),
    0 0 0 4px var(--c-accent);
}

textarea.input,
.field textarea {
  min-block-size: 6rem;
  line-height: 1.55;
  resize: vertical;
}

.input:disabled,
.field :where(input, textarea, select):disabled {
  background: var(--c-disabled);
  color: var(--c-muted-strong);
  cursor: not-allowed;
}

.field-hint {
  margin: 0.4rem 0 0;
  font-size: var(--fs-meta);
  line-height: 1.45;
  color: var(--c-muted);
}

/* K-FORM-05 in der Redaktion: Ankreuzfeld mit Wort daneben. Dieselbe Größe
   und Farbe wie im Formular der Website. Stand vorher viermal als `.switch`
   mit drei Größen und einmal als `.check`. */
.check {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-small);
  color: var(--c-ink);
  cursor: pointer;
}

.check input,
.field input:where([type='checkbox'], [type='radio']) {
  flex: none;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  margin: 0;
  accent-color: var(--c-accent);
}

/* --- K-FORM-12 Segmentschalter ---
   Eine aus wenigen Möglichkeiten, alle sichtbar: Breite der Vorschau, Art eines
   Kontos. Der Schalter ist ein `role="group"` aus Knöpfen mit `aria-pressed`
   (oder Radio-Beschriftungen mit `.is-active`). Gewählt hebt sich die Fläche
   heraus — ein Zustand, keine Farbe (Regel B). */
.seg {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--c-sunken);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
}

.seg > button,
.seg > label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-block-size: 2.25rem;
  padding: 0 0.75rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  font: inherit;
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--c-muted);
  cursor: pointer;
  white-space: nowrap;
}

.seg > :hover {
  color: var(--c-ink);
}

.seg > [aria-pressed='true'],
.seg > .is-active {
  background: var(--c-raised);
  color: var(--c-ink);
  box-shadow: var(--shadow-sm);
}

/* Der gewählte Teil trägt einen Schatten und verlöre damit den Fokusring, der
   ebenfalls ein Schatten ist. */
.seg > :focus-visible {
  box-shadow:
    0 0 0 2px var(--c-bg),
    0 0 0 4px var(--c-accent);
}

.seg > :disabled {
  cursor: not-allowed;
}

.seg > :disabled[aria-pressed='true'] {
  background: var(--c-disabled);
  color: var(--c-muted-strong);
  box-shadow: none;
}

/* --- K-NAV-13 Reiter ---
   Ansichten desselben Gegenstands: Sprachfassungen, Baustein/Seite/SEO, die
   Teile eines Kontos. Neutrale Schrift, die Bedienfarbe als Linie darunter
   (R-02, R-03) — wie der aktive Menüpunkt der Website (K-NAV-02). Die Linie
   steht im Ruhezustand durchsichtig da, damit der aktive Reiter nicht rückt. */
.tabs {
  display: flex;
  gap: 0.25rem;
  border-block-end: 1px solid var(--c-border);
}

.tabs > * {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-block-size: 2.75rem;
  margin-block-end: -1px;
  padding: 0 0.75rem;
  border: 0;
  border-block-end: 2px solid transparent;
  background: none;
  font: inherit;
  font-size: var(--fs-small);
  color: var(--c-muted);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.tabs > :hover {
  color: var(--c-ink);
}

.tabs > [aria-selected='true'],
.tabs > [aria-current],
.tabs > .is-active {
  color: var(--c-ink);
  font-weight: 600;
  border-block-end-color: var(--c-accent);
}

/* Gleich breit, wo die Reiter eine Spalte teilen. */
.tabs--fill > * {
  flex: 1;
}

/* --- K-DLG-01 Dialog ---
   Rückfrage, Auswahl, kurze Eingabe. Deckend und mit `--shadow-md` (R-04),
   davor der Schleier `--c-scrim`. Eine Breite je Aufgabe über `--dialog-w`,
   sonst nichts Eigenes. Fuß rechtsbündig, die Handlung zuletzt. */
.dialog-scrim {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: var(--c-scrim);
}

.dialog {
  inline-size: min(var(--dialog-w, 32rem), 100%);
  max-block-size: calc(100dvh - 2 * var(--space-4));
  overflow: auto;
  padding: var(--space-5);
  background: var(--c-raised);
  color: var(--c-ink);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.dialog__title {
  margin: 0 0 var(--space-2);
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.35;
}

.dialog__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-block-start: var(--space-5);
}

/* --- K-DLG-02 Aktionsmenü ---
   Die Handlungen an einem Gegenstand, beschriftet, hinter einem Knopf
   „Weitere Aktionen" (K-BTN-08). Fläche, Linie, Radius und Schatten wie der
   Dialog (R-04), aber ohne Schleier: es ist nicht modal. Einträge 36 px
   (R-10, Werkzeug), Zeichen in `--c-muted`, Kürzel rechts. Eine Gefahr steht
   zuletzt, unter einer Linie, und färbt Schrift und Zeichen in `--c-error`.
   Wo es steht, entscheidet der Aufrufer — als `popover` liegt es in der
   obersten Ebene und wird von keinem rollenden Behälter abgeschnitten. */
.action-menu {
  min-inline-size: 13.5rem;
  margin: 0;
  padding: var(--space-1);
  list-style: none;
  background: var(--c-raised);
  color: var(--c-ink);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.action-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  inline-size: 100%;
  min-block-size: 2.25rem;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  font: inherit;
  font-size: var(--fs-small);
  color: inherit;
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
}

.action-menu__item > svg {
  flex: none;
  color: var(--c-muted);
}

.action-menu__item:hover {
  background: var(--c-row-hover);
}

/* Innen, wie in jeder Liste, die ihren Rand selbst zieht. */
.action-menu__item:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--c-accent);
}

.action-menu__item.is-danger,
.action-menu__item.is-danger > svg {
  color: var(--c-error);
}

.action-menu__key {
  margin-inline-start: auto;
  padding-inline-start: var(--space-4);
  font: inherit;
  font-size: var(--fs-tag);
  color: var(--c-muted);
}

.action-menu__sep {
  margin: var(--space-1) var(--space-2);
  border-block-start: 1px solid var(--c-border);
}

/* --- K-LIST-07 Kennzahlenraster ---
   Volumen, Platz und vier Lighthouse-Noten in festen Unterspalten, damit die
   Werte aller Zeilen untereinander stehen. In der Suche seit dem 06.10.2026
   eine dritte Unterspalte: was für Google zu tun ist (`seo_pruefstand`), als
   K-TAG-01.3 mit Zahl, .2 mit Haken, .4, wenn etwas Google abhält. Der Kopf kommt aus demselben
   Bauteil (`KennzahlRaster.vue`, `kopf`). Die Spaltenbreiten stehen einmal hier und gelten für Kopf und
   Zeilen. 2.7rem trägt ein Kennzeichen „100“ samt Punkt im engen Zuschnitt
   unten; der schmale dritte Streifen trennt Suche und Lighthouse. So knapp,
   weil die Seitenliste bei 1440 px sonst in Karten kippt. */
.kz {
  --kz-spalten: 3.4rem 3rem 2.7rem 0.5rem repeat(4, 2.7rem) minmax(1rem, auto);
  display: grid;
  grid-template-columns: var(--kz-spalten);
  align-items: center;
  column-gap: 0.2rem;
  white-space: nowrap;
  text-align: start;
}

.kz--ohne-seo {
  --kz-spalten: repeat(4, 2.7rem) minmax(1rem, auto);
}

/* Feste Zeilen: Gruppe 1, Unterköpfe 2, Werte 3 (in der Karte) bzw. 1 (in
   der Tabelle). Ohne sie setzte der Browser den ersten Unterkopf in die
   Lücke zwischen „Suche“ und „Lighthouse“ in Zeile 1. */
.kz__kopf {
  grid-row: 2;
}

.kz__z {
  grid-row: var(--kz-zeile, 1);
}

.kz--compact {
  --kz-zeile: 3;
}

/* Die Werte rechtsbündig: so endet jede Unterspalte auf derselben Linie. */
.kz__wert,
.kz__kopf {
  justify-self: end;
}

.kz__kopf {
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--c-muted);
}

/* Die Gruppe über ihren Unterspalten, mit einer Linie über deren volle Breite. */
.kz__gruppe {
  grid-row: 1;
  padding-block-end: 0.2rem;
  margin-block-end: 0.15rem;
  border-block-end: 1px solid var(--c-border-strong);
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--c-ink);
}

.kz__gruppe--suche {
  grid-column: 1 / span 3;
}

.kz__gruppe--lh {
  grid-column: 5 / span 4;
}

.kz--ohne-seo .kz__gruppe--lh {
  grid-column: 1 / span 4;
}

/* Gleich breite Kennzeichen, Punkt links, Zahl rechts — im engen Zuschnitt:
   weniger Polster und Abstand zum Punkt als K-TAG-01 sonst, Rahmen, Punkt
   und Schrift unverändert. */
.kz .tag {
  min-inline-size: 2.6rem;
  padding-inline: 0.3rem;
  gap: 0.25rem;
  justify-content: space-between;
  font-variant-numeric: tabular-nums;
}

.kz__volumen {
  font-variant-numeric: tabular-nums;
}

/* Die vier Noten sind ein Knopf und behalten doch das Raster (`subgrid`). */
.kz__noten {
  grid-column: span 4;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.kz__breit {
  grid-column: span 4;
  justify-self: start;
}

.kz__zeichen {
  display: inline-flex;
  gap: 0.15rem;
  justify-self: start;
}

.kz__zeichen svg {
  display: block;
  inline-size: 1rem;
  block-size: 1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.kz__zeichen svg .voll {
  fill: currentColor;
  stroke: none;
}

.kz__zeichen--hinweis {
  color: var(--c-mark);
}

.kz__zeichen--fehler {
  color: var(--c-error);
}

.kz__zeichen--still {
  color: var(--c-muted);
}

/* In der Karte steht der Kopf über den Werten; er wird dort nicht großgeschrieben. */
.kz--compact {
  row-gap: 0.2rem;
}

/* --- K-LIST-08 Prüfpunkt ---
   Eine Prüfung der Redaktion als ganzer Satz (R-21), daneben ihr Gewicht als
   Kennzeichen K-TAG-01: gut (.2), zu tun (.3), kann helfen und so lassen
   (.1, ohne Punkt). Die ganze Zeile ist ein Knopf zu dem Feld, in dem man den
   Punkt behebt — Hover `--c-row-hover`, Fokus über den globalen Ring. Der
   Satz bricht um, das Kennzeichen steht oben rechts. Mehrere stehen in einer
   `.pruefliste`, getrennt durch Haarlinien. Erster Einsatz: Reiter „SEO". */
.pruefliste {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-meta);
}

.pruefliste > li + li {
  border-block-start: 1px solid var(--c-border);
}

.pruefpunkt {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.5rem;
  align-items: start;
  inline-size: 100%;
  padding: 0.35rem;
  font: inherit;
  line-height: 1.45;
  color: var(--c-ink);
  text-align: start;
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.pruefpunkt:hover {
  background: var(--c-row-hover);
}

.pruefpunkt__satz {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* K-LIST-08.1 — am Feld. Derselbe Satz mit Gewicht, direkt unter dem Feld,
   das er prüft. Kein Knopf: das Feld steht schon da, ein Sprung wäre einer
   an dieselbe Stelle. Ohne Polster links, damit der Satz bündig unter der
   Beschriftung steht. */
.pruefpunkt--feld {
  padding: 0.3rem 0 0;
  font-size: var(--fs-meta);
  cursor: default;
}

.pruefpunkt--feld:hover {
  background: none;
}

/* --- K-TXT-08 Meldung ---
   Rückmeldung der Anwendung. Neutrale Schrift; Zeichen und Kante tragen die
   Bedeutung (R-02). Drei Ausprägungen: .1 Hinweis (`role="status"`), .2 Fehler
   (`role="alert"`), .3 Erfolg (`role="status"`). Das Zeichen ist absolut
   gesetzt und nicht Teil eines Rasters — eine Meldung darf `<b>` und Links
   enthalten, und jedes davon würde sonst eine eigene Spalte. */
.msg {
  --msg-mark: var(--c-mark);
  position: relative;
  margin: 0 0 var(--space-4);
  padding: 0.7rem 0.9rem 0.7rem 2.5rem;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-bg);
  box-shadow: inset 3px 0 0 var(--msg-mark);
  color: var(--c-ink);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.msg::before {
  content: '';
  position: absolute;
  inset-inline-start: 0.85rem;
  inset-block-start: 0.85rem;
  inline-size: 1.125rem;
  block-size: 1.125rem;
  background: var(--msg-mark);
  -webkit-mask: var(--msg-icon, var(--icon-info)) center / contain no-repeat;
  mask: var(--msg-icon, var(--icon-info)) center / contain no-repeat;
}

/* K-TXT-08.2 — Fehler. Die Fläche ist die Ruhefläche des Gefahr-Knopfs. */
.msg--error {
  --msg-mark: var(--c-error);
  --msg-icon: var(--icon-error);
  background: var(--c-error-soft);
  border-color: transparent;
}

/* K-TXT-08.3 — Erfolg. */
.msg--ok {
  --msg-mark: var(--c-success);
  --msg-icon: var(--icon-done);
}

/* Material Symbols Outlined (Apache-2.0): info, error, check_circle —
   eingebettet, nicht geladen (R-13). */
.msg {
  --icon-info: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Z'/%3E%3C/svg%3E");
  --icon-error: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M480-280q17 0 28.5-11.5T520-320q0-17-11.5-28.5T480-360q-17 0-28.5 11.5T440-320q0 17 11.5 28.5T480-280Zm-40-160h80v-240h-80v240Zm40 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Z'/%3E%3C/svg%3E");
  --icon-done: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='m424-296 282-282-56-56-226 226-114-114-56 56 170 170Zm56 216q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Z'/%3E%3C/svg%3E");
}

/* --- K-TXT-09 Leer-, Lade- und Fehlerzustand ---
   Eine Liste oder Spalte ohne Inhalt sagt, warum: nichts da, Filter, fehlendes
   Recht, Fehler. Der Titel nennt die Ursache, der Satz darunter den Weg.
   Laden trägt `role="status"` und ist nie ein endloser Kreisel — schlägt es
   fehl, wird daraus eine Meldung K-TXT-08.2. */
.empty {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--c-muted);
}

.empty__title {
  margin: 0 0 var(--space-1);
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--c-ink);
}
/* ==== REDAKTION END ==== */
}

@layer blocks {
  /* R-22 Ausgeblendeter Baustein — nur in Editor und Vorschau zu sehen; die
     öffentliche Seite hat ihn nicht. Gestrichelter Rahmen in der Fehlerfarbe
     des Kennzeichens K-TAG-01.4, das Kennzeichen oben links. Beides ohne
     Einfluss auf die Maße: der Rahmen ist ein `outline` nach innen, das
     Kennzeichen liegt absolut. So sieht die Vorschau aus wie die Seite. */
  [data-ausgeblendet] {
    position: relative;
    outline: 2px dashed var(--c-error);
    outline-offset: -2px;
  }

  .block-ausgeblendet {
    position: absolute;
    z-index: 3;
    inset-block-start: var(--space-2);
    inset-inline-start: var(--space-2);
    /* In einer schmalen Rasterzelle umbrechen statt herausragen. */
    max-inline-size: calc(100% - 2 * var(--space-2));
    white-space: normal;
    pointer-events: none;
  }

  /* --- Textabschnitt --- */

  .block-text__headline {
    font-size: var(--fs-h2);
    margin-block-end: var(--space-5);
  }

  .block-text__body > p + p {
    margin-block-start: var(--space-4);
  }

  /* Der Umwandler aus WordPress erzeugt je Textabschnitt der Bestandsseite
     einen eigenen Textblock; in einem Beitrag stehen davon bis zu sieben. Drei
     hintereinander sind Fließtext und keine drei Abschnitte — mit `--section-y`
     dazwischen (bei 1280px sind das 115px) zerfällt ein Artikel in weit
     auseinanderliegende Inseln, und die Seite wird fast doppelt so hoch wie die
     Vorlage. Zwischen zwei unmittelbar aufeinanderfolgenden Textblöcken gilt
     deshalb der Absatzabstand; die Null oben setzt die Regel im `layout`-Layer.

     Trägt der zweite Block eine Überschrift, ist der Abschnittswechsel echt und
     der Abstand kommt zurück. Beide Fälle brauchen `:has()`: ohne den Blick auf
     den Nachbarn lässt sich Fließtext nicht von einem neuen Abschnitt
     unterscheiden. */
  /* Die Aufzählung zählt dabei als Textblock: sie ist Fließtext in anderer Form,
     und eine Liste, die einen Absatz fortsetzt, darf nicht mit dem vollen
     Abschnittsabstand darunter stehen. */
  :is(.block-text, .block-list):not([data-tone]):has(
      + :is(.block-text, .block-list):not([data-tone])
    ) {
    padding-block-end: var(--space-4);
  }

  :is(.block-text, .block-list):not([data-tone])
    + :is(.block-text, .block-list):not([data-tone]):has(
      :is(.block-text__headline, .block-list__headline)
    ) {
    padding-block-start: var(--space-9);
  }

  .block-text__body {
    max-width: var(--width-prose);
    color: var(--c-muted);
  }

  [data-tone='contrast'] .block-text__body {
    color: var(--c-on-contrast-muted);
  }

  /* Schaltfläche unter dem Text. Derselbe Abstand wie zwischen zwei Absätzen
     und nicht mehr: sie gehört zum Abschnitt darüber, nicht zum nächsten. */
  .block-text__cta {
    margin-block-start: var(--space-5);
  }

  /* --- Datei zum Herunterladen ---
     Der Verweis ist eine Fläche und keine Textzeile: er ist das einzige
     Bedienelement des Blocks, und ein Ziel, das eine Datei öffnet, sollte sich
     von einem Verweis im Fließtext unterscheiden. */
  .block-file__link {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-4) var(--space-5);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius-md);
    background: var(--c-raised);
    color: var(--c-ink);
    text-decoration: none;
    max-width: var(--width-prose);
  }

  .block-file__link:hover {
    border-color: var(--c-accent);
    background: var(--c-accent-soft);
  }

  .block-file__name {
    font-weight: 600;
    /* Dateinamen aus dem Bestand sind lang und ohne Leerzeichen
       (`01_Bedienungsanleitung-POIApp-RTK-Empfaenger_V003_2026.04.28-1.pdf`).
       Ohne Umbruch im Wort schiebt einer davon die ganze Seite seitwärts. */
    overflow-wrap: anywhere;
  }

  .block-file__meta {
    font-size: var(--fs-small);
    color: var(--c-muted);
    white-space: nowrap;
  }

  .block-file__headline {
    font-size: var(--fs-h3);
    margin-block-end: var(--space-4);
  }

  /* --- Aufzählung ---
     Lesebreite und Farbe wie im Textabschnitt: eine Aufzählung ist Fließtext in
     anderer Form und soll nicht wie ein eigenes Bauteil wirken. Die Lesebreite
     sitzt deshalb an der Liste und nicht am `.shell` — beides am selben Element
     würde die schmale Box im Ansichtsfenster zentrieren, während die Blöcke
     darunter am linken Rand beginnen. Derselbe Grund wie beim Beitrag.

     Der Einzug steht in `em`, damit die Marke bei jeder Schriftgröße denselben
     Abstand hält. Zwischen zwei Punkten ist der Abstand kleiner als zwischen
     zwei Absätzen: Punkte einer Aufzählung gehören enger zusammen. Ein Punkt
     darf mehrere Zeilen tragen — die Bestandsseite setzt Unterpunkte mit `<br>`
     innerhalb eines Punktes. */

  .block-list__headline {
    font-size: var(--fs-h2);
    margin-block-end: var(--space-5);
  }

  .block-list__items {
    max-width: var(--width-prose);
    padding-inline-start: 1.35em;
    color: var(--c-muted);
  }

  .block-list__items > li + li {
    margin-block-start: var(--space-3);
  }

  /* Ein Aufzählungszeichen ist kein Text: es muss 3:1 erreichen, nicht
     4,5:1. Genau dafür ist `--c-mark` da — auf jedem hellen Grund die
     Bedienfarbe, im Kontrastband und über einem Bild die dortige Stufe. Die
     Zahl 4,35:1, die hier stand, galt dem alten Grund #fafbfc; auf Weiß sind
     es 4,51:1. */
  .block-list__items > li::marker {
    color: var(--c-mark);
  }

  [data-tone='contrast'] .block-list__items {
    color: var(--c-on-contrast-muted);
  }

  /* --- Merkmalliste ---
     Bestandsblock. Die Trennlinien entstehen aus den Rahmen der Felder selbst,
     die sich über einen negativen Außenabstand gegenseitig überdecken — die
     äußeren fallen aus dem `overflow: hidden` des Rahmens.

     Vorher lag eine Rasterlücke von 1px über einer eingefärbten Fläche. Das ist
     kürzer, färbt aber auch die **leeren** Zellen: fünf Einträge in einem
     vierspaltigen Raster ergaben eine Reihe mit drei grauen Löchern. Auf
     `/unsere-mission/veroeffentlichungen/` war das der auffälligste Fehler der
     ganzen Seite. */

  .block-features__list {
    list-style: none;
    padding: 0;
    display: grid;
    gap: 0;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    overflow: hidden;
  }

  .block-features__list li {
    padding: var(--space-6);
    border-inline-start: 1px solid var(--c-border);
    border-block-start: 1px solid var(--c-border);
    margin-inline-start: -1px;
    margin-block-start: -1px;
  }

  .block-features__list :is(h2, h3) {
    font-size: var(--fs-h3);
    margin-block-end: var(--space-3);
  }

  .block-features__list p {
    color: var(--c-muted);
    font-size: var(--fs-small);
    line-height: 1.6;
  }

  /* --- Bild --- */

  /* Hier bewusst KEIN `margin: 0` auf die Figur: `.shell` zentriert über
     `margin-inline: auto`, und diese Schicht liegt hinter `layout` — eine
     Nullsetzung würde die Zentrierung aufheben. Das `figure`-Reset in `base`
     stört nicht, weil `base` vor `layout` liegt. */
  /* `width: auto` statt `100%`: ein Rasterbild darf nie über seine eigene
     Größe hinaus vergrößert werden. Sonst füllt eine 300 Pixel breite Plakette
     den ganzen Container und wird dabei unscharf — auf der übernommenen
     Startseite hat genau das die DJI-Auszeichnung zum größten Element der Seite
     gemacht. Die Attribute `width`/`height` in der Vorlage liefern die
     natürliche Breite, `max-width` deckelt nach oben. */
  .block-image img {
    display: block;
    width: auto;
    /* `--image-max` setzt die Vorlage aus der Anzeigebreite des Inhalts; ohne
       Angabe gilt die Containerbreite. `min()` deckelt in jedem Fall. */
    max-width: min(100%, var(--image-max, 100%));
    margin-inline: auto;
    border-radius: var(--radius-md);
  }

  .block-image figcaption {
    margin-block-start: var(--space-3);
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  /* --- Handlungsaufruf ---
     Eine dunkle Karte statt eines weiteren weißen Abschnitts: der Aufruf soll
     sich vom Fließtext darüber absetzen. */

  .block-cta__panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
    padding: clamp(2rem, 5vw, 3.5rem);
    border-radius: var(--radius-lg);
  }

  /* Trägt der Block keinen Text, ist die Schaltfläche der ganze Inhalt: dann
     gehört sie in die Mitte und das Feld darf flacher sein. Links ausgerichtet
     in voller Höhe sähe es aus, als fehlte etwas daneben. */
  .block-cta__panel:not(:has(> div)) {
    justify-content: center;
    padding-block: clamp(1.5rem, 3vw, 2.25rem);
  }

  .block-cta__headline {
    font-size: clamp(1.375rem, 3vw, 2rem);
    max-width: 30ch;
  }

  /* --- Bild und Text ------------------------------------------------------
     Unter 60rem einspaltig mit dem Bild oben — die Leserichtung bleibt damit
     eindeutig, unabhängig davon, welche Seite die Redaktion gewählt hat. */

  .block-media-text__inner {
    display: grid;
    gap: var(--space-7);
    align-items: center;
  }

  .block-media-text__figure img {
    display: block;
    width: auto;
    max-width: 100%;
    /* Höhengrenze, keine Breitengrenze. Hochformatige Aufnahmen — bei den
       Produktbildern Smartphones — werden bei halber Zeilenbreite über 1000 px
       hoch, und daneben stehen drei Zeilen Text: der Text schwebt dann in einer
       leeren Fläche. Querformate liegen mit rund 320 px darunter und bleiben
       unberührt, die Grenze greift also nur dort, wo sie gebraucht wird. */
    max-block-size: 34rem;
    margin-inline: auto;
    border-radius: var(--radius-md);
  }

  .block-media-text__headline {
    font-size: var(--fs-h2);
    margin-block-end: var(--space-5);
  }

  .block-media-text__text {
    color: var(--c-muted);
  }

  .block-media-text__body > p + p {
    margin-block-start: var(--space-4);
  }

  .block-media-text__body > p:has(.arrow-link) {
    margin-block-start: var(--space-6);
  }

  @media (min-width: 60rem) {
    .block-media-text__inner {
      grid-template-columns: 1fr 1fr;
      gap: clamp(3rem, 6vw, 6rem);
    }

    .block-media-text[data-media='right'] .block-media-text__figure {
      order: 2;
    }
  }

  /* --- Kartenraster -------------------------------------------------------
     `--cards` ist eine Obergrenze für breite Schirme. Darunter entscheidet
     `auto-fit`, damit die Redaktion nicht je Bildschirmbreite eine eigene
     Spaltenzahl pflegen muss. */

  .block-cards__list {
    list-style: none;
    padding: 0;
    display: grid;
    gap: var(--space-8) var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  }

  @media (min-width: 60rem) {
    .block-cards__list {
      grid-template-columns: repeat(var(--cards, 3), minmax(0, 1fr));
    }
  }

  /* Bewusst ohne Rahmen und Schatten: Karten in Kästen in Kästen sind das
     sicherste Kennzeichen einer Vorlage von der Stange. Struktur entsteht hier
     aus Bild, Eyebrow und Abstand. */
  .card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
  }

  .card__image {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: var(--radius-md);
    margin-block-end: var(--space-2);
  }

  /* Bei einem quadratischen oder hochkanten Bild nimmt der Beschnitt auf 4:3
     mittig Höhe weg und schneidet damit genau das an, was auf einem Porträt
     zählt: Andreas Kern fehlten auf `/unser-team/` die Haare.

     25 % und nicht `top` — nachgemessen an vier Varianten. Bei `top` zeigt ein
     hochkantes Porträt nur noch die Stirn: Tanja Kerns Bild (1363×2048) war
     unterhalb der Augen abgeschnitten. 25 % rettet den Kopf des quadratischen
     Bildes, ohne das hochkante zu köpfen. */
  .card__image[data-tall] {
    object-position: center 25%;
  }

  /* Abzeichen und Plaketten statt Fotos — die Vorlage setzt das Attribut, wenn
     die Datei schmaler ist als die kleinste erzeugte Variante **und** deutlich
     breiter als hoch. Kein Beschnitt und keine Hochskalierung: `aspect-ratio`
     und `cover` gelten dem gleichmäßigen Bildband einer Kartenreihe, hier
     richten sie Schaden an. */
  .card__image[data-intrinsic] {
    width: auto;
    max-width: min(100%, var(--card-image-max));
    aspect-ratio: auto;
    object-fit: contain;
  }

  /* K-CARD-01.1 Karte mit Video. Der Player steht an der Stelle des Bildes
     und hält in einer Kartenreihe dasselbe Format für alle — auch ein Short
     (Hochformat) liegt hier in 16:9, sonst stünde eine Karte doppelt so hoch
     wie ihre Nachbarn. Der Player zeigt das Hochformat darin mit Rand. */
  .card--video .video-player {
    --video-format: 16 / 9;
    max-inline-size: none;
    margin-block-end: var(--space-2);
  }

  .card__eyebrow {
    margin-block-end: 0;
  }

  .card__title {
    font-size: var(--fs-h3);
  }

  /* Fließtextgröße, nicht `--fs-small`: der Kartentext ist der größte Teil
     des Textes auf der Startseite. Mit 14 px stand er auf dem Handy 4 px unter
     der Bestandsseite (18 px), gemessen am 05.10.2026 bei 390 px. */
  .card__text {
    color: var(--c-muted);
    font-size: var(--fs-body);
    line-height: 1.6;
  }

  /* Auf dem Kontrastband kehrt sich die Richtung um. Ohne diese Regel stand
     `--c-muted` (#5E5E5E) auf `--c-contrast` (#222222) — **2,45:1**, also
     weit unter den 4,5:1, die 14px normaler Schrift brauchen. Gemessen am
     24.09.2026 auf der Startseite, wo drei Karten im Band liegen.

     Dieselbe Umkehr wie bei `.lead` und `.block-stats__label`. Sie fehlte
     ausgerechnet hier, weil `.card__text` als einziger Kartenteil eine eigene
     Farbe setzt — Eyebrow, Titel und Verweis erben und kippten deshalb mit. */
  [data-tone='contrast'] .card__text {
    color: var(--c-on-contrast-muted);
  }

  /* Zwei Absätze in einer Karte brauchen eine Grenze, aber keine so große wie
     zwischen zwei Karten. */
  .card__text + .card__text {
    margin-block-start: var(--space-3);
  }

  /* Der Textkörper der Karte. Er ist eine Säule wie die Karte selbst, damit die
     Regel für den Verweis darunter weiter gilt — und er ist die eine Hülle, die
     der Streifen braucht, um Bild und Text nebeneinander zu legen. */
  .card__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    flex: 1;
    min-inline-size: 0;
  }

  /* Schiebt die Links aller Karten auf eine gemeinsame Linie, auch wenn die
     Texte unterschiedlich lang sind. */
  .card__link {
    margin-block-start: auto;
    padding-block-start: var(--space-2);
  }

  /* --- Kartenstreifen (Karussell) ---
     `grid_style: slider`. Derselbe scrollende Bereich mit Rastpunkten wie der
     Bilderstreifen, ohne Skript — und der Ort, an dem das Karussell der
     Startseite wieder eines ist. Die Bildlaufleiste bleibt sichtbar: sie ist
     der Hinweis darauf, dass es weitergeht. */
  .block-cards__list[data-layout='slider'] {
    display: flex;
    gap: var(--space-6);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    padding-block-end: var(--space-2);
  }

  .block-cards__list[data-layout='slider']:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 4px;
  }

  .block-cards__list[data-layout='slider'] > .card {
    flex: 0 0 calc((100% - (var(--cards, 1) - 1) * var(--space-6)) / var(--cards, 1));
    scroll-snap-align: center;
  }

  /* Eine Karte je Ansicht liegt quer: Bild links, Text rechts — die Form, die
     die Folie im Bestand hatte. Erst ab 48rem; darunter bleibt die Karte
     gestapelt, weil ein Bild neben Text auf dem Telefon beides zerdrückt.
     Der Text sitzt mittig zur Bildhöhe, das Bild behält sein 4:3. */
  @media (min-width: 48rem) {
    .block-cards__list[data-layout='slider'][data-single] > .card {
      display: grid;
      grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
      column-gap: var(--space-8);
      align-items: center;
    }

    .block-cards__list[data-layout='slider'][data-single] > .card > .card__image {
      margin-block-end: 0;
    }

    .block-cards__list[data-layout='slider'][data-single] > .card > .card__body {
      flex: none;
    }

    /* Im Streifen gibt es keine Nachbarkarten, an denen der Verweis eine
       gemeinsame Linie fände — er folgt dem Text. */
    .block-cards__list[data-layout='slider'][data-single] .card__link {
      margin-block-start: 0;
    }
  }

  /* --- Partner und Auszeichnungen ----------------------------------------
     Die Logos bleiben farbig. Ein Graustich würde das Band beruhigen, nimmt
     Auszeichnungen aber genau die Wiedererkennbarkeit, für die sie hier
     stehen. */

  .block-logos__head {
    max-width: 62ch;
    margin-inline: auto;
    margin-block-end: var(--space-8);
    text-align: center;
  }

  .block-logos__headline {
    font-size: var(--fs-h2);
  }

  .block-logos__intro {
    margin-block-start: var(--space-4);
    color: var(--c-muted);
  }

  .block-logos__list {
    list-style: none;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: clamp(2rem, 5vw, 4.5rem);
  }

  .block-logos__list img {
    display: block;
    width: auto;
    max-width: 10rem;
    max-height: 3.75rem;
  }

  /* --- Referenzstimmen --- */

  .block-quotes__list {
    list-style: none;
    padding: 0;
    display: grid;
    gap: var(--space-9) var(--space-7);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  }

  .quote {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
  }

  .quote__org {
    margin-block-end: 0;
  }

  .quote__title {
    font-size: var(--fs-h3);
  }

  /* Das Anführungszeichen ist Zierde und darf deshalb kein Zeichen im Text
     sein — als Pseudo-Element landet es nicht im Vorlesefluss.

     Die Höhe des Zeichens (Schriftgröße × line-height) muss unter dem oberen
     Innenabstand bleiben, sonst überlagert es den ersten Buchstaben des Zitats:
     2.5rem × 0.75 = 1.875rem gegen 2.5rem Abstand. */
  .quote__body {
    position: relative;
    padding-block-start: var(--space-7);
    color: var(--c-muted);
  }

  .quote__body::before {
    content: '\201E';
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    font-size: 2.5rem;
    line-height: 0.75;
    color: var(--c-accent);
    opacity: 0.45;
  }

  .quote__body p {
    font-size: var(--fs-small);
    line-height: 1.65;
  }

  .quote__author {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-block-start: var(--space-2);
  }

  .quote__avatar {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
  }

  .quote__author cite {
    font-style: normal;
    font-weight: 600;
    font-size: var(--fs-small);
    color: var(--c-ink);
  }

  /* --- Video (K-MEDIA-03) -------------------------------------------------
     Standbild mit Abspielmarke. Bei YouTube ist es der Platzhalter des Players
     (K-MEDIA-03.2): `site.js` setzt den Player erst nach Einwilligung ein
     (R-13). Bei anderen Anbietern verweist das Standbild auf das Video. Eine
     eigene Datei aus der Mediathek spielt sofort (K-MEDIA-03.4/.5). */

  .block-video__link {
    position: relative;
    display: block;
    border-radius: var(--radius-md);
    overflow: hidden;
    text-decoration: none;
  }

  .block-video__link img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
  }

  .block-video__link::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgb(18 32 47 / 0.65), transparent 55%);
  }

  .block-video__play {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    translate: -50% -50%;
    z-index: 1;
    width: clamp(3.5rem, 7vw, 5rem);
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--c-accent);
    display: grid;
    place-items: center;
    transition: scale var(--dur) var(--ease);
  }

  /* Dreieck aus Rahmen statt aus einer Datei — ein Icon-Request für ein
     Dreieck wäre nicht zu rechtfertigen. */
  .block-video__play::before {
    content: '';
    width: 0;
    height: 0;
    border-inline-start: 1.1rem solid var(--c-on-accent);
    border-block: 0.7rem solid transparent;
    margin-inline-start: 0.35rem;
  }

  .block-video__link:hover .block-video__play,
  .block-video__link:focus-visible .block-video__play {
    scale: 1.08;
  }

  .block-video__label {
    position: absolute;
    z-index: 1;
    inset-inline: var(--space-5);
    inset-block-end: var(--space-5);
    color: #fff;
    font-weight: 600;
    font-size: var(--fs-lead);
    text-wrap: balance;
  }

  /* Ein Video ohne Standbild ist ein Verweis. Der Grund steht in
     `blocks/video.html`: 76 Bausteine des Bestands haben eine Adresse und kein
     Bild und zeichneten deshalb gar nichts. Die Flächenform wäre hier falsch —
     ohne Bild gibt es nichts zu überdecken, also die Form des Pfeilverweises. */
  .block-video__link--plain {
    display: inline;
    border-radius: 0;
    overflow: visible;
  }

  /* `::after` trägt in der Flächenform den Farbverlauf über dem Bild; hier ist
     es der Pfeil. Beides am selben Element, weil die Form dieselbe bleibt.

     Derselbe Doppelpfeil, dieselbe Weite und dieselbe Farbquelle wie bei
     `.arrow-link`: es ist dieselbe Geste, und zwei verschiedene Pfeile dafür
     wären ein Versehen, das man erst auf der Seite sieht. */
  .block-video__link--plain::after {
    content: '';
    position: static;
    inset: auto;
    display: inline-block;
    vertical-align: middle;
    margin-inline-start: var(--space-2);
    inline-size: 1.725em;
    block-size: 1.725em;
    background: var(--c-mark);
    -webkit-mask: var(--icon-doppelpfeil) center / contain no-repeat;
    mask: var(--icon-doppelpfeil) center / contain no-repeat;
    transform: translateY(-0.09em);
    transition: transform var(--dur) var(--ease);
  }

  .block-video__link--plain:hover::after {
    transform: translateY(-0.09em) translateX(0.35em);
  }

  .block-video__link--plain .block-video__label {
    position: static;
    inset: auto;
    color: inherit;
    font-size: var(--fs-small);
  }

  .block-video__link--plain:hover .block-video__label {
    text-decoration: underline;
  }

  .block-video__figure figcaption {
    margin-block-start: var(--space-3);
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  /* K-MEDIA-03.2 YouTube-Platzhalter und K-MEDIA-03.3 YouTube-Player.

     Die Fläche hat ihr Seitenverhältnis von sich aus, auch ohne Vorschaubild:
     bis die Planeraufgabe `video_vorschau` das Bild geholt hat, steht der
     Knopf auf dem dunklen Grund, und beim Einsetzen des Players springt
     nichts. Hochformat (YouTube Shorts) ist 9:16 und schmaler, damit es in
     einer Rasterzelle nicht über die Nachbarn hinauswächst. */
  .video-player {
    --video-format: 16 / 9;
  }

  .video-player--hoch {
    --video-format: 9 / 16;
    max-inline-size: 24rem;
  }

  /* Knopf und Beschriftung stehen untereinander in der Mitte, nicht wie beim
     Standbild der Knopf mittig und die Beschriftung unten links: in einer
     schmalen Karte (189 px hoch auf dem Telefon) lagen die beiden sonst
     übereinander. Der Schleier ist deshalb gleichmäßig statt ein Verlauf von
     unten — die Schrift steht in der Bildmitte. */
  .video-player__start {
    display: grid;
    place-content: center;
    justify-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    aspect-ratio: var(--video-format);
    background: var(--c-dark);
    text-align: center;
  }

  .video-player__start::after {
    background: var(--c-scrim);
  }

  .video-player__start .block-video__play {
    position: relative;
    inset: auto;
    translate: none;
  }

  .video-player__start .block-video__label {
    position: relative;
    inset: auto;
    font-size: var(--fs-body);
  }

  .video-player__start img {
    position: absolute;
    inset: 0;
    block-size: 100%;
    aspect-ratio: auto;
  }

  .video-player__start .block-video__label {
    display: grid;
    gap: var(--space-1);
  }

  .video-player__hinweis {
    font-size: var(--fs-small);
    font-weight: 400;
    color: var(--c-on-dark);
  }

  .video-player__frame {
    display: block;
    inline-size: 100%;
    aspect-ratio: var(--video-format);
    border: 0;
    border-radius: var(--radius-md);
    background: var(--c-dark);
  }

  /* K-MEDIA-03.4 Eigenes Video, Player — dieselbe Fläche wie der
     YouTube-Platzhalter; das eingesetzte `<video>` trägt `.video-player__frame`.
     `contain`, damit nichts beschnitten wird, wenn die Bedienleiste das
     Seitenverhältnis um einen Pixel verfehlt. */
  video.video-player__frame {
    object-fit: contain;
  }

  /* K-MEDIA-03.5 Eigenes Video, Schleife.

     Standbild und Video liegen übereinander. Das Video ist unsichtbar, bis es
     läuft (`.is-laeuft`, gesetzt von `site.js` beim Ereignis `playing`), und
     blendet dann über das Standbild ein — das erste Bild des Videos, also ohne
     Sprung. Bleibt es beim Standbild (Bewegung reduzieren, Datensparmodus,
     kein JavaScript), sieht man keinen Unterschied zu einem Bild. */
  .video-schleife {
    --video-format: 16 / 9;
    position: relative;
    aspect-ratio: var(--video-format);
    overflow: hidden;
    border-radius: var(--radius-md);
    background: var(--c-dark);
  }

  .video-schleife--hoch {
    max-inline-size: 24rem;
  }

  .video-schleife__bild,
  .video-schleife__film {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
  }

  .video-schleife__film {
    opacity: 0;
    transition: opacity 0.6s var(--ease);
  }

  .video-schleife.is-laeuft .video-schleife__film {
    opacity: 1;
  }

  /* K-MEDIA-03.5.T1 Pauseknopf — unten rechts auf dem Schleier, 44 px
     Zielfläche. Er erscheint erst, wenn das Video läuft: vorher gibt es nichts
     anzuhalten. */
  .video-schleife__pause {
    position: absolute;
    z-index: 1;
    inset-inline-end: var(--space-3);
    inset-block-end: var(--space-3);
    display: grid;
    place-items: center;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--c-scrim);
    color: var(--c-on-dark);
    cursor: pointer;
  }

  .video-schleife__pause[hidden] {
    display: none;
  }

  .video-schleife__zeichen {
    inline-size: 1.5rem;
    block-size: 1.5rem;
  }

  .video-schleife__pause[aria-pressed='true'] .video-schleife__zeichen--pause,
  .video-schleife__pause[aria-pressed='false'] .video-schleife__zeichen--weiter {
    display: none;
  }

  @media (prefers-reduced-motion: reduce) {
    .video-schleife__film {
      transition: none;
    }
  }
  /* ══ Neue Bausteine ═════════════════════════════════════════════════
     Zehn Typen aus dem Vergleich mit dem WordPress-Kern, Stackable und dem
     eigenen Bestand. Was JavaScript bräuchte, fehlt bewusst: Reiter,
     Karussell, Zähl-Animation, Fortschrittsbalken. Das Akkordeon gibt es
     trotzdem — als details/summary ist es HTML.
     ═══════════════════════════════════════════════════════════════════ */

  /* --- Zitat --- */
  .block-quote__inner {
    margin: 0;
  }

  .block-quote__body {
    margin: 0;
    padding-inline-start: var(--space-5);
    border-inline-start: 3px solid var(--c-mark);
    font-size: var(--fs-lead);
    line-height: var(--lh-body);
  }

  .block-quote__body p + p {
    margin-block-start: var(--space-4);
  }

  .block-quote__source {
    margin-block-start: var(--space-4);
    padding-inline-start: var(--space-5);
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  .block-quote__source cite {
    font-style: normal;
    font-weight: 600;
    color: var(--c-ink);
  }

  .block-quote__org::before {
    content: ' · ';
  }

  /* --- Tabelle --- */
  .block-table__headline {
    font-size: var(--fs-h3);
    margin-block-end: var(--space-5);
  }

  /* Der Rahmen scrollt, damit eine breite Tabelle nicht die Seite aufzieht.
     Der Umriss beim Fokus gehört dazu: ohne ihn ist nicht zu sehen, dass hier
     mit der Tastatur gescrollt werden kann. */
  .block-table__scroll {
    overflow-x: auto;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
  }

  .block-table__scroll:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 2px;
  }

  .block-table__table {
    inline-size: 100%;
    border-collapse: collapse;
    font-size: var(--fs-small);
  }

  .block-table__table th,
  .block-table__table td {
    padding: var(--space-3) var(--space-4);
    text-align: start;
    vertical-align: top;
    border-block-end: 1px solid var(--c-border);
  }

  .block-table__table th {
    background: var(--c-raised);
    font-weight: 600;
    white-space: nowrap;
  }

  .block-table__table tbody tr:last-child td {
    border-block-end: 0;
  }

  /* Die Zeile unter dem Zeiger, damit das Auge in einer breiten Tabelle
     nicht die Zeile verliert. */
  .block-table__table tbody tr:hover {
    background: var(--c-row-hover);
  }

  /* --- Aufklappbare Abschnitte --- */
  .block-faq__list {
    border-block-start: 1px solid var(--c-border);
  }

  .block-faq__item {
    border-block-end: 1px solid var(--c-border);
  }

  .block-faq__question {
    padding: var(--space-4) 0;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
  }

  /* Das voreingestellte Dreieck weg, ein eigenes Zeichen hin: jenes steht bei
     jedem Browser anders und lässt sich nicht ausrichten. */
  .block-faq__question::-webkit-details-marker {
    display: none;
  }

  .block-faq__question::before {
    content: '+';
    flex: none;
    inline-size: 1em;
    font-weight: 400;
    color: var(--c-muted);
  }

  .block-faq__item[open] > .block-faq__question::before {
    content: '−';
  }

  .block-faq__answer {
    padding-block-end: var(--space-5);
  }

  .block-faq__answer p + p {
    margin-block-start: var(--space-4);
  }

  /* --- Galerie und Team: dasselbe Raster --- */
  .block-gallery__grid,
  .block-team__grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-5);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  }

  @media (width >= 60rem) {
    .block-gallery__grid,
    .block-team__grid {
      grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
    }
  }

  .block-gallery__cell figure,
  .block-gallery__cell img {
    margin: 0;
    display: block;
    inline-size: 100%;
    block-size: auto;
    border-radius: var(--radius-md);
  }

  .block-gallery__cell figcaption {
    margin-block-start: var(--space-3);
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  .block-team__portrait {
    inline-size: 100%;
    block-size: auto;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    border-radius: var(--radius-md);
    margin-block-end: var(--space-4);
  }

  .block-team__name {
    font-size: var(--fs-body);
    margin: 0;
  }

  .block-team__role {
    margin-block: var(--space-1) var(--space-3);
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  .block-team__text {
    font-size: var(--fs-small);
    line-height: var(--lh-body);
  }

  /* --- Schaltflächengruppe --- */
  .block-buttons__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
  }

  /* --- Trennlinie --- */
  .block-separator {
    --block-y: var(--section-y-tight);
  }

  .block-separator__rule {
    border: 0;
    margin: 0;
  }

  .block-separator__rule--line {
    border-block-start: 1px solid var(--c-border);
  }

  /* Punktreihe statt Linie: dieselbe Trennung, weicher. Als Hintergrundbild,
     damit kein zusätzliches Element im Dokument steht. */
  .block-separator__rule--dots {
    block-size: 5px;
    background-image: radial-gradient(circle, var(--c-border-strong) 1.5px, transparent 1.6px);
    background-size: 1.25rem 5px;
    background-position: center;
    background-repeat: repeat-x;
  }

  /* --- Kennzahlen --- */
  .block-stats__list {
    margin: 0;
    display: grid;
    gap: var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  }

  .block-stats__value {
    font-size: var(--fs-display);
    line-height: var(--lh-display);
    letter-spacing: var(--ls-display);
    font-weight: 700;
  }

  .block-stats__label {
    margin: var(--space-2) 0 0;
    font-size: var(--fs-small);
    color: var(--c-muted);
    max-inline-size: 24ch;
  }

  [data-tone='contrast'] .block-stats__label {
    color: var(--c-on-contrast-muted);
  }

  /* --- Hinweiskasten --- */
  .block-notice__box {
    padding: var(--space-5);
    border-radius: var(--radius-md);
    border-inline-start: 3px solid currentColor;
    background: var(--c-raised);
  }

  .block-notice__box--info {
    color: var(--c-ink);
    border-inline-start-color: var(--c-border-strong);
  }

  .block-notice__box--warning {
    color: var(--c-error);
    background: color-mix(in srgb, var(--c-error) 7%, var(--c-bg));
  }

  .block-notice__box--success {
    color: var(--c-success);
    background: color-mix(in srgb, var(--c-success) 8%, var(--c-bg));
  }

  .block-notice__headline {
    font-size: var(--fs-body);
    margin: 0 0 var(--space-3);
  }

  /* Der Fließtext bleibt lesbar dunkel — die Farbe trägt der Rahmen und die
     Überschrift, nicht der Text. */
  .block-notice__text {
    color: var(--c-ink);
  }

  .block-notice__text + .block-notice__text {
    margin-block-start: var(--space-4);
  }

  /* --- Zeitleiste --- */
  .block-timeline__list {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  .block-timeline__step {
    position: relative;
    padding-inline-start: var(--space-6);
    padding-block-end: var(--space-6);
    border-inline-start: 1px solid var(--c-border);
  }

  .block-timeline__step:last-child {
    border-inline-start-color: transparent;
    padding-block-end: 0;
  }

  /* Der Punkt auf der Linie. Als ::before und nicht als Element: er ist Zierde,
     und ein Screenreader müsste ihn sonst vorlesen. */
  .block-timeline__step::before {
    content: '';
    position: absolute;
    inset-inline-start: -5px;
    inset-block-start: 0.35em;
    inline-size: 9px;
    block-size: 9px;
    border-radius: 50%;
    background: var(--c-mark);
  }

  /* Dieselbe Form wie ein Eyebrow, also auch dieselbe Farbe — auf dem weißen
     Grund 4,51:1. Der Punkt auf der Linie darüber trägt sie ohnehin schon. */
  .block-timeline__marker {
    margin: 0;
    font-size: var(--fs-eyebrow);
    letter-spacing: var(--ls-eyebrow);
    text-transform: uppercase;
    color: var(--c-accent);
  }

  /* Dieselben zwei Ausnahmen wie beim Eyebrow — und auf dem dunklen Band ist
     das zugleich die Behebung einer Unterschreitung: die Marke stand dort in
     --c-muted und erreichte 2,66:1. */
  [data-tone='contrast'] .block-timeline__marker {
    color: var(--c-accent-on-contrast);
  }

  [data-tone='sunken'] .block-timeline__marker {
    color: var(--c-muted-strong);
  }

  [data-bg] .block-timeline__marker {
    color: var(--c-on-dark);
  }

  .block-timeline__title {
    font-size: var(--fs-body);
    margin: var(--space-1) 0 var(--space-2);
  }

  .block-timeline__text {
    font-size: var(--fs-small);
    line-height: var(--lh-body);
  }

  /* ── Eingesetzte Bausteine ──────────────────────────────────────────
     Ein Baustein in einem Behälter behält seine Gestaltung und legt genau
     zwei Dinge ab: seine **eigene Hülle** und seinen **Abschnittsabstand**.
     Beides kommt vom Behälter, und beides zweimal ergibt doppelte Polster und
     eine Breite innerhalb einer Breite.

     Die Farben regelt niemand hier: `[data-tone='contrast']` an einer Textebene
     über einem Bild kehrt Überschriften, Verweise, Eyebrow und Schaltflächen
     schon um. Eine Aufzählung darin wird dadurch von selbst hell — hätte das
     Stylesheet diesen Kontextbegriff nicht, wäre jede Kombination von
     Behälter und Kind eigene Arbeit.
     ─────────────────────────────────────────────────────────────────── */
  [data-nested] {
    /* `.block` setzt `padding-block: var(--block-y, var(--section-y))` */
    --block-y: 0;
  }

  [data-nested] > .shell {
    max-inline-size: none;
    padding-inline: 0;
  }

  /* Ein eingesetzter Baustein mit eigener Fläche braucht seinen Abstand zurück:
     ohne ihn klebt die Schrift an der Kante der Tönung oder des Bildes.

     Diese zwei Regeln standen zuerst beim übrigen Flächenwerk im Layer
     `layout` — und wirkten nicht. Ein späterer Layer gewinnt unabhängig von
     der Spezifität, und `[data-nested] { --block-y: 0 }` steht hier in
     `blocks`. Am Bild nachgesehen, nicht überlegt: die Schrift saß auf der
     Kante. Deshalb stehen sie jetzt dort, wo sie etwas zurücknehmen. */
  [data-nested]:is([data-tone], [data-bg]) {
    --block-y: var(--space-6);
  }

  [data-nested]:is([data-tone], [data-bg]) > .shell {
    padding-inline: var(--space-6);
  }

  /* Der Abstand zwischen zwei eingesetzten Bausteinen ist ein Textabstand,
     kein Abschnittsabstand — sie stehen innerhalb eines Gedankens.

     Die Dichte wirkt hier zum zweiten Mal: außen am Abschnittsabstand, innen
     am Abstand zwischen den eingesetzten Bausteinen. Ein Behälter, der weit
     steht, soll auch innen atmen — sonst wäre „weit" eine Aussage über den
     Rand und nicht über den Abschnitt. */
  .nested {
    margin-block-start: var(--rhythm-inner, var(--space-5));
    display: grid;
  }

  /* Der Abstand steht als Rand am **zweiten** Baustein und nicht als `gap` am
     Umschlag — und das ist der ganze Unterschied zwischen „erben" und „erben,
     aber überschreibbar". Ein `gap` gehört dem Elternteil: ein eingesetzter
     Baustein, der `density: tight` wählt, könnte ihn nicht anfassen und stünde
     weiter so weit wie seine Geschwister. Als eigener Rand rückt er sich selbst
     heran. Ränder von Rasterkindern fallen nicht zusammen, der Abstand ist
     also genau einer. */
  .nested > .block + .block {
    margin-block-start: var(--rhythm-inner, var(--space-5));
  }

  /* Ein Bild in einem Behälter füllt die Spalte, in der es steht, und behält
     seine Proportion — die Deckelung aus `max_width` gilt weiter. */
  [data-nested].block-image img {
    inline-size: 100%;
    block-size: auto;
  }

  /* Der Verweis um ein Bild. Er ist ein Block und trägt **dieselbe** Deckelung
     wie das Bild darin — sonst wäre die anklickbare Fläche die ganze Spalte,
     und ein Klick neben ein schmales Abzeichen führte weg. Ohne eigene Angabe
     ist `--image-max` die natürliche Breite der Datei, der Verweis also
     genau so breit wie das Bild. */
  .block-image__link {
    display: block;
    max-inline-size: min(100%, var(--image-max, 100%));
    margin-inline: auto;
  }

  /* --- Bilderstreifen ---
     `gallery_style: slider` statt Raster. Ein scrollender Bereich mit
     Rastpunkten und ohne eine Zeile Skript.

     Die Bildlaufleiste bleibt sichtbar und wird nicht weggeräumt: sie ist der
     Hinweis darauf, dass hier etwas zu scrollen ist. Ein Streifen ohne
     Leiste, ohne Pfeile und ohne Punkte wäre ein Bereich, dessen zweite
     Hälfte niemand findet. */
  .block-gallery__grid[data-layout='slider'] {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    padding-block-end: var(--space-2);
  }

  .block-gallery__grid[data-layout='slider']:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 4px;
  }

  /* Die Breite einer Zelle ist die Containerbreite abzüglich der Rinnen,
     geteilt auf `--cols`. Bei einer Spalte ergibt das genau die volle Breite —
     ein Screenshot einer Anleitung soll lesbar sein und nicht als Vorschaubild
     neben zwei anderen stehen. */
  .block-gallery__grid[data-layout='slider'] > .block-gallery__cell {
    flex: 0 0 calc(
      (100% - (var(--cols, 1) - 1) * var(--space-5)) / var(--cols, 1)
    );
    scroll-snap-align: center;
  }

  /* --- Selbstlaufende Streifen ---
     `data-autoplay`: `site.js` schiebt in Abständen eine Karte weiter, pausiert
     beim Zeigen und beim Fokus und ruht außer Sicht. Die Bildlaufleiste ist
     hier weg — bei einem Streifen, der von selbst läuft, wäre sie ein
     Bedienelement für etwas, das man nicht bedient. Von Hand scrollen geht
     weiter: Wischen, Trackpad, Pfeiltasten.

     Ohne Skript läuft nichts von selbst, und der Streifen ist ein gewöhnlicher
     scrollender Bereich ohne Leiste; deshalb bleibt `tabindex` an ihm. */
  [data-layout='slider'][data-autoplay] {
    scrollbar-width: none;
    padding-block-end: 0;
  }

  [data-layout='slider'][data-autoplay]::-webkit-scrollbar {
    display: none;
  }

  /* Mit der Maus ziehbar (`site.js` setzt `data-draggable`). Die Greifhand nur
     dort, wo es eine Maus gibt — auf dem Telefon wäre sie ein Zeiger, den
     niemand sieht. Während des Zugs keine Textauswahl: die Hand hält die
     Karte, nicht den Satz darauf. */
  @media (hover: hover) and (pointer: fine) {
    [data-layout='slider'][data-draggable] {
      cursor: grab;
    }

    [data-layout='slider'][data-dragging] {
      cursor: grabbing;
      user-select: none;
    }

    [data-layout='slider'][data-dragging] a {
      cursor: grabbing;
    }
  }

  /* --- Kontaktangaben ---
     Eine Beschreibungsliste, kein Kartenraster: es sind drei Angaben, jede mit
     einer Beschriftung und einem Wert. `dl` sagt das auch dem Vorleseprogramm. */
  .block-contact__list {
    display: grid;
    gap: var(--space-4);
    margin-block-start: var(--space-6);
    padding-block-start: var(--space-5);
    border-block-start: 1px solid var(--c-border);
  }

  @media (width >= 40rem) {
    .block-contact__row {
      display: grid;
      grid-template-columns: 8rem 1fr;
      gap: var(--space-4);
      align-items: baseline;
    }
  }

  .block-contact__row dt {
    font-weight: 600;
    color: var(--c-muted);
    font-size: var(--fs-small);
  }

  .block-contact__row dd {
    margin: 0;
  }

  /* Browser setzen `address` kursiv. Eine kursive Anschrift liest sich
     schlechter, und schräge Ziffern in einer Postleitzahl sind kein Gewinn. */
  .block-contact__address {
    font-style: normal;
    line-height: var(--lh-body);
  }

  /* --- Freies Raster ---
     Zellen nebeneinander, und jede Zelle ist ein Baustein. Die Mechanik ist
     dieselbe wie beim Kartenraster: `auto-fit` bricht von selbst um, ab 60rem
     gilt die eingestellte Spaltenzahl. Bewusst ohne Rahmen und Schatten um die
     Zelle — Karten in Kästen in Kästen sind das sicherste Kennzeichen einer
     Vorlage von der Stange; eine Fläche bekommt, wer einen Hinweiskasten
     hineinsetzt oder dem ganzen Raster einen `tone` gibt. */
  .block-grid__list {
    display: grid;
    gap: var(--space-8) var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  }

  @media (min-width: 60rem) {
    .block-grid__list {
      grid-template-columns: repeat(var(--cells, 2), minmax(0, 1fr));
    }
  }

  /* `min-inline-size: 0` ist nötig, damit ein breiter Inhalt — eine Tabelle,
     ein Bild mit eigener Breite — die Spalte nicht aufzieht und das Raster
     sprengt. Ohne die Angabe hat eine Rasterspalte als Mindestbreite ihren
     Inhalt, nicht null. */
  .block-grid__cell {
    min-inline-size: 0;
    /* Die Zelle ist ein Anfragebereich, damit ein Baustein darin auf die Breite
       DER ZELLE reagieren kann und nicht auf die des Fensters. Siehe die
       Container-Regel unter dem Karussell: sie gilt Zelle und Folie
       gemeinsam. */
    container-type: inline-size;
  }

  /* Eine Tabelle in einer Zelle rollt in sich, statt die Spalte zu weiten. */
  .block-grid__cell .block-table__scroll {
    max-inline-size: 100%;
  }

  /* K-LAYOUT-06.3/.4 — eine Spalte doppelt so breit. Erst ab 60rem, wie die
     Spaltenzahl selbst; darunter bricht das Raster um, und dort wäre „doppelt
     so breit" eine Zelle, die die nächste aus der Zeile drängt.
     `--cells-rest` rechnet die Vorlage, weil `repeat()` eine ganze Zahl will. */
  @media (min-width: 60rem) {
    .block-grid__list[data-wide='first'] {
      grid-template-columns: minmax(0, 2fr) repeat(var(--cells-rest, 1), minmax(0, 1fr));
    }

    .block-grid__list[data-wide='last'] {
      grid-template-columns: repeat(var(--cells-rest, 1), minmax(0, 1fr)) minmax(0, 2fr);
    }
  }

  /* K-LAYOUT-06.5/.6 — wo der Inhalt sitzt, wenn die Nachbarspalte höher ist.
     Ohne Angabe oben: die Zellen strecken sich, ihr Inhalt beginnt oben. */
  .block-grid__list[data-valign='center'] {
    align-items: center;
  }

  .block-grid__list[data-valign='end'] {
    align-items: end;
  }

  /* K-LAYOUT-06.7–.9 — Abstand zwischen den Spalten. Am Attribut der Liste
     und nicht als Custom-Property: eine Gruppe in einer Zelle soll ihn nicht
     erben, sie hat ihr eigenes Feld. */
  .block-grid__list[data-gap='small'] {
    gap: var(--space-5) var(--space-4);
  }

  .block-grid__list[data-gap='large'] {
    gap: var(--space-9) var(--space-8);
  }

  .block-grid__list[data-gap='none'] {
    gap: 0;
  }

  /* K-LAYOUT-06.2 — untereinander. Die Kinder stehen in `.nested` wie in jedem
     Behälter; der Rand oben gehört dort einem Inhalt darüber. Ohne
     Überschrift steht nichts darüber, und die Gruppe begänne mit einer Lücke. */
  .block-grid__inner > .nested:first-child {
    margin-block-start: 0;
  }

  /* --- Freies Karussell ---
     Der dritte Streifen, und der einzige, dessen Folien Bausteine sind. Die
     Mechanik ist dieselbe wie beim Kartenstreifen — `data-layout="slider"` ist
     der Vertrag mit `site.js`, und die Regeln für Greifhand, verborgene
     Rollleiste und Rastpunkte stehen weiter unten und gelten allen Streifen.
     Hier steht nur, was die Folie selbst ausmacht. */
  .block-carousel__list {
    display: flex;
    gap: var(--space-6);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    padding-block-end: var(--space-2);
    /* Die Liste trägt Bausteine, keine Listenpunkte. */
    list-style: none;
    margin: 0;
    padding-inline: 0;
  }

  .block-carousel__list:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 4px;
  }

  /* Eine Folie ist so breit wie der Ausschnitt, geteilt durch die Zahl der
     Folien je Ansicht — dieselbe Rechnung wie beim Kartenstreifen.
     `min-inline-size: 0` ist nötig, damit ein breiter Inhalt (eine Tabelle,
     ein Bild) die Folie nicht aufzieht und den Streifen sprengt. */
  .block-carousel__slide {
    flex: 0 0 calc((100% - (var(--slides, 1) - 1) * var(--space-6)) / var(--slides, 1));
    min-inline-size: 0;
    scroll-snap-align: center;
  }

  /* Der Baustein IN der Folie füllt sie. `[data-nested]` nimmt ihm oben schon
     Hülle und Abschnittsabstand; hier kommt nur dazu, dass er die ganze Höhe
     nutzt — sonst stehen zwei Folien unterschiedlich hoch und der Streifen
     wackelt beim Weiterlaufen. */
  .block-carousel__slide > .block {
    block-size: 100%;
  }

  /* Eine Tabelle in einer Folie scrollt in sich, statt die Folie zu weiten. */
  .block-carousel__slide .block-table__scroll {
    max-inline-size: 100%;
  }

  /* --- Bausteine in einer Zelle oder Folie ---
     Beide sind Anfragebereiche (`container-type: inline-size`). Der Grund ist
     ein sichtbarer Fehler: „Bild und Text" teilt sich ab 60rem FENSTERbreite in
     zwei Spalten. In einer Zelle von 37rem — zwei Spalten auf einem 1440er
     Schirm — waren das zwei Spalten von je 250 Pixeln, also vier Wörter je
     Zeile.

     Die Schwelle rechnet vom Bestehenden her: die Teilung im Baustein setzt ab
     60rem Fensterbreite ein, dort ist die Hülle rund 56rem breit und eine
     Spalte davon 26rem. Unter 42rem Zellbreite bleibt für eine Spalte weniger
     als 20rem übrig — dann steht das Bild wieder über dem Text. Ein Raster mit
     zwei Spalten fällt damit immer in diese Form, ein Raster mit einer Spalte
     und eine Folie über die ganze Breite nie. */
  .block-carousel__slide {
    container-type: inline-size;
  }

  @container (max-width: 42rem) {
    .block-media-text__inner {
      grid-template-columns: 1fr;
      gap: var(--space-7);
    }

    /* Die Reihenfolge aus `data-media="right"` ist bei einer Spalte gegenstandslos:
       das Bild steht oben, wie im Dokument. */
    .block-media-text[data-media='right'] .block-media-text__figure {
      order: 0;
    }
  }

  /* --- Formular ---
     Felder untereinander, eine Spalte: ein Formular ist eine Liste von Fragen,
     und die liest man von oben nach unten. Die Breite kommt vom schmalen
     Container (`shell--prose`) — ein Eingabefeld über 750 Pixel ist eine
     Fläche, auf der der Cursor verloren geht.

     Rahmen wie die übrigen Linien, Radius der Eingabefelder klein (der große
     gehört den Schaltflächen — der Bestand trennt beides genauso). Der Fokus
     kommt aus der Basisregel `:focus-visible`; hier nur die Farbe des Rahmens,
     damit das Feld im Blick bleibt, auch wenn der Umriss außen liegt. */
  .block-form__form {
    display: grid;
    gap: var(--space-5);
  }

  .block-form__field {
    display: grid;
    gap: var(--space-2);
  }

  .block-form__label {
    font-weight: 600;
    font-size: var(--fs-small);
  }

  /* Der Stern stand einmal in abgedunkeltem Orange und danach neutral. Jetzt
     trägt er die Bedienfarbe unverändert — auf dem weißen Grund 4,51:1, und
     damit auch als Zeichen dieser Größe zulässig. */
  .block-form__req {
    color: var(--c-accent);
  }

  /* Wie beim Eyebrow. Auf dem dunklen Band stand der Stern in --c-ink und
     erreichte dort 1,50:1 — auch das ist damit behoben. */
  [data-tone='contrast'] .block-form__req {
    color: var(--c-accent-on-contrast);
  }

  [data-tone='sunken'] .block-form__req {
    color: var(--c-muted-strong);
  }

  [data-bg] .block-form__req {
    color: var(--c-on-dark);
  }

  .block-form__input {
    inline-size: 100%;
    padding: 0.75rem 0.9rem;
    font: inherit;
    line-height: 1.4;
    color: var(--c-ink);
    /* Weiß auf dem Grund: ein Eingabefeld ist eine Fläche, in die man
       schreibt, und liegt damit *auf* der Seite. */
    background: var(--c-raised);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius-sm);
    transition: border-color var(--dur) var(--ease);
  }

  .block-form__input:hover {
    border-color: var(--c-muted);
  }

  .block-form__input:focus-visible {
    border-color: var(--c-accent);
  }

  textarea.block-form__input {
    resize: vertical;
    min-block-size: 8rem;
  }

  .block-form__field--check {
    grid-template-columns: auto 1fr;
    align-items: start;
    gap: var(--space-3);
  }

  .block-form__field--check .block-form__label {
    font-weight: 400;
    font-size: var(--fs-body);
    line-height: var(--lh-body);
  }

  .block-form__checkbox {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    margin: 0.15rem 0 0;
    accent-color: var(--c-accent);
  }

  .block-form__field--check .block-form__hint {
    grid-column: 1 / -1;
  }

  /* Fehler: die Farbe am Rahmen **und** ein Satz darunter — Farbe allein
     sieht nicht jeder. `aria-describedby` verbindet beides für Vorleser. */
  .block-form__field.is-invalid .block-form__input,
  .block-form__field.is-invalid .block-form__checkbox {
    border-color: var(--c-error);
    outline-color: var(--c-error);
  }

  .block-form__hint {
    margin: 0;
    font-size: var(--fs-small);
    color: var(--c-error);
  }

  .block-form__summary {
    margin: 0;
    padding: var(--space-3) var(--space-4);
    border-inline-start: 3px solid var(--c-error);
    background: var(--c-raised);
    color: var(--c-ink);
    font-weight: 600;
  }

  /* Der Honigtopf: aus dem Fluss und vom Schirm, aber im Dokument. */
  .block-form__trap {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .block-form__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
  }

  .block-form__note {
    margin: 0;
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  /* Der Dank nach dem Absenden: an der Stelle des Formulars, ruhig, mit
     der Erfolgsfarbe am Rand. `role="status"` sagt es dem Vorleser, ohne zu
     unterbrechen. */
  .block-form__done {
    padding: var(--space-5) var(--space-6);
    border-inline-start: 3px solid var(--c-success);
    background: var(--c-raised);
    border-radius: var(--radius-sm);
  }

  .block-form__done-text {
    margin: 0;
    font-size: var(--fs-lead);
    line-height: var(--lh-body);
  }

  /* Nur im Editor sichtbar (`editor`): der Dank als bearbeitbare Vorschau. */
  .block-form__preview {
    margin-block-start: var(--space-6);
    padding: var(--space-4) var(--space-5);
    border: 1px dashed var(--c-border-strong);
    border-radius: var(--radius-sm);
  }

  .block-form__preview-label {
    margin: 0 0 var(--space-2);
    font-size: var(--fs-eyebrow);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--c-muted);
  }

  /* --- Ausrichtung ---
     `data-align` steht am Abschnitt und wird von drei Vorlagen gesetzt:
     Textabschnitt, Schaltflächen, Bild. Im Bestand ist `contentAlign` mit 762
     Vorkommen die häufigste Einstellung überhaupt (403 mittig, 322 links, 37
     rechts) und war bei uns die einzige der Spitzengruppe ohne Feld.

     Angesetzt wird nicht am Abschnitt, sondern an genau den Elementen, die den
     Text tragen. `text-align` am Abschnitt erbt in die eingesetzten Bausteine:
     eine mittig gestellte Textspalte zöge eine Aufzählung darin mit, und eine
     zentrierte Aufzählung ist keine mehr. */
  [data-align='center']
    > .block-text__inner
    > :is(.eyebrow, .block-text__headline, .block-text__body, .block-text__cta) {
    text-align: center;
  }

  [data-align='right']
    > .block-text__inner
    > :is(.eyebrow, .block-text__headline, .block-text__body, .block-text__cta) {
    text-align: right;
  }

  [data-align='center'] > .block-buttons__inner > .block-buttons__row {
    justify-content: center;
  }

  [data-align='right'] > .block-buttons__inner > .block-buttons__row {
    justify-content: flex-end;
  }

  /* Beim Bild ist mittig die Voreinstellung (`margin-inline: auto` oben), links
     und rechts sind hier die Abweichung — deshalb steht `left` in der
     Weißliste, obwohl es am Textabschnitt nichts bewirkt.

     Getroffen wird das Bild **oder** der Verweis darum: welches von beiden das
     äußere Element ist, entscheidet die Vorlage. */
  [data-align='left'] > .block-image__figure > :is(img, .block-image__link) {
    margin-inline: 0 auto;
  }

  [data-align='right'] > .block-image__figure > :is(img, .block-image__link) {
    margin-inline: auto 0;
  }

  /* Die Bildunterschrift folgt dem Bild. Sie ist der einzige Fließtext in der
     Figur; das Bild selbst ist ein Block und wird von `text-align` nicht
     bewegt. */
  [data-align='center'] > .block-image__figure {
    text-align: center;
  }

  [data-align='right'] > .block-image__figure {
    text-align: right;
  }
  /* --- K-LAYOUT-11 Ebenen-Block -------------------------------------------
     Die Kinder liegen übereinander in **einer** Rasterzelle. Keine Ebene liegt
     absolut — die Bühne wird so hoch wie ihre höchste Textebene, und Text
     ragt nie heraus. Bilder und Videos geben keine Höhe vor, sie füllen.

     Jede Einstellung kommt dreifach als Custom Property aus `ebene()` und
     `layer()` (`-d`, `-t`, `-m`, schon fertig vererbt). Hier wird nur gewählt:
     die Desktopfassung als Grundlage, Tablet und Mobil in Container-Queries.
     Gemessen wird die Breite **des Blocks** (`.block-layer__inner`), nicht
     des Fensters — ein Ebenen-Block in einer halben Rasterzelle ist auch auf
     dem Desktop schmal und soll sich so verhalten.

     Füllen und Stapeln schalten mehrere Eigenschaften zugleich um und stehen
     deshalb in Bereichen, die sich gegenseitig ausschließen: so muss keine
     Breite zurücknehmen, was eine andere gesetzt hat. */
  .block-layer {
    --schleier-dicht: color-mix(in srgb, var(--c-dark-deep) 74%, transparent);
    /* Die verfügbare Höhe (K-LAYOUT-11.8) ist das Fenster unterhalb dessen,
       was über dem Block steht: was so hoch ist, endet am unteren
       Fensterrand. `--oben` ist dieser Abstand. Das Stilblatt schätzt ihn —
       die Kopfzeile wächst nicht mit der Schrift (R-20), gemessen am
       06.10.2026 76,8 px unter 60rem (Menüknopf) und 73,5 px darüber; auf
       Unterseiten kommen die Brotkrumen in einer Zeile dazu (45 px).
       `site.js` misst nach und überschreibt die Schätzung nur, wo sie nicht
       stimmt: Brotkrumen in zwei Zeilen, die Redaktionsleiste. Weil die
       Schätzung im Regelfall genau ist, springt beim Nachmessen nichts. Steht
       der Block weiter unten, zählt nur die klebende Kopfzeile. */
    --oben: 77px;
    --verfuegbar: calc(100svh - var(--oben));
  }

  .breadcrumbs + .block-layer {
    --oben: 122px;
  }

  /* Die Kopfzeile ist nur dort niedriger, wo sie zur Leiste wird — also nicht
     auf Tablets, die die Klappfläche behalten (`hover: none`, siehe K-NAV-03). */
  @media (width >= 60rem) and (hover: hover) {
    .block-layer {
      --oben: 74px;
    }

    .breadcrumbs + .block-layer {
      --oben: 119px;
    }
  }

  .block-layer__inner {
    container: ebenen / inline-size;
  }

  /* Randlos: die Bühne läuft über die ganze Breite und stößt an ihre
     Nachbarn. Der Text bleibt im Satzspiegel (`--e-rand` unten). */
  .block-layer[data-bleed='full'] {
    --block-y: 0;
  }

  .block-layer[data-bleed='full'] > .block-layer__inner {
    max-inline-size: none;
    padding-inline: 0;
  }

  /* K-LAYOUT-11.1 Übereinander — auf dem Desktop immer. */
  .block-layer__buehne {
    --format: var(--format-d);
    --hoehe: var(--hoehe-d);
    display: grid;
    grid-template: auto / minmax(0, 1fr);
    position: relative;
    isolation: isolate;
    overflow: clip;
    border-radius: var(--radius-lg);
  }

  /* Sichtbar nur, solange das Bild lädt — und als Fläche unter gestapeltem
     Text. Dunkel, weil darauf die helle Schrift der Ebenen steht. Nur mit
     Bild oder Video (`data-medien`): ohne liegt die Bühne durchsichtig auf
     der Fläche des Blocks, und der Text behält seine dunkle Schrift. */
  .block-layer__buehne[data-medien] {
    background: var(--c-dark);
  }

  .block-layer[data-bleed='full'] .block-layer__buehne {
    border-radius: 0;
  }

  /* Das Format steht nicht an der Bühne, sondern an einem leeren Platzhalter
     in derselben Zelle. So wird die Bühne so hoch wie das Größere von beiden:
     Format oder Text. Mit `aspect-ratio` an der Bühne selbst blieb sie starr —
     gemessen ragten 378 px Text aus einer Bühne von 339 px. */
  .block-layer__buehne::before {
    content: '';
    grid-area: 1 / 1;
    aspect-ratio: var(--format);
    min-block-size: var(--hoehe);
  }

  /* K-LAYOUT-11.T1 Ebene */
  .block-layer__ebene,
  .block-layer__schleier {
    grid-area: 1 / 1;
    min-inline-size: 0;
  }

  .block-layer__ebene {
    --e-platz: var(--e-platz-d);
    --e-breite: var(--e-breite-d);
    --e-abstand: var(--e-abstand-d);
    --e-anzeige: var(--e-anzeige-d);
    --e-fokus: var(--e-fokus-d);
    --e-groesse: var(--e-groesse-d);
    --e-rand: var(--e-abstand);
    position: relative;
    display: var(--e-anzeige);
    place-self: var(--e-platz);
    margin-block: var(--e-abstand);
    margin-inline: var(--e-rand);
    /* Text wird nie schmaler als 17rem: aus „ein Drittel" wird auf schmaler
       Bühne von selbst die volle Breite. Eine Bild- oder Videoebene mit
       fester Größe (`--e-groesse`, Feld `size`) nimmt stattdessen diese — die
       Eigenschaft fehlt sonst, und es gilt der Rückfall. */
    inline-size: var(--e-groesse, max(min(100%, 17rem), calc(var(--e-breite) - 2 * var(--e-rand))));
    max-inline-size: calc(100% - 2 * var(--e-rand));
  }

  .block-layer[data-bleed='full'] .block-layer__ebene {
    --e-rand: max(var(--e-abstand), calc((100% - var(--width-max)) / 2 + var(--gutter)));
  }

  /* Text direkt auf dem Bild: Farben aus dem Kontrastband (`data-tone`),
     Rollen-Token aus dem Abschnittsbild (`data-ueber-bild`, siehe oben) —
     aber nicht dessen Fläche. Die Fläche ist das Bild. */
  .block-layer__ebene[data-ueber-bild] {
    background: none;
  }

  /* Text mit eigener Fläche ist eine Karte auf dem Bild. */
  .block-layer__ebene > .block[data-tone] {
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
  }

  /* K-LAYOUT-11.T3 Aufmacher-Satz. Die Ebene, die die h1 der Seite trägt
     (`data-aufmacher` aus `ebene()`), setzt Überschrift und ersten Absatz wie
     der frühere Kopfbereich: Anzeigegröße, höchstens 22 Zeichen, darunter der
     Vorspann. Kein Feld — die Gestalt folgt der Rolle, und eine zweite h1
     gibt es nicht. Über dem Bild nimmt der Vorspann die gedämpfte helle
     Schrift; als Karte bleibt er bei der Farbe seiner Fläche. */
  [data-aufmacher] > .block-text > .block-text__inner > .block-text__headline {
    font-size: var(--fs-display);
    line-height: var(--lh-display);
    letter-spacing: var(--ls-display);
    max-inline-size: 22ch;
  }

  [data-aufmacher] > .block-text > .block-text__inner > .block-text__body > p:first-child {
    font-size: var(--fs-lead);
    line-height: 1.45;
    max-inline-size: 44ch;
  }

  [data-aufmacher][data-ueber-bild] > .block-text > .block-text__inner > .block-text__body > p:first-child {
    color: var(--c-on-contrast-muted);
  }

  /* Schaltflächen und eingesetzte Bausteine stehen mit Luft unter dem
     Vorspann, wie die Knöpfe im früheren Kopfbereich. */
  [data-aufmacher] > .block-text > .block-text__inner > .nested {
    margin-block-start: var(--space-8);
  }

  /* K-LAYOUT-11.T2 Schleier — liegt im HTML direkt vor der untersten
     Textebene ohne Fläche, also über dem Bild und unter dem Text. Er läuft
     vom Ankerpunkt des Textes weg; bei Mitte und Füllen bleibt er bis zum
     Rand gleich dicht. 0,55 am Text ist der Wert, für den `--c-scrim`
     bemessen ist (4,6:1 im schlechtesten Fall). */
  .block-layer__schleier {
    --s-richtung: var(--s-richtung-d);
    --s-ende: var(--s-ende-d);
    --s-anzeige: var(--s-anzeige-d);
    display: var(--s-anzeige);
    place-self: stretch;
    /* Positioniert wie die Ebenen: sonst malt der Browser ihn vor allen
       positionierten Ebenen und das Bild deckt ihn zu. So gilt für alle die
       Reihenfolge im HTML. */
    position: relative;
    pointer-events: none;
    background: linear-gradient(
      var(--s-richtung),
      var(--schleier-dicht) 0%,
      var(--c-scrim) 50%,
      var(--s-ende) 90%
    );
  }

  .block-layer[data-schleier='strong'] .block-layer__schleier {
    background:
      linear-gradient(var(--s-richtung), var(--schleier-dicht) 0%, var(--c-scrim) 50%, var(--s-ende) 90%),
      linear-gradient(var(--c-scrim), var(--c-scrim));
  }

  /* Tablet und Mobil: nur die Fassung wechseln. */
  @container ebenen (width < 60rem) {
    .block-layer__buehne {
      --format: var(--format-t);
      --hoehe: var(--hoehe-t);
    }

    .block-layer__ebene {
      --e-platz: var(--e-platz-t);
      --e-breite: var(--e-breite-t);
      --e-abstand: var(--e-abstand-t);
      --e-anzeige: var(--e-anzeige-t);
      --e-fokus: var(--e-fokus-t);
      --e-groesse: var(--e-groesse-t);
    }

    .block-layer__schleier {
      --s-richtung: var(--s-richtung-t);
      --s-ende: var(--s-ende-t);
      --s-anzeige: var(--s-anzeige-t);
    }
  }

  @container ebenen (width < 48rem) {
    .block-layer__buehne {
      --format: var(--format-m);
      --hoehe: var(--hoehe-m);
    }

    .block-layer__ebene {
      --e-platz: var(--e-platz-m);
      --e-breite: var(--e-breite-m);
      --e-abstand: var(--e-abstand-m);
      --e-anzeige: var(--e-anzeige-m);
      --e-fokus: var(--e-fokus-m);
      --e-groesse: var(--e-groesse-m);
    }

    .block-layer__schleier {
      --s-richtung: var(--s-richtung-m);
      --s-ende: var(--s-ende-m);
      --s-anzeige: var(--s-anzeige-m);
    }
  }

  /* Füllen: Bild oder Video liegt randlos hinter allem. Ein Ankerpunkt in
     einer anderen Breite macht dieselbe Ebene dort wieder zu einem Bild mit
     eigener Größe — deshalb je Breite eine eigene, ausschließende Regel. */
  @container ebenen (width >= 60rem) {
    .block-layer__ebene[data-fuellen~='d'] {
      place-self: stretch;
      margin: 0;
      inline-size: auto;
      max-inline-size: none;
    }

    .block-layer__ebene[data-fuellen~='d'] :is(.block-image__figure > img, .block-image__link, .video-schleife, .video-player) {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      max-inline-size: none;
      aspect-ratio: auto;
      border-radius: 0;
      object-fit: var(--e-passung, cover);
      object-position: var(--e-fokus);
    }

    .block-layer__ebene[data-fuellen~='d'] :is(.block-image__link > img, .video-schleife__bild, .video-schleife__film, .video-player img) {
      inline-size: 100%;
      block-size: 100%;
      object-fit: var(--e-passung, cover);
      object-position: var(--e-fokus);
    }

    .block-layer__ebene[data-fuellen~='d'] figcaption {
      display: none;
    }
  }

  @container ebenen (48rem <= width < 60rem) {
    .block-layer__ebene[data-fuellen~='t'] {
      place-self: stretch;
      margin: 0;
      inline-size: auto;
      max-inline-size: none;
    }

    .block-layer__ebene[data-fuellen~='t'] :is(.block-image__figure > img, .block-image__link, .video-schleife, .video-player) {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      max-inline-size: none;
      aspect-ratio: auto;
      border-radius: 0;
      object-fit: var(--e-passung, cover);
      object-position: var(--e-fokus);
    }

    .block-layer__ebene[data-fuellen~='t'] :is(.block-image__link > img, .video-schleife__bild, .video-schleife__film, .video-player img) {
      inline-size: 100%;
      block-size: 100%;
      object-fit: var(--e-passung, cover);
      object-position: var(--e-fokus);
    }

    .block-layer__ebene[data-fuellen~='t'] figcaption {
      display: none;
    }

    /* K-LAYOUT-11.2 Gestapelt / K-LAYOUT-11.3 Verzahnt, Tablet */
    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock']) {
      display: flex;
      flex-direction: column;
    }

    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock'])::before {
      display: none;
    }

    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock']) > .block-layer__ebene[data-fuellen~='t'] {
      aspect-ratio: var(--stapel-t);
    }
  }

  @container ebenen (width < 48rem) {
    .block-layer__ebene[data-fuellen~='m'] {
      place-self: stretch;
      margin: 0;
      inline-size: auto;
      max-inline-size: none;
    }

    .block-layer__ebene[data-fuellen~='m'] :is(.block-image__figure > img, .block-image__link, .video-schleife, .video-player) {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      max-inline-size: none;
      aspect-ratio: auto;
      border-radius: 0;
      object-fit: var(--e-passung, cover);
      object-position: var(--e-fokus);
    }

    .block-layer__ebene[data-fuellen~='m'] :is(.block-image__link > img, .video-schleife__bild, .video-schleife__film, .video-player img) {
      inline-size: 100%;
      block-size: 100%;
      object-fit: var(--e-passung, cover);
      object-position: var(--e-fokus);
    }

    .block-layer__ebene[data-fuellen~='m'] figcaption {
      display: none;
    }

    /* K-LAYOUT-11.2 Gestapelt / K-LAYOUT-11.3 Verzahnt, Mobil */
    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock']) {
      display: flex;
      flex-direction: column;
    }

    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock'])::before {
      display: none;
    }

    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock']) > .block-layer__ebene[data-fuellen~='m'] {
      aspect-ratio: var(--stapel-m);
    }
  }

  /* Gestapelt stehen die Ebenen untereinander in Stapelreihenfolge: das Bild
     oben, der Text darunter auf der dunklen Bühne. Verzahnt rückt die Ebene
     direkt nach dem Bild um 3rem hinein; die Bühne ist dann keine Fläche
     mehr, sondern nur noch Bild und Karte. */
  @container ebenen (48rem <= width < 60rem) {
    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock']) > :is(.block-layer__ebene, .block-layer__schleier) {
      place-self: auto;
      margin: 0;
      inline-size: auto;
      max-inline-size: none;
    }

    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock']) > .block-layer__schleier {
      display: none;
    }

    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock']) > .block-layer__ebene[data-ueber-bild] {
      padding: var(--space-6) var(--space-5);
    }

    .block-layer__buehne:is([data-modus-t='stack'], [data-modus-t='interlock']) > .block-layer__ebene:not([data-fuellen~='t'], [data-ueber-bild]) {
      margin: var(--space-4);
    }

    .block-layer__buehne[data-modus-t='interlock'] {
      overflow: visible;
      border-radius: 0;
      background: none;
    }

    .block-layer__buehne[data-modus-t='interlock'] > .block-layer__ebene[data-fuellen~='t'] {
      border-radius: var(--radius-lg);
      overflow: hidden;
    }

    .block-layer__buehne[data-modus-t='interlock'] > .block-layer__ebene[data-fuellen~='t'] + .block-layer__ebene,
    .block-layer__buehne[data-modus-t='interlock'] > .block-layer__ebene[data-fuellen~='t'] + .block-layer__schleier + .block-layer__ebene {
      margin: calc(-1 * var(--space-8)) var(--space-5) 0;
    }

    .block-layer__buehne[data-modus-t='interlock'] > .block-layer__ebene[data-ueber-bild] {
      background: var(--c-dark);
      border-radius: var(--radius-md);
      box-shadow: var(--shadow-md);
    }
  }

  @container ebenen (width < 48rem) {
    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock']) > :is(.block-layer__ebene, .block-layer__schleier) {
      place-self: auto;
      margin: 0;
      inline-size: auto;
      max-inline-size: none;
    }

    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock']) > .block-layer__schleier {
      display: none;
    }

    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock']) > .block-layer__ebene[data-ueber-bild] {
      padding: var(--space-6) var(--space-5);
    }

    .block-layer__buehne:is([data-modus-m='stack'], [data-modus-m='interlock']) > .block-layer__ebene:not([data-fuellen~='m'], [data-ueber-bild]) {
      margin: var(--space-4);
    }

    .block-layer__buehne[data-modus-m='interlock'] {
      overflow: visible;
      border-radius: 0;
      background: none;
    }

    .block-layer__buehne[data-modus-m='interlock'] > .block-layer__ebene[data-fuellen~='m'] {
      border-radius: var(--radius-lg);
      overflow: hidden;
    }

    .block-layer__buehne[data-modus-m='interlock'] > .block-layer__ebene[data-fuellen~='m'] + .block-layer__ebene,
    .block-layer__buehne[data-modus-m='interlock'] > .block-layer__ebene[data-fuellen~='m'] + .block-layer__schleier + .block-layer__ebene {
      margin: calc(-1 * var(--space-8)) var(--space-5) 0;
    }

    .block-layer__buehne[data-modus-m='interlock'] > .block-layer__ebene[data-ueber-bild] {
      background: var(--c-dark);
      border-radius: var(--radius-md);
      box-shadow: var(--shadow-md);
    }
  }
}

@layer content {
  /* --- Kopfzeile ----------------------------------------------------------
     Die Navigation hat auf schmalen Schirmen zwei Zustände, und welcher gilt,
     entscheidet allein die Klasse `js` am Wurzelelement:

       ohne `js`  waagerecht scrollende Leiste — jeder Link im DOM, erreichbar
                  und crawlbar. Das war lange der einzige Zustand.
       mit `js`   hinter einem Umschalter, aufklappend unter der Kopfzeile.

     Eine rein CSS-gelöste Klappnavigation wäre der dritte Weg und bleibt
     verworfen: `<details>` meldet sich Hilfsmitteln als Aufklappelement statt
     als Menü, reagiert nicht auf Escape, und `::details-content` ist neuerdings
     content-visibility-gesteuert, also zwischen den Engines uneinheitlich. Der
     Umweg über gut drei Dutzend Zeilen JavaScript liefert `aria-expanded`,
     Escape und Klick-daneben in derselben Form wie überall sonst im Netz.

     Entscheidend ist die Reihenfolge der beiden Zustände: der scrollende ist
     die Grundregel, der klappende die Zutat. Fällt `site.js` aus oder ist
     JavaScript abgeschaltet, bleibt die Seite vollständig bedienbar. */

  /* Die Leiste ist deckend weiß, nicht durchscheinend. Hier stand
     `color-mix(… 88%, transparent)` mit `backdrop-filter: blur(12px)` — ein
     Glaseffekt, der drei Nachteile hatte: der Inhalt schimmerte unter der
     Navigation durch und machte Beschriftungen unruhig, `backdrop-filter`
     kostet auf jedem Bildlauf eine eigene Ebene samt Weichzeichnung (auf
     schwachen Geräten sichtbar), und die Leiste nahm die Farbe dessen an, was
     zufällig darunter lag.

     `--c-raised` statt `--c-bg`: eine Fläche, die über dem Grund liegt, ist
     heller als er, und auf `#fafbfc` ist heller nur noch Weiß. Damit steht die
     Leiste auch ohne Schatten sichtbar über der Seite.

     Der Schatten kommt erst beim Scrollen. Solange die Seite oben steht, gibt
     es nichts zu überdecken — dann trennt die Linie. Beides gleichzeitig wäre
     doppelt, deshalb weicht die Linie, sobald der Schatten kommt. */
  .site-header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--c-raised);
    border-block-end: 1px solid var(--c-border);
    transition:
      box-shadow var(--dur) var(--ease),
      border-color var(--dur) var(--ease);
  }

  /* `is-scrolled` setzt `site.js` am Wurzelelement, sobald der Inhalt mehr als
     vier Pixel gelaufen ist. Ohne das Skript bleibt es bei der Linie — der
     Schatten ist Schmuck, keine Information. */
  .is-scrolled .site-header {
    border-block-end-color: transparent;
    box-shadow: var(--shadow-sm);
  }

  /* Wer weniger Bewegung wünscht, bekommt den Schatten ohne Überblenden. */
  @media (prefers-reduced-motion: reduce) {
    .site-header {
      transition: none;
    }
  }

  /* Liegt die Redaktionsleiste darüber, heftet sich die Kopfzeile unter sie
     statt an den oberen Rand. Die Klasse setzt `site.js` am `html`-Element,
     bevor es die Leiste einhängt — für alle anderen Besucher ändert sich hier
     nichts. */
  .has-adminbar .site-header {
    top: var(--td-adminbar-h);
  }

  /* R-20: Die Kopfzeile klebt oben und wächst deshalb nicht mit der
     Systemschrift. Logo, Menüknopf, Abstände und Polster sind Bedienrahmen,
     keine Schrift; sie bleiben bei den Maßen von 100 %. Bei 200 % brach die
     Zeile sonst um und belegte 273 px — ein Drittel des Bildschirms. Die
     Beschriftung „Shop" wächst weiter mit, wie jede Schrift. */
  .site-header__inner {
    display: flex;
    align-items: center;
    gap: min(var(--space-5), 24px);
    padding-block: min(var(--space-4), 16px);
  }

  /* 1.5rem sind keine Geschmacksfrage: „thermal" steht in der Markenfarbe
     #FF4000, und die erreicht auf Weiß nur 3,51:1. Ab 24px in normaler Stärke
     gilt der Schwellwert für große Schrift (3:1) statt 4,5:1 — die Wortmarke
     bleibt damit in der richtigen Farbe und ist trotzdem regelkonform.

     Kleiner setzen heißt also: Größe verteidigen, nicht Farbe ändern. Die
     Farbe steht nicht zur Verfügung — WCAG 1.4.3 nähme die Wortmarke sogar
     ganz von der Anforderung aus (docs/branding/farben.md). Der Umweg über
     die Schriftgröße ist der strengere und bleibt. */
  .brand {
    display: inline-flex;
    align-items: baseline;
    gap: 0.1em;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    text-decoration: none;
    white-space: nowrap;
    color: var(--c-ink);
  }

  /* Wortmarke: „thermal" leicht und in der Marke, „DRONES" fett und navy —
     so steht es im Logo. Hier und im Fuß sind die einzigen zwei Stellen, an
     denen --c-brand stehen darf; alles Bedienende trägt --c-accent. */
  .brand__light {
    font-weight: 400;
    color: var(--c-brand);
  }

  /* Die Höhe steht auch in `partials/header.html`: die Vorlage rechnet daraus
     die dargestellte Breite für `sizes` (36 px mal Seitenverhältnis). Wird sie
     hier geändert, muss die Zahl dort mitgehen — sonst lädt der Browser wieder
     eine Fassung, die nicht zur Fläche passt. */
  .brand__logo {
    height: min(2.25rem, 36px);
    width: auto;
  }

  /* --- Menübaum ----------------------------------------------------------
     Die Bestandsseite führt ein Menü über drei Ebenen: Menüpunkt →
     Spaltenüberschrift → Ziel. Nur so ist die dritte Ebene überhaupt
     erreichbar; eine flache Leiste hätte für 44 Ziele keinen Platz.

     Die Klappflächen der Breitfassung sind **reines CSS** — `:hover` für die
     Maus, `:focus-within` für die Tastatur. Das geht nur, weil die Fläche
     durchsichtig ist und nicht `display: none`: was nicht dargestellt wird, ist
     nicht fokussierbar, der Tabulator käme nie hinein, und die Fläche
     erschiene nie. So aber wandert der Fokus in die Liste und macht sie im
     selben Zug sichtbar — ohne eine Zeile JavaScript und ohne Zustand, der
     zwischen Skript und Stylesheet auseinanderlaufen könnte.

     Für Hilfsmittel ist das keine Notlüge: die Unterpunkte stehen als
     verschachtelte Liste in der Navigation und sind dort auch angesagt. Die
     Klappfläche ist eine Darstellungsform für Zeigegeräte, keine
     Zugangsschranke. */

  .site-nav {
    flex: 1;
    min-width: 0;
  }

  .nav-list {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  /* Erste Ebene: die Leiste. `overflow-x: auto` bleibt auf jeder Breite —
     passt der Inhalt, scrollt hier ohnehin nichts; passt er nicht, scrollt die
     Leiste statt das ganze Dokument. Die Klappfläche wird davon nicht
     beschnitten: ihr Bezugsrahmen ist `.site-header` und liegt damit
     **oberhalb** dieses Überlaufs. */
  .nav-list--1 {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    overflow-x: auto;
    scrollbar-width: none;
  }

  .nav-list--1::-webkit-scrollbar {
    display: none;
  }

  .nav-item__label {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    font-size: var(--fs-small);
    font-weight: 600;
    color: var(--c-muted);
    text-decoration: none;
    white-space: nowrap;
  }

  a.nav-item__label:hover {
    color: var(--c-ink);
  }

  .nav-list--1 > .nav-item > .nav-item__label {
    padding-block: var(--space-2);
    border-block-end: 2px solid transparent;
  }

  /* Markiert wird der Teilbaum, nicht nur der Treffer: steht man auf
     `/produkte/poisuite/`, ist „Produkte" der Menüpunkt, unter dem man sich
     befindet. Genau das zeigt die Bestandsseite auch. */
  .nav-list--1 > .nav-item.is-active > .nav-item__label {
    color: var(--c-ink);
    border-block-end-color: var(--c-mark);
  }

  /* Der Winkel am Menüpunkt mit Untermenü — zwei Rahmenkanten, um 45° gedreht.
     Rein dekorativ; die Struktur steckt in der verschachtelten Liste. */
  .nav-list--1 > .nav-item--branch > .nav-item__label::after {
    content: '';
    inline-size: 0.375rem;
    block-size: 0.375rem;
    border-inline-end: 1.5px solid currentColor;
    border-block-end: 1.5px solid currentColor;
    transform: translateY(-0.15em) rotate(45deg);
  }

  /* Zweite Ebene: die Klappfläche über die ganze Fensterbreite, wie im
     Original. Bezugsrahmen ist `.site-header`: es ist klebend positioniert,
     und schon das macht es zum Container für absolut positionierte Nachfahren.
     Früher stand hier zusätzlich ein `backdrop-filter`, das dasselbe bewirkt
     hätte — es ist entfallen, der Bezugsrahmen bleibt.

     Das seitliche Maß richtet die Spalten am `.shell` aus: bis 78rem greift die
     Rinne, darüber der Betrag, um den der Container eingerückt ist. Der
     Prozentwert bezieht sich auf die Kopfzeile und nicht auf `100vw` — sonst
     verschöbe eine sichtbare Bildlaufleiste die Spalten gegen den Rest der
     Seite. */
  .nav-list--2 {
    position: absolute;
    inset-inline: 0;
    inset-block-start: 100%;
    display: grid;
    /* Vier feste Spalten, keine `auto-fit`-Automatik: sonst verteilt eine
       Fläche mit drei Gruppen ihre Spalten anders als eine mit vier, und die
       Überschriften wandern beim Wechsel zwischen den Menüpunkten seitwärts.
       Die Bestandsseite hält dasselbe Raster. */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-7) var(--space-6);
    padding-block: var(--space-7) var(--space-8);
    padding-inline: max(var(--gutter), 50% - var(--width-max) / 2 + var(--gutter));
    /* Dasselbe Weiß wie die Kopfzeile: die Klappfläche hängt an ihr und soll
       mit ihr eine Fläche bilden. Stand hier `--c-bg`, war die Naht zwischen
       Leiste und Fläche sichtbar, seit die Leiste deckend weiß ist. */
    background: var(--c-raised);
    border-block-end: 1px solid var(--c-border);
    box-shadow: var(--shadow-md);
    opacity: 0;
    pointer-events: none;
    transform: translateY(-0.25rem);
    transition:
      opacity var(--dur) var(--ease),
      transform var(--dur) var(--ease);
  }

  /* Die Brücke über den unteren Innenabstand der Kopfzeile. Ohne sie fällt der
     Zeiger auf dem Weg von der Beschriftung zur Fläche in den Zwischenraum, die
     Fläche verliert `:hover` und klappt unter dem Zeiger zu. Sie erbt
     `pointer-events` und fängt deshalb nur, was ohnehin offen ist. */
  .nav-list--2::before {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 100%;
    block-size: var(--space-4);
    content: '';
  }

  .nav-item--branch:hover > .nav-list--2,
  .nav-item--branch:focus-within > .nav-list--2 {
    opacity: 1;
    pointer-events: auto;
    transform: none;
  }

  /* Spaltenüberschrift. Sie führt oft, aber nicht immer irgendwohin —
     „Anwendungen" ordnet nur. Beide Fassungen sehen gleich aus, damit die
     Spalten nicht ungleich schwer wirken. */
  .nav-list--2 > .nav-item > .nav-item__label {
    font-size: var(--fs-body);
    color: var(--c-ink);
    white-space: normal;
  }

  /* Dritte Ebene: die Ziele, als Spalte unter der Überschrift. */
  .nav-list--3 {
    display: grid;
    gap: var(--space-3);
    margin-block-start: var(--space-5);
  }

  .nav-list--3 .nav-item__label {
    white-space: normal;
    font-weight: 400;
  }

  .nav-list--3 .nav-item__label[aria-current='page'] {
    color: var(--c-ink);
    font-weight: 600;
  }

  /* K-NAV-09 Menüeintrag mit Symbol. Ein Eintrag mit `options.icon` wird zur
     Zeile: Zeichen in der Bedienfarbe, Beschriftung neutral (R-02), und führt
     er hinaus, rechts ein Pfeil nach oben rechts. Die Zeilen sind 44 px hoch
     (R-10) und durch eine Haarlinie getrennt; der Abstand der Liste entfällt
     dafür, sonst stünde er zusätzlich zwischen den Linien.

     Der Pfeil sagt, dass der Link die Seite verlässt — der Newsletter liegt auf
     der eigenen Seite und trägt keinen. Er ist die einzige Bewegung: beim
     Überfahren rückt er ein Stück in seine Richtung und färbt sich ein. */
  .nav-list--3:has(> .nav-item--icon) {
    gap: 0;
    /* Die Schrift steht mittig in der 44-px-Zeile und damit tiefer als der
       erste Eintrag der Nachbarspalten. Der halbe Überstand über eine Zeile
       Text wird oben abgezogen, damit die ersten Zeilen fluchten. */
    margin-block-start: calc(var(--space-5) - (2.75rem - 1lh) / 2);
  }

  .nav-item--icon > .nav-item__label {
    display: flex;
    gap: var(--space-3);
    min-block-size: 2.75rem;
  }

  .nav-item--icon + .nav-item--icon {
    border-block-start: 1px solid var(--c-border);
  }

  .nav-item__icon {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    flex-shrink: 0;
    color: var(--c-mark);
  }

  .nav-item__out {
    inline-size: 1rem;
    block-size: 1rem;
    flex-shrink: 0;
    margin-inline-start: auto;
    color: var(--c-muted);
    transition:
      color var(--dur) var(--ease),
      transform var(--dur) var(--ease);
  }

  a.nav-item__label:hover .nav-item__out,
  a.nav-item__label:focus-visible .nav-item__out {
    color: var(--c-mark);
    transform: translate(0.125rem, -0.125rem);
  }

  /* Der Knopf gehört der Schmalfassung: dort klappt er den Zweig auf. In der
     Breitfassung übernimmt das `:hover`/`:focus-within`, und ein zweiter
     Bedienweg mit eigenem Zustand wäre eine Quelle für Widersprüche. */
  .nav-branch-toggle {
    display: none;
  }

  .locale-switch {
    display: flex;
    gap: var(--space-1);
    flex-shrink: 0;
  }

  .locale-switch a {
    padding: 0.25rem 0.45rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: var(--c-muted);
    text-decoration: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
  }

  .locale-switch a:hover {
    color: var(--c-ink);
  }

  .locale-switch a.active {
    color: var(--c-ink);
    background: var(--c-sunken);
    border-color: var(--c-border);
  }

  /* Der Shop liegt unter eigener Domäne und ist im Original ein Knopf neben dem
     Menü. Er bleibt außerhalb der Klappfläche und damit auf jeder Breite
     sichtbar — eine Handlungsaufforderung hinter einem Umschalter ist keine. */
  .site-header__shop {
    flex-shrink: 0;
  }

  /* --- Klappnavigation ----------------------------------------------------
     Ausgangszustand, gültig auf jeder Breite: die Hülle erzeugt keine eigene
     Box, `.site-nav` und `.locale-switch` bleiben damit unmittelbare
     Flex-Kinder von `.site-header__inner`. Ohne `display: contents` müsste die
     gesamte Geometrie der Kopfzeile oben umgeschrieben werden, nur damit ein
     Umschalter auf kleinen Schirmen möglich wird. Der Knopf ist verborgen und
     wird nur im Klappzustand weiter unten hervorgeholt. */

  .site-nav-panel {
    display: contents;
  }

  .nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    /* 2.75rem sind 44px — die kleinste Zielfläche, die WCAG 2.5.8 zulässt.
       Das Symbol darin ist kleiner; der Rest ist unsichtbare Trefferfläche. */
    inline-size: min(2.75rem, 44px);
    block-size: min(2.75rem, 44px);
    padding: 0;
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    color: var(--c-ink);
    cursor: pointer;
  }

  .nav-toggle__bars {
    position: relative;
  }

  .nav-toggle__bars,
  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    display: block;
    inline-size: 1.375rem;
    block-size: 2px;
    border-radius: 1px;
    background: currentColor;
    transition:
      transform var(--dur) var(--ease),
      background-color var(--dur) var(--ease);
  }

  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    position: absolute;
    inset-inline-start: 0;
    content: '';
  }

  .nav-toggle__bars::before {
    inset-block-start: -0.4375rem;
  }

  .nav-toggle__bars::after {
    inset-block-start: 0.4375rem;
  }

  /* Offen: der mittlere Balken wird durchsichtig, die äußeren rücken zusammen
     und kreuzen sich. Bewusst `transition` und nicht `animation` — so greift
     der `prefers-reduced-motion`-Block im Basis-Layer von selbst. */
  .nav-toggle[aria-expanded='true'] .nav-toggle__bars {
    background: transparent;
  }

  .nav-toggle[aria-expanded='true'] .nav-toggle__bars::before {
    transform: translateY(0.4375rem) rotate(45deg);
  }

  .nav-toggle[aria-expanded='true'] .nav-toggle__bars::after {
    transform: translateY(-0.4375rem) rotate(-45deg);
  }

  /* Der Klappzustand steht als einziger Block in einer `max-width`-Abfrage,
     obwohl die Datei sonst durchweg mobile-first aufgebaut ist. Das ist keine
     Nachlässigkeit: Leiste und Klappfläche sind nicht Grund- und Ausbaustufe
     desselben Bauteils, sondern zwei Aggregatzustände. Als `min-width`
     geschrieben müsste jede Eigenschaft oben einzeln zurückgenommen werden,
     einschließlich der Klappflächen-Geometrie — und genau solche
     Rücknahmelisten laufen erfahrungsgemäß auseinander.

     Die Schwelle liegt bei 60rem und nicht mehr bei 52rem: mit fünf
     Menüpunkten, Sprachumschalter und Shop-Knopf war die Leiste bei 832px
     übervoll und begann zu scrollen, bevor der Umschalter übernahm. 60rem ist
     im Stylesheet ohnehin eine gesetzte Stufe (Kartenraster, Zwei-Spalter).

     Die Bereichsschreibweise `width < 60rem` statt `max-width: 59.999rem`
     schließt exakt an die `min-width: 60rem` der übrigen Abfragen an; mit dem
     Bruchwert bliebe dazwischen eine haarfeine Lücke ohne Zuständigkeit.

     `hover: none` holt Tablets und quer gehaltene Handys dazu. Die Leiste
     klappt allein über `:hover` und `:focus-within` auf — ein Finger kann
     beides nicht: der Tipp auf einen verlinkten Oberpunkt lud sofort dessen
     Seite, der auf einen unverlinkten zeigte die Fläche nur einen Augenblick,
     weil ein `span` keinen Fokus hält. Die Schwelle steht wortgleich in
     `site.js`. */
  @media (width < 60rem), (hover: none) {
    /* Ohne JavaScript steht der Baum offen als Spalte in der Kopfzeile. Das ist
       hoch, aber vollständig bedienbar — auch mit dem Finger, der nicht
       „hovern" kann. Die Leiste der Breitfassung wäre hier die schlechtere
       Grundregel: sie zeigt nur die erste Ebene, und die zweite käme allein
       über den Fokus. */
    /* Die Kopfzeile bricht um: Wortmarke und Shop-Knopf in die erste Zeile, der
       Menübaum darunter über die ganze Breite. Ohne den Umbruch stünde die
       Spalte als schmaler Flex-Nachbar neben der Wortmarke und wäre gut 60
       Zeichen breit. */
    .site-header__inner {
      flex-wrap: wrap;
    }

    .site-header__shop {
      order: 2;
      margin-inline-start: auto;
    }

    .site-nav {
      order: 3;
      flex-basis: 100%;
    }

    .locale-switch {
      order: 4;
    }

    .nav-list--1 {
      display: grid;
      gap: 0;
      overflow-x: visible;
    }

    .nav-list--1 > .nav-item > .nav-item__label {
      border-block-end: 0;
      border-inline-start: 2px solid transparent;
    }

    /* Die Akzentlinie wandert von unten an die Seite: unter einem Eintrag
       gelesen wirkte sie in der Spalte wie ein Trennstrich zum nächsten. */
    .nav-list--1 > .nav-item.is-active > .nav-item__label {
      border-block-end-color: transparent;
      border-inline-start-color: var(--c-mark);
    }

    .nav-list--1 > .nav-item--branch > .nav-item__label::after {
      content: none;
    }

    /* Aus der Klappfläche wird eine eingerückte Liste — kein eigener Grund,
       kein Schatten, keine absolute Lage. */
    .nav-list--2,
    .nav-list--3 {
      position: static;
      display: grid;
      grid-template-columns: 1fr;
      gap: 0;
      margin: 0;
      padding: 0;
      background: none;
      border: 0;
      box-shadow: none;
      opacity: 1;
      pointer-events: auto;
      transform: none;
    }

    .nav-list--2::before {
      content: none;
    }

    /* Beschriftung links, Klappknopf rechts, die Unterliste über die ganze
       Breite darunter. Als Flexbox mit `flex-wrap` geschrieben ging das schief:
       die Beschriftung darf schrumpfen, also schrumpfte sie auf null Breite und
       teilte sich die Zeile mit der Liste, die eigentlich umbrechen sollte. Ein
       Raster mit zwei Spuren kann das nicht passieren. */
    .nav-item {
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
    }

    .nav-item__label {
      grid-column: 1;
      padding-block: var(--space-3);
      font-size: var(--fs-body);
      white-space: normal;
    }

    .nav-list--2,
    .nav-list--3 {
      grid-column: 1 / -1;
    }

    .nav-list--2 > .nav-item > .nav-item__label,
    .nav-list--3 > .nav-item > .nav-item__label {
      font-size: var(--fs-small);
    }

    /* K-NAV-09: die Zeile ist über `min-block-size` schon 44 px hoch; die
       Polsterung der übrigen Einträge machte sie hier fast doppelt so hoch. */
    .nav-item--icon > .nav-item__label {
      padding-block: 0;
    }

    /* Den Ausgleich gegen die Nachbarspalten gibt es hier nicht: die Liste
       steht allein, und der Abzug wäre eine Lücke über der ersten Zeile. */
    .nav-list--3:has(> .nav-item--icon) {
      margin-block-start: 0;
    }

    /* Einrückung je Ebene, damit die Verschachtelung sichtbar bleibt. Die
       Liste, nicht der Eintrag, trägt sie — sonst rückte auch der Knopf ein. */
    .nav-list--2,
    .nav-list--3 {
      padding-inline-start: var(--space-4);
    }

    .js .nav-toggle {
      display: inline-flex;
      order: 3;
    }

    /* Bezugsrahmen ist wieder `.site-header`. Der seitliche Innenabstand ist
       derselbe `--gutter` wie im `.shell`, damit die Links unter der Wortmarke
       fluchten. */
    .js .site-nav-panel {
      display: none;
      position: absolute;
      inset-inline: 0;
      inset-block-start: 100%;
      padding: var(--space-2) var(--gutter) var(--space-5);
      /* Deckend, und im selben Weiß wie die Kopfzeile darüber: die Fläche
         hängt an ihr. Unter der aufgeklappten Fläche steht Fließtext, der
         sonst hindurchschiene. */
      background: var(--c-raised);
      border-block-end: 1px solid var(--c-border);
      box-shadow: var(--shadow-md);
      /* Wächst das Menü, schiebt die Fläche sich nicht aus dem
         Ansichtsfenster heraus, sondern scrollt in sich. Steht die
         Redaktionsleiste darüber, beginnt die Fläche um deren Höhe tiefer —
         ohne den Abzug liefe sie unten aus dem Bild, weil sie an einer nach
         unten gerückten Kopfzeile hängt. */
      max-block-size: calc(80dvh - var(--td-adminbar-h, 0px));
      overflow-y: auto;
    }

    .js .site-nav-panel[data-open] {
      display: block;
    }

    /* Mit JavaScript klappen die Zweige einzeln zu. Erst hier bekommt der
       Knopf eine Aufgabe, und erst hier wird er sichtbar. */
    .js .nav-branch-toggle {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      inline-size: 2.75rem;
      block-size: 2.75rem;
      flex-shrink: 0;
      padding: 0;
      background: none;
      border: 0;
      color: var(--c-muted);
      cursor: pointer;
    }

    .js .nav-branch-toggle .nav-chevron {
      inline-size: 0.4375rem;
      block-size: 0.4375rem;
      border-inline-end: 1.5px solid currentColor;
      border-block-end: 1.5px solid currentColor;
      transform: translateY(-0.1em) rotate(45deg);
      transition: transform var(--dur) var(--ease);
    }

    .js .nav-branch-toggle[aria-expanded='true'] .nav-chevron {
      transform: translateY(0.1em) rotate(225deg);
    }

    /* Die Überschrift ohne Link klappt ihren Zweig mit auf (`site.js`). */
    .js .nav-item--branch > .nav-item__label--plain {
      cursor: pointer;
    }

    .js .nav-item--branch > .nav-list {
      display: none;
    }

    .js .nav-item--branch[data-open] > .nav-list {
      display: grid;
    }

    .js .site-nav-panel .locale-switch {
      margin-block-start: var(--space-4);
      padding-block-start: var(--space-4);
      padding-inline-start: var(--space-4);
      border-block-start: 1px solid var(--c-border);
    }
  }

  /* --- Fußzeile ---
     Gestaltung von der Bestandsseite übernommen: neutrales Dunkelgrau #282828,
     hellgrauer Text mit Weiß beim Überfahren, Titel in normalem Schnitt statt
     Versalien, die weiße Wortmarke über der Anschrift und die Profile als
     Symbolknöpfe. Die Grautöne stehen als Literale hier und nicht in den
     Tokens: sie gehören der Fußzeile allein, ein Token würde zur Verwendung
     auf anderen Flächen einladen. */

  /* Kein zusätzlicher Außenabstand: der letzte Inhaltsblock bringt seinen
     unteren Innenabstand schon mit, beides zusammen wäre eine doppelte Lücke.
     Endet die Seite mit einer getönten Fläche, grenzt der Farbwechsel ab. */
  .site-footer {
    padding-block: var(--space-9) var(--space-6);
    background: #282828;
    color: #cccccc;
    font-size: var(--fs-small);
  }

  /* Spaltenmaße der Bestandsseite: die Anschrift doppelt so breit wie jede
     Linkspalte. Feste Spuren statt `auto-fit`, weil ungleiche Anteile sich
     nicht automatisch verteilen lassen. */
  .site-footer__inner {
    display: grid;
    gap: var(--space-7) var(--space-6);
    grid-template-columns: 1fr;
  }

  @media (min-width: 40rem) {
    .site-footer__inner {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (min-width: 64rem) {
    .site-footer__inner {
      grid-template-columns: 2fr 1fr 1fr 1fr;
    }
  }

  /* Höhe wie das Logo der Kopfzeile; die Breite folgt dem Seitenverhältnis. */
  .site-footer__logo {
    height: 2.25rem;
    width: auto;
  }

  /* Schriftfassung der Wortmarke — nur Rückfall, falls die Logodatei fehlt. */
  .site-footer__brand {
    font-size: 1.1875rem;
    font-weight: 700;
    color: #ffffff;
  }

  /* Die Wortmarke trägt die Marke exakt, hier wie in der Kopfzeile. Sie
     stand im Fuß als aufgehelltes #ff8a4c — die Marke selbst in
     abgewandelter Form, dauerhaft, an der einen Stelle, an der der Wert
     unbedingt stimmen muss. */
  .site-footer__brand .brand__light {
    color: var(--c-brand);
  }

  .site-footer__address {
    font-style: normal;
    margin-block-start: var(--space-4);
    line-height: 1.7;
  }

  .site-footer__locations {
    margin-block-start: var(--space-2);
    line-height: 1.7;
  }

  .site-footer__title {
    font-size: 1.125rem;
    font-weight: 400;
    color: #ffffff;
    margin-block-end: var(--space-4);
  }

  .site-footer__list {
    list-style: none;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .site-footer__contact {
    margin-block-start: var(--space-4);
  }

  /* Nur die Linkspalten laufen senkrecht — der Sprachumschalter in der
     Copyright-Zeile ist auch ein `nav` und bleibt waagerecht. */
  .site-footer nav:not(.locale-switch) {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: start;
  }

  /* Die vier Profilknöpfe: weißes Symbol auf mittlerem Grau, wie auf der
     Bestandsseite. 2.75rem Kantenlänge hält die Zielfläche über den 24px
     aus WCAG 2.5.8. */
  /* `wrap` wegen R-20: Die Knöpfe wachsen mit der Systemschrift, bei 200 %
     waren fünf nebeneinander 424 px breit und verbreiterten die Seite. */
  .site-footer__social {
    list-style: none;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-block-start: var(--space-5);
  }

  .site-footer__social a {
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    background: #666666;
    border-radius: 10px;
    color: #ffffff;
  }

  .site-footer__social a:hover {
    background: #4f4f4f;
    color: #ffffff;
  }

  .site-footer__social svg {
    width: 1.5rem;
    height: 1.5rem;
  }

  /* Der Sprachumschalter unten steht auf dunklem Grund und braucht daher
     andere Flächen als der in der Kopfzeile. */
  .site-footer .locale-switch a {
    color: #cccccc;
  }

  .site-footer .locale-switch a.active {
    color: #ffffff;
    background: rgb(255 255 255 / 0.12);
    border-color: #555555;
  }

  .site-footer a {
    color: #cccccc;
    text-decoration: none;
  }

  .site-footer a:hover {
    color: #ffffff;
    text-decoration: underline;
  }

  /* Widerruf der Einwilligung (K-NAV-10). Sieht aus wie die Verweise daneben,
     ist aber ein Knopf — er öffnet die Leiste. Ohne JavaScript gibt es nichts
     zu widerrufen, also auch keinen Knopf. */
  .site-footer__consent {
    display: none;
    min-block-size: 2.75rem;
    padding: 0;
    border: 0;
    background: none;
    color: #cccccc;
    font: inherit;
    cursor: pointer;
  }

  .js .site-footer__consent {
    display: inline-block;
  }

  .site-footer__consent:hover {
    color: #ffffff;
    text-decoration: underline;
  }

  /* K-NAV-10 Einwilligungsleiste. Am unteren Rand, über der Seite, aber nicht
     modal: dahinter bleibt alles bedienbar. Deckend und mit Schatten, ohne
     Durchscheinen (R-04). Die beiden Knöpfe sind gleich gebaut — Nein muss so
     leicht sein wie Ja. */
  .consent {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 20;
    max-block-size: 70dvh;
    overflow-y: auto;
    padding-block: var(--space-5);
    background: var(--c-raised);
    border-block-start: 1px solid var(--c-border);
    box-shadow: var(--shadow-md);
  }

  .consent__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4) var(--space-6);
  }

  .consent__text {
    flex: 1 1 32rem;
    min-inline-size: 0;
    font-size: var(--fs-small);
    color: var(--c-ink);
  }

  .consent__text p {
    margin: 0;
  }

  .consent__title {
    margin: 0 0 var(--space-1);
    font-size: var(--fs-body);
    font-weight: 700;
  }

  .consent__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  /* Gleich breit, nicht nur gleich gestaltet: ein kürzeres „Ablehnen" neben
     einem breiteren „YouTube erlauben" wäre schon ein Gewicht. */
  .consent__actions .btn {
    flex: 1 1 0;
    min-inline-size: 11rem;
    white-space: nowrap;
  }

  /* Copyright-Zeile in Weiß mit heller Trennlinie darüber — beides von der
     Bestandsseite. */
  .site-footer__meta {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-4);
    margin-block-start: var(--space-6);
    padding-block-start: var(--space-5);
    border-block-start: 1px solid #dddddd;
    color: #ffffff;
    font-size: 0.8125rem;
  }

  /* --- Brotkrumen --- */

  .breadcrumbs {
    padding-block: var(--space-5) 0;
    font-size: 0.8125rem;
    color: var(--c-muted);
  }

  .breadcrumbs ol {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: 0;
  }

  .breadcrumbs li + li::before {
    content: '\203A';
    margin-inline-end: var(--space-2);
    color: var(--c-border-strong);
  }

  .breadcrumbs a {
    color: inherit;
    text-decoration: none;
  }

  .breadcrumbs a:hover {
    text-decoration: underline;
  }

  /* --- Beitrag --- */

  .post {
    padding-block: var(--section-y-tight) var(--section-y);
    /* Ein Beitrag ist ein Artikel und keine Landingpage: seine Blöcke sind
       Absätze mit Bild, keine Abschnitte mit Farbwechsel. Mit dem großen
       Rhythmus stand ein dreizeiliger Beitrag in 350 Pixeln Luft, und ein
       Artikel mit sieben Textblöcken wurde doppelt so hoch wie die Vorlage. */
    --block-y: var(--section-y-tight);
  }

  .post__header {
    max-width: var(--width-prose);
  }

  .post__header h1 {
    font-size: clamp(2rem, 4.5vw, 3.25rem);
    letter-spacing: var(--ls-display);
    line-height: 1.08;
  }

  .post__meta,
  .archive__meta {
    font-size: var(--fs-small);
    color: var(--c-muted);
    margin-block: var(--space-4) 0;
  }

  .post__excerpt {
    font-size: var(--fs-lead);
    line-height: 1.5;
    color: var(--c-muted);
    margin-block-start: var(--space-5);
  }

  .post__image {
    margin-block: var(--space-8);
  }

  /* Das Beitragsbild kommt aus dem Bestand in jedem Seitenverhältnis, auch
     hochkant. Über die volle Containerbreite ergibt ein Hochkantbild einen 1500
     Pixel hohen Block, durch den man scrollen muss, bevor der erste Satz
     beginnt. Gedeckelt wird die Höhe und nicht beschnitten: `object-fit: cover`
     würde bei einem Porträt genau das Motiv wegschneiden. Mit `inline-size:
     auto` skaliert der Browser das Bild selbst herunter und zentriert es. */
  .post__image img {
    display: block;
    inline-size: auto;
    max-inline-size: min(100%, var(--image-max, 100%));
    max-block-size: 32rem;
    margin-inline: auto;
    border-radius: var(--radius-md);
  }

  .post__body {
    max-width: var(--width-prose);
  }

  .post__body p + p {
    margin-block-start: var(--space-5);
  }

  /* --- Archiv --- */

  .archive {
    padding-block: var(--section-y-tight) var(--section-y);
  }

  .archive__header h1 {
    font-size: var(--fs-h2);
  }

  .archive__intro {
    margin-block-start: var(--space-4);
    color: var(--c-muted);
    max-width: 58ch;
  }

  .archive__list,
  .block-post-list__list {
    list-style: none;
    padding: 0;
    margin-block-start: var(--space-9);
    display: grid;
    gap: var(--space-8) var(--space-6);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  }

  .archive__item h2,
  .block-post-list__title {
    font-size: var(--fs-h3);
    line-height: 1.3;
    margin-block-end: var(--space-2);
  }

  .archive__item h2 a,
  .block-post-list__title a {
    color: var(--c-ink);
    text-decoration: none;
  }

  /* Überschriften tragen keine Unterstreichung; der Hover bringt sie und
     färbt sie exakt, statt die Schrift in abgedunkeltem Orange zu setzen. */
  .archive__item h2 a:hover,
  .block-post-list__title a:hover {
    text-decoration: underline;
    text-decoration-color: var(--c-mark);
    text-decoration-thickness: 2px;
    text-underline-offset: 0.18em;
  }

  .archive__item p,
  .block-post-list__item p {
    color: var(--c-muted);
    font-size: var(--fs-small);
    line-height: 1.6;
  }

  /* Der Anrisstext kommt aus dem Bestand und ist zwischen einer Zeile und
     fünfzehn lang. Ungekürzt zieht ein einzelner Eintrag seine Rasterzeile auf
     die dreifache Höhe, und aus einer Übersicht wird eine Liste mit einem
     Ausreißer. Vier Zeilen und Auslassungspunkte — dieselbe Kürzung, die die
     Bestandsseite serverseitig vornimmt.

     `-webkit-`: das ist die einzige Schreibweise, die alle Engines verstehen;
     `line-clamp` ohne Präfix ist erst in Teilen umgesetzt. Kein Verlust an
     Inhalt, denn der vollständige Text steht im Beitrag. */
  .archive__excerpt,
  .block-post-list__excerpt {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    overflow: hidden;
  }

  .archive__thumb,
  .block-post-list__thumb {
    display: block;
    margin-block-end: var(--space-4);
    border-radius: var(--radius-md);
    overflow: hidden;
  }

  .archive__thumb img,
  .block-post-list__thumb img {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    transition: scale var(--dur-slow) var(--ease);
  }

  /* Wie im Kartenraster, mit derselben Begründung für die 25 %. */
  .archive__thumb img[data-tall],
  .block-post-list__thumb img[data-tall] {
    object-position: center 25%;
  }

  .archive__item:hover .archive__thumb img,
  .block-post-list__item:hover .block-post-list__thumb img {
    scale: 1.03;
  }

  /* Beitragsliste als Block. Sie erbt Raster, Beschnitt und Kürzung des
     Archivs (die Selektoren oben führen beide), braucht aber eigenen
     Blockabstand: sie steht zwischen anderen Blöcken einer Seite und nicht als
     einziger Inhalt eines Archivs. Der Abstand über der Liste entfällt, wenn
     kein Abschnittskopf darüber steht — sonst klaffte oben eine Lücke. */
  .block-post-list__list {
    margin-block-start: var(--space-8);
  }

  .section-head + .block-post-list__list {
    margin-block-start: var(--space-9);
  }

  .block-post-list__inner > .block-post-list__list:first-child {
    margin-block-start: 0;
  }

  .pagination {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    margin-block-start: var(--space-9);
    padding-block-start: var(--space-5);
    border-block-start: 1px solid var(--c-border);
    font-size: var(--fs-small);
    color: var(--c-muted);
  }

  /* --- Fehlerseite --- */

  /* Die Breite kommt aus `.shell--prose` in der Vorlage, nicht von hier —
     zwei `max-width`-Angaben am selben Element wären eine Frage der
     Schichtreihenfolge und damit unnötig fragil. */
  .error-page {
    padding-block: var(--section-y-loose);
  }

  .error-page h1 {
    font-size: var(--fs-h2);
    margin-block-end: var(--space-5);
  }

  .error-page p {
    color: var(--c-muted);
  }

  .error-page p + p {
    margin-block-start: var(--space-5);
  }
}

@layer utils {
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: var(--space-3) var(--space-4);
    background: var(--c-accent);
    color: var(--c-on-accent);
    font-weight: 600;
  }

  .skip-link:focus {
    left: 0;
  }

  .muted {
    color: var(--c-muted);
  }
}
