/* ============================================================
   sharemagazines Prototyp — Tablet 834
   ------------------------------------------------------------
   Screen-Layout und Screen-Wechsel. KEINE Komponenten — die
   liegen in /components, je eine Datei (AGENTS.md §16).

   Setzt voraus, in dieser Reihenfolge:
     ../sharemagazines-base/tokens.css
     ../sharemagazines-base/base.css
     ../sharemagazines-base/components/motion.css

   BREITE
   Der Prototyp läuft randlos über die Fensterbreite und ist bei
   834 px deckungsgleich mit Figma. Gefordert war die Spanne
   750–950; darüber wird zentriert, damit die Tablet-Typografie
   (Breakpoint 768–1199, SKILL.md §0) nicht in eine Breite läuft,
   für die sie nicht gemessen ist.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
   Diese Werte stehen so in Figma und liegen NICHT auf der
   Spacing-Skala aus tokens.css. AGENTS.md §2.4 verlangt die
   Skala, §8a und SKILL.md §17.1 erklären das gemessene Ergebnis
   für verbindlich. Hier gilt das Maß, sichtbar aufgeführt:

     32   Seitenrand im Onboarding (Figma: px-[32px]).
          Die Skala kennt 24 und 36, nicht 32.
     112  Breite des Navigationsstreifens.
     950  Obergrenze der Prototyp-Breite (aus der Anforderung,
          nicht aus dem System).

   ZU KLÄREN: soll der Onboarding-Rand auf --space-xl (36) oder
   --space-lg (24) gehen, oder wird 32 ein Token?
   ============================================================ */

/* ------------------------------------------------------------
   1. Bühne
   ------------------------------------------------------------ */

body {
  /* Der Nav-Streifen liegt fixiert; ohne diese Zeile scrollt die
     Seite unter ihm weg statt neben ihm. */
  overflow-x: hidden;
}

/* Die Bühnenmaße stehen auf :root und nicht auf .app, weil Scrim,
   Sheet und das Inhalte-Overlay AUSSERHALB von .app liegen — sie
   gehören über das ganze Fenster und würden die Werte sonst nicht
   erben. --buehne-links ist die linke Kante der Bühne: bei Fenstern
   über 950 px ist sie zentriert, darunter beginnt sie bei 0. */
:root {
  /* Die Höhe der Bottom Nav. Sie ergibt sich aus ihrem Inhalt
     (15,85 + 62 + 3,15 = 81), steht aber als Wert da, weil VIER
     Stellen sie brauchen: die Bar selbst, das Polster unter den
     Screens, das unter der Inhalte-Liste und der Abstand, den die
     Toast-Schicht über der Bar hält. Bis zum 15.09.2026 stand die
     81 dreimal als Zahl im Text. */
  --nav-bar-h: 81px;
  --nav-rail-breite: 112px;
  --prototyp-max: 950px;
  --buehne-links: max(0px, calc((100vw - var(--prototyp-max)) / 2));
}

.app {
  width: 100%;
  max-width: var(--prototyp-max);
  margin-inline: auto;
  position: relative;
  min-height: 100vh;
  background-color: var(--surface-primary);
}

/* ------------------------------------------------------------
   2. Screen-Wechsel
   ------------------------------------------------------------
   Alle Screens liegen im selben Dokument; sichtbar ist immer
   genau einer. [hidden] statt display:none im JS, damit der
   Zustand auch für Screenreader stimmt und der Fokus nicht in
   einem unsichtbaren Screen hängen bleibt.

   DER ÜBERGANG IST EIN LEICHTES GLEITEN. Bis zum 09.09.2026
   sprang der Wechsel hart — mit der Begründung, motion.css
   führe für Screens keine Kurve. Das stimmt weiter, aber die
   fehlende Kurve war nie eine Entscheidung gegen Bewegung,
   sondern eine Lücke. Lisi hat sie am 09.09.2026 geschlossen:
   „eine leichte smooth animation wäre schön, etwas dass es
   flüssig gleitet“. Der Block darunter führt sie aus.
   ------------------------------------------------------------ */

/* DIE KLASSE .screen WIRD HIER NICHT BENUTZT. base.css definiert
   sie als Layout-Helfer mit 20 px Seitenrand
   (--layout-screen-margin) — nicht als Umschalt-Klasse. Wer sie
   an eine Screen-Sektion hängt, bekommt einen Rand, den Figma
   nicht hat: der QR-Scanner stand dadurch 20 px eingerückt und
   der Sucherrahmen 9 px zu weit rechts. Umgeschaltet wird über
   data-screen, gestaltet über eigene Klassen.

   [hidden] MUSS GEWINNEN. Jedes Element, das hier ein eigenes
   display bekommt — .screen--voll, .app-gestell, .sheet-halter —
   überschreibt damit das display:none, das der Browser für
   [hidden] mitbringt. Genau daran lag es, dass der
   Navigationsstreifen im Onboarding stehen blieb: .app-gestell
   ist display:flex, und flex schlägt none.

   Deshalb eine Regel für alle statt eine je Element: die nächste
   Komponente mit eigenem display fällt sonst in dieselbe Falle. */
[hidden] {
  display: none !important;
}

/* ------------------------------------------------------------
   2z. Was nur im Besucher-Zugang dasteht
   ------------------------------------------------------------
   Wer sich über das WLAN einbucht, ist an einem Standort mit
   mehr Medienarten als die Vorschau zeigt: Spiele, eBooks und
   Hörbücher kommen dazu (Lisi, 10.09.2026).

   SEIT DEM 11.09.2026 GIBT ES ZWEI BESUCHER-ZUGÄNGE: über das
   WLAN und über den QR-Code. Für die Inhalte sind sie dasselbe —
   derselbe Ort, dieselben Medienarten. Sie unterscheiden sich
   nur in der Zeile unter dem Standort. Die Auswahl heißt deshalb
   „nicht Admin" und nicht „ist WLAN"; die Attribute im Markup
   heißen weiter data-nur-wlan, weil sie an vielen Stellen stehen
   — ZU KLÄREN, ob daraus data-nur-besucher werden soll.

   Der Zustand steht als data-zugang am <html>-Element, nicht am
   Screen: Entdecken liegt in .app-gestell, die Suche ist ein
   eigener Voll-Screen daneben — ein gemeinsamer Vorfahr ist erst
   das Dokument.

   Ohne das Attribut gilt der Admin-Zugang. So ist die Vorschau
   auch dann richtig, wenn das JS nicht läuft.
   ------------------------------------------------------------ */

/* ES WIRD VERSTECKT, NICHT EINGEBLENDET. Andersherum — verstecken
   und im WLAN-Zugang mit `display: revert` zurückholen — käme das
   Element nicht auf sein eigenes display zurück, sondern auf das
   des Browsers: aus einer `.sektion` (flex) würde ein `block`,
   und die Abschnitte fielen auseinander.

   So steht im WLAN-Zugang gar keine display-Regel im Weg. */
:root:not([data-zugang="wlan"]):not([data-zugang="qr"]) [data-nur-wlan] {
  display: none;
}

/* DAS ZEICHEN VOR DER ROLLENZEILE folgt dem Zugang: Person für
   den Admin, WLAN-Bogen fürs WLAN, Uhr für den QR-Code — der
   gilt auf Zeit (Figma „location access status", 11408:4070).

   ES SCHALTET CSS, NICHT DAS SKRIPT. Vorher setzte prototyp.js
   `el.hidden`, und das ist eine Eigenschaft von HTMLElement — an
   einem <svg> legt die Zuweisung nur eine Eigenschaft an, ohne
   das Attribut zu setzen. Alle drei Zeichen standen gleichzeitig
   da, sichtbar war das erste: die Person, auch neben „Mit WLAN
   verbunden" (Lisi, 14.09.2026).

   Ohne Attribut gilt der Admin-Zugang — so wie überall in diesem
   Abschnitt. */
[data-rollen-ikon] {
  display: none;
}

:root:not([data-zugang]) [data-rollen-ikon="admin"],
[data-zugang="admin"] [data-rollen-ikon="admin"],
[data-zugang="wlan"] [data-rollen-ikon="wlan"],
[data-zugang="qr"]   [data-rollen-ikon="qr"] {
  display: block;
}

/* Und andersherum: was nur zum Admin-Zugang gehört. Auf „Vor Ort"
   erzählen beide Zustände etwas anderes — der Admin einen
   Friseursalon, das WLAN das Klinikum aus dem Rahmen. Das Layout
   ist dasselbe, nur die Inhalte wechseln. */
[data-zugang="wlan"] [data-nur-admin],
[data-zugang="qr"] [data-nur-admin] {
  display: none;
}

/* UND NOCH EINE STUFE GENAUER. „Nicht Admin" reicht im Sheet „Dein
   Zugang" nicht: dort sagen WLAN und QR-Code Verschiedenes — der
   Code gilt auf Zeit und bringt zwei eigene Zeilen mit, das WLAN
   hat keine Frist. data-nur-qr und data-nur-netz sind die beiden
   EINZELNEN Fälle, data-nur-wlan bleibt das gemeinsame
   „nicht Admin". Ergänzt am 15.09.2026 (Figma 13435:12766). */
:root:not([data-zugang="qr"]) [data-nur-qr] {
  display: none;
}

:root:not([data-zugang="wlan"]) [data-nur-netz] {
  display: none;
}

/* ------------------------------------------------------------
   2v. Die Vorschau ohne Zugang
   ------------------------------------------------------------
   Wer über „Zur Vorschau" hereinkommt, sieht die App, hat aber
   keinen Zugang. Das sagt ein Banner über der Suche, und sein
   Knopf führt in die Zugangswege (Figma „access.none · Ziel B").

   Der Zustand steht als data-vorschau am <html>-Element, aus
   demselben Grund wie data-zugang: er betrifft Entdecken UND die
   feste Kopfzeile, und die haben keinen gemeinsamen Vorfahren
   unterhalb des Dokuments.

   Wie bei data-zugang wird VERSTECKT, nicht eingeblendet — sonst
   käme das Element beim Zurückholen auf das display des Browsers
   statt auf sein eigenes (§2z).
   ------------------------------------------------------------ */

:root:not([data-vorschau]) [data-nur-vorschau] {
  display: none;
}

/* Und umgekehrt: „Vor Ort" gibt es in der Vorschau nicht. Der
   Screen erzählt von einem Standort, an dem man eingebucht ist —
   ohne Zugang gibt es diesen Ort nicht, und ein Tab, der auf
   einen leeren Screen führt, ist schlimmer als keiner
   (Lisi, 14.09.2026). Gilt für beide Navigationen. */
:root[data-vorschau] [data-nicht-vorschau] {
  display: none;
}

/* HIER STAND DIE STÜTZE FÜR DEN BANNER-KNOPF (flex-shrink: 0,
   damit der Textblock daneben ihn nicht schmaler drückt, als
   sein Label breit ist). Sie ist am 14.09.2026 weg: Cowork hat
   `rolle=zugang` mit `aktion=button` in banner.css gebaut, nach
   11919:1804, und die Zeile steht dort jetzt als
   `.banner__row > .btn`.

   Ersatzlos gestrichen und nicht etwa umgeschrieben. Dieselbe
   Regel an zwei Orten ist in diesem Prototyp schon dreimal
   auseinandergelaufen — Press-Ring, Tab-Zuordnung, QR-Weg. Der
   Knopf im Markup hat dafür auch die Klasse `banner__aktion`
   verloren: sie trug nichts mehr, und das Beispiel in banner.css
   führt sie nicht. */

/* 16 UNTER DEM BANNER, NICHT 24 (Lisi, 14.09.2026: „der abstand
   muss korrigiert werden, es war falsch in figma, 16px zwischen
   banner und suche").

   Die 24 kamen aus dem alten Rahmen — Banner endet bei 99,
   Suchfeld beginnt bei 123. Der Rahmen ist inzwischen ein
   Auto-Layout mit Abstand 16 (353 × 285 bei X 20 / Y 93), und
   damit hält der Banner denselben Abstand wie das Suchfeld zu
   den Abkürzungen darunter. Ein Block, ein Abstand. */
.entdecken__banner {
  margin-bottom: var(--space-md);          /* 16 */
}

/* NICHT IM INHALTE-PANEL (Lisi, 14.09.2026: „bei inhalte bei
   tablet und mobile bitte wieder entfernen, das sieht nicht gut
   aus"). Das Panel liegt ÜBER einem Screen, der den Banner schon
   trägt — er stand dadurch zweimal übereinander im Bild. Der
   Zustand ist einmal gesagt genug. */

/* DIE GRAUE ZWEITE ZEILE IM BANNER stand hier am 14.09.2026 für
   ein paar Stunden. Cowork hat `color: var(--text-description)`
   an `.banner__untertitel` in banner.css gesetzt — mit der
   Begründung daneben, dass `.banner__zeilen` text-primary für
   den Titel setzt und der Untertitel sie ohne eigene Angabe
   miterbt. Ersatzlos weg. */

/* ------------------------------------------------------------
   Das Logo weicht dem Knopf
   ------------------------------------------------------------
   Aus der Demo, wörtlich: „Das Logo weicht nicht dem Scrollen,
   sondern der Aktion. Es geht nur dann, wenn etwas Neues in die
   Zeile kommt und der Platz bei 393 px sonst nicht reicht."

   Genau dieser Fall ist die Vorschau: beim Scrollen kommt der
   Zugangs-Knopf in die Zeile. Also schrumpft die Wortmarke mit
   demselben Fortschritt, mit dem der Knopf wächst — sie tauschen
   den Platz, und die Zeile wird nie zu eng.

   In jedem anderen Zustand bleibt das Logo stehen: dort kommt
   nichts hinzu.

   Auf dem Tablet stellt sich die Frage nicht — das Logo sitzt
   dort im Navigationsstreifen und nicht in der Kopfzeile
   (Lisi, 14.09.2026).
   ------------------------------------------------------------ */

:root[data-vorschau] .topbar .wortmarke {
  width: calc(79px * (1 - var(--zugang-p, 0)));
  opacity: calc(1 - var(--zugang-p, 0));
  overflow: hidden;
  flex-shrink: 0;
}

/* ------------------------------------------------------------
   Derselbe Knopf oben in der festen Zeile
   ------------------------------------------------------------
   Er blendet mit demselben Fortschritt ein wie das Such-Icon
   daneben — --such-icon-p kommt aus prototyp.js und misst, wie
   weit das große Suchfeld schon weg ist (topbar.css).

   Warum überhaupt zweimal derselbe Knopf: der Banner scrollt mit
   dem Inhalt weg, der Zustand bleibt aber. Ohne den Knopf oben
   wäre der einzige Weg zum Zugang nach zwei Wischern nicht mehr
   zu sehen.

   Bedienbar erst ab 0,6, wie das Such-Icon: ein halb sichtbares
   Ziel, das schon auslöst, ist eine Falle.
   ------------------------------------------------------------ */

.topbar__zugang {
  opacity: var(--zugang-p, 0);
  pointer-events: none;
  flex-shrink: 0;
}

.topbar__zugang[data-bedienbar] {
  pointer-events: auto;
}

/* ------------------------------------------------------------
   2a. Das Gleiten beim Screenwechsel
   ------------------------------------------------------------
   Ein Screen wird nicht überblendet, sondern getauscht: der alte
   ist im selben Augenblick weg, in dem der neue kommt. Der neue
   kommt aber nicht fertig an — er blendet auf und gleitet dabei
   ein Stück nach oben, als würde er von unten nachrücken.

   EINE ANIMATION, KEINE TRANSITION. Geschaltet wird über
   [hidden], also über display — dazwischen gibt es keinen
   Übergang, den eine Transition tragen könnte. Eine Animation
   startet dagegen von selbst neu, sobald ein Element wieder
   dargestellt wird. Genau das ist der Moment, den wir wollen.

   KEINE NEUEN WERTE. Dauer und Kurve sind die des Dialogs aus
   motion.css — 250 ms mit --motion-ease-out, dieselbe Fassung
   von „etwas erscheint“. Die Strecke ist --space-sm (12), der
   kleinste Abstand des Systems, den man als Weg überhaupt noch
   wahrnimmt. Mehr wäre ein Auftritt, weniger ein Zucken.

   DAS GERÜST BEWEGT SICH NICHT MIT. [data-screen="app"] ist der
   Rahmen um die Tab-Screens — Leiste oben, Navigation unten. Es
   gleitet nur das, was wirklich wechselt: der Inhalt. Würde der
   Rahmen mitlaufen, liefe die Bewegung doppelt, und die feste
   Leiste würde kurz wandern, obwohl sie steht.
   ------------------------------------------------------------ */

:root {
  --screen-gleiten: var(--space-sm);       /* 12 */
}

@keyframes screen-erscheinen {
  from {
    opacity: 0;
    transform: translateY(var(--screen-gleiten));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

[data-tab-screen]:not([hidden]),
[data-screen]:not([hidden]):not([data-screen="app"]) {
  animation:
    screen-erscheinen
    calc(var(--motion-dialog) * var(--motion-scale))
    var(--motion-ease-out)
    backwards;
}

/* Reduced Motion: die Fläche erscheint, statt zu fahren (§23.7).
   Die Ortsveränderung fällt weg, die Deckkraft trägt weiter —
   deshalb wird nur die Strecke auf null gesetzt und nicht die
   ganze Animation abgeschaltet. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --screen-gleiten: 0px;
  }
}

/* ------------------------------------------------------------
   2b. DER PROTOTYP BLEIBT AUF DEM TABLET-BREAKPOINT
   ------------------------------------------------------------
   tokens.css schaltet die Textgrößen bei 768 und bei 1200 um.
   Der zweite Sprung trifft diesen Prototypen, obwohl er ihn
   nicht meint: die Bühne bleibt bei --prototyp-max (950) stehen,
   die Media Query fragt aber das FENSTER. Wer die Datei auf
   einem 1400er Bildschirm öffnet, sieht also ein 950 breites
   Tablet mit Desktop-Schrift — Title-Text 20 statt 14, Small 16
   statt 14, H1 44 statt 34.

   Genau das ist am 04.09.2026 aufgefallen: „der Text unter den
   Covern ist zu groß". Er war im Prototyp richtig gebaut und im
   Fenster falsch dargestellt.

   Deshalb hier ab 1200 die TABLET-Werte zurück. Es sind keine
   neuen Zahlen — es sind dieselben, die tokens.css im
   Tablet-Block führt. Sie stehen doppelt, weil CSS die Werte
   einer anderen Media Query nicht lesen kann.

   FÜR DIE ECHTE APP GILT DAS NICHT. Dort entscheidet das Gerät,
   nicht ein Fenster. Dieser Block gehört zum Prototypen und
   nicht ins System.
   ------------------------------------------------------------ */

@media (min-width: 1200px) {
  :root {
    --font-size-h1:               34px;
    --font-size-h2:               27px;
    --font-size-h3:               22px;
    --font-size-large-text:       24px;
    --font-size-medium-text:      18px;
    --font-size-title-text:       14px;
    --font-size-small-text:       14px;
    --font-size-extra-small-text: 12px;

    /* Nur diese eine Zeilenhöhe unterscheidet sich zwischen
       Tablet (1,5 → 21) und Desktop (1,2 → 24). */
    --line-height-title-text:     1.5;
  }
}

/* ------------------------------------------------------------
   3. Screens ohne Navigationsstreifen
   ------------------------------------------------------------
   Onboarding und Anmelden gehören zu keinem Tab — dort gibt es
   keinen Streifen und deshalb auch keinen Einzug.
   ------------------------------------------------------------ */

.screen--voll {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ------------------------------------------------------------
   4. Onboarding
   ------------------------------------------------------------
   Aufbau: Video ganzflächig, darüber ein Verlauf, darüber der
   Inhalt an der Unterkante. Figma-Node 13832:13885, ausgelesen
   am 04.09.2026.
   ------------------------------------------------------------ */

/* GENAU EIN FENSTER HOCH, UNTEN BÜNDIG, OBEN ABGESCHNITTEN
   (Lisi, 14.09.2026: „der onboarding screen sollte unten
   ausgerichtet sein … oben den screen anschneiden und voll
   füllen, kein scroll. es soll immer den gesamten screen füllen
   und wenn abschneiden dann oben").

   Vorher stand hier nur das `min-height: 100vh` aus
   .screen--voll. „Mindestens" heißt: passt der Inhalt nicht,
   WÄCHST der Screen und die Seite scrollt — auf Android lag „Zur
   Vorschau" dadurch unter der Kante. Derselbe Fehler wie am
   07.09.2026 beim Intro, nur eine Datei weiter.

   Jetzt ist die Höhe fest. Der Inhalt hängt an der Unterkante
   (justify-content: flex-end), also läuft er bei zu wenig Platz
   nach OBEN über, und `overflow: hidden` schneidet ihn dort ab —
   genau die geforderte Richtung. Abgeschnitten wird die
   Zeichnung, nie ein Knopf.

   svh UND NICHT vh. `100vh` ist auf dem Telefon die Höhe OHNE
   die Browserleisten — der Browser rechnet mit dem Fenster, das
   entstünde, wenn die Leisten eingefahren wären. Solange sie
   ausgefahren sind (und ohne Scrollen fahren sie nie ein), ist
   der Screen dadurch höher als das Sichtbare, und unten fällt
   genau so viel weg, wie die Leisten hoch sind. Das ist der
   Streifen, der Lisi auf Android den Knopf abgeschnitten hat.

   `100svh` ist die kleine Fassung: die Höhe MIT ausgefahrenen
   Leisten. Sie ändert sich beim Scrollen nicht — hier wird
   ohnehin nicht gescrollt — und garantiert, dass nichts hinter
   einer Leiste landet. Die vh-Zeile davor bleibt als Rückfall
   für Browser ohne svh stehen. */
.onboarding {
  overflow: hidden;
  justify-content: flex-end;

  min-height: 0;
  height: 100vh;
  height: 100svh;
}

/* Das Video liegt hinter allem und füllt den Screen. Es ist
   532 x 1280 und damit schmaler als der Screen — object-fit:
   cover füllt die Breite und schneidet oben und unten ab, so wie
   der Rahmen in Figma über den Screen hinausragt. */
.onboarding__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Ohne z-index läge das Video über dem Verlauf, sobald es
     abspielt — ein Video erzeugt einen eigenen Stapelkontext. */
  z-index: 0;
}

/* Verlauf von durchsichtig auf surface-primary, das Ganze auf
   90 % Deckkraft. In Figma ist es Colors/Black auf 90 %; ein
   Token für „Schwarz auf 90 %" gibt es nicht, und ein zweites
   Token mit derselben Farbe in anderer Deckkraft wäre keins
   (AGENTS.md §15: Deckkraft gehört an das Element, nicht an die
   Farbe). Der durchsichtige Anfang bleibt durchsichtig, das
   Ende landet bei genau 90 % — also derselbe Wert wie in Figma,
   ohne neue Farbe. */
.onboarding__verlauf {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0.9;
  background-image: linear-gradient(
    to bottom,
    var(--surface-blur-gradient-0) 16%,
    var(--surface-primary) 64%
  );
  pointer-events: none;
}

.onboarding__inhalt {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xl);                    /* 36 */
  padding-inline: 32px;                    /* gemessen, siehe Kopf */
  padding-bottom: var(--space-xl);         /* 36 */
}

.onboarding__logo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);                    /* 8 */
  width: 364px;
  max-width: 100%;
}

.onboarding__claim {
  font-family: var(--font-family-display);
  font-size: var(--font-size-h3);
  line-height: var(--line-height-h3);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
  text-align: center;
}

.onboarding__aktionen {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);                    /* 12 */
  width: 100%;
}

/* ------------------------------------------------------------
   4b. Hover auf Geräten ohne Zeiger — erledigt
   ------------------------------------------------------------
   Hier stand vom 14.09.2026 bis zum selben Tag eine
   Zwischenlösung: sechs Hover-Regeln aus button.css und
   input.css lagen nicht hinter `(hover: hover) and
   (pointer: fine)`, und auf Android blieb der Zustand nach dem
   Antippen kleben (Lisi: „der button zeigt hover oder pressed
   state obwohl ich nicht gehovert oder gepresst habe").

   Cowork hat es an derselben Stelle gebaut, an der es hingehört
   — und dabei die `.is-hover`-Fassungen bewusst VOR der Media
   Query gelassen, damit das Vorführen auf jedem Gerät geht. Die
   Zwischenlösung ist deshalb ersatzlos weg: zwei Orte, die
   dasselbe sagen, laufen auseinander.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   5. Reduced Motion
   ------------------------------------------------------------
   Weniger, nicht aus (§23.7). Das Onboarding-Video ist eine
   30-Sekunden-Dauerbewegung über den ganzen Screen — genau die
   Art Ortsveränderung, die §23.7 wegfallen lässt. Statt des
   Videos bleibt sein erstes Bild stehen; Verlauf, Farbe und
   Inhalt sind unverändert, es fehlt nur die Bewegung.
   Das Anhalten selbst macht prototyp.js.
   ------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .onboarding__video {
    /* Poster statt Bewegtbild: das Video wird angehalten und auf
       Bild 0 zurückgesetzt, sichtbar bleibt das Standbild. */
    visibility: hidden;
  }

  .onboarding__standbild {
    display: block;
  }
}

/* Standbild-Ebene. Normalerweise aus — das Video bringt sein
   Poster selbst mit. */
.onboarding__standbild {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ------------------------------------------------------------
   6b. Im scrollenden Sheet beginnt der Inhalt an der Kante —
       erledigt
   ------------------------------------------------------------
   Hier stand am 14.09.2026 für ein paar Stunden die Rücknahme des
   24er Abstands unter der klebenden Kopfleiste. Cowork hat sie in
   `components/sheet.css` gebaut, an `.sheet--scroll .sheet__inhalt`,
   mit beiden Bedingungen als Begründung daneben: nur dieser eine
   Abstand, und in jeder Scroll-Position. Ersatzlos weg.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   7. Überlagerungen: Scrim und Sheet
   ------------------------------------------------------------
   dialog.css bringt .scrim mit (fixed, inset 0, scrim-black-50)
   und sheet.css das Sheet selbst. Was dort fehlt, ist die Lage
   im Screen — sheet.css sagt dazu ausdrücklich „position wird
   vom Screen gesetzt, nicht hier".

   Der Halter ist an die Bühnenbreite gebunden, nicht ans
   Fenster: das Sheet gehört zum Tablet-Screen und darf nicht
   breiter werden als er.
   ------------------------------------------------------------ */

.scrim {
  z-index: 20;
}

.sheet-halter {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 21;
  width: 100%;
  max-width: var(--prototyp-max, 950px);
  margin-inline: auto;
  /* Der Halter selbst fängt keine Klicks — sonst wäre der Streifen
     neben einem schmalen Sheet eine unsichtbare Klickfalle. */
  pointer-events: none;
}

.sheet-halter > .sheet {
  pointer-events: auto;
}

/* ------------------------------------------------------------
   6. Icons
   ------------------------------------------------------------
   input.css bringt eine .icon-Klasse mit (24 x 24, stroke:
   currentColor, fill: none). Die passt nur für die Augen-Icons.
   Der Prototyp braucht Icons in vielen Größen und teils gefüllt,
   deshalb eine eigene Klasse mit anderem Namen — input.css wird
   nicht angefasst (AGENTS.md §16).

   overflow: visible ist keine Kosmetik: Figma exportiert die
   viewBox OHNE den Strichsaum. Die Striche liegen mittig auf dem
   Pfad und ragen aus der Box heraus (in den Design-Contexts als
   negativer inset zu lesen). Ohne diese Zeile werden sie an der
   Symbolkante abgeschnitten und das Icon sieht dünner aus als in
   Figma. Die viewBox aufzuweiten wäre der falsche Weg — das
   verschiebt das Seitenverhältnis und verzerrt die Wortmarke.
   ------------------------------------------------------------ */

.ikon {
  display: block;
  overflow: visible;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
}


/* ------------------------------------------------------------
   8. Anmelden
   ------------------------------------------------------------
   Figma-Node 13837:14872 (leer) und 13837:14909 (getippt),
   ausgelesen am 04.09.2026.

   Aufbau: oben Zurück-Button, Titel und Erklärung, darunter die
   beiden Felder. Die Hauptaktion sitzt an der Unterkante — der
   Platz dazwischen bleibt leer, so wie in Figma. Das ist keine
   Lücke, die zu füllen wäre: die Tastatur des Tablets schiebt
   sich später von unten davor.

   Seitenrand hier 24 (--space-lg), nicht 32 wie im Onboarding
   und nicht 20 wie --layout-screen-margin. So gemessen.
   ------------------------------------------------------------ */

.anmelden {
  /* 24 oben und seitlich, 36 unten. Nicht symmetrisch, so
     gemessen: der CTA-Block endet in Figma 36 über der
     Unterkante — Platz für die Home-Indicator-Zone, dieselbe
     Begründung wie beim Sheet (sheet.css). */
  padding: var(--space-lg) var(--space-lg) var(--space-xl);
}

/* Die Aufteilung oben/unten sitzt auf dem Formular, nicht auf dem
   Screen: das Formular muss beides umschließen, damit die
   Eingabetaste den Knopf unten erreicht. */
.anmelden__form {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-lg);
}

.anmelden__oben {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);                    /* 24: Button zu Titelblock */
}

.anmelden__titelblock {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);                    /* 8 */
}

.anmelden__titel {
  font-family: var(--font-family-display);
  font-size: var(--font-size-h1);
  line-height: var(--line-height-h1);
  font-weight: var(--font-weight-extrabold);
  color: var(--text-primary);
}

.anmelden__erklaerung {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  color: var(--text-description);
}

/* Die Felder. 24 zwischen ihnen, gemessen: Feld 1 endet bei 69,
   Feld 2 beginnt bei 93. */
.anmelden__felder {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);                    /* 24 */
  margin-top: var(--space-lg);             /* 24 unter der Erklärung */
}

/* „Passwort vergessen" sitzt rechts unter dem Passwortfeld, ohne
   eigenen Abstand — die 45 px Höhe des Link Buttons tragen ihn. */
.anmelden__unter-feld {
  display: flex;
  justify-content: flex-end;
}

.anmelden__unten {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);                    /* 12 */
}

/* „Noch kein Konto?  Konto erstellen →" — Text und Link auf
   einer Zeile, zusammen mittig. Der Text bekommt keinen eigenen
   Abstand: das Padding des Link Buttons (8 links) ist der
   Abstand, genau wie bei .message__zeilen in message.css. */
.anmelden__konto-zeile {
  display: flex;
  align-items: center;
  justify-content: center;
}

.anmelden__konto-frage {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  color: var(--text-primary);
}

/* ------------------------------------------------------------
   9. App-Gerüst: Streifen links, Inhalt rechts
   ------------------------------------------------------------
   Figma-Node 13866:15967, ausgelesen am 04.09.2026.
   Streifen 112, Container 722, Innenabstand 24 → 674 Inhalt.

   DER STREIFEN BLEIBT STEHEN. In Figma ist er so hoch wie der
   Frame, also so hoch wie die ganze Seite. Im Prototyp ist er
   fixiert: die Seiten sind bis 3800 px lang, und §7 nennt die
   Navigation „die einzige jederzeit sichtbare Struktur der App".
   Wäre sie mitgescrollt, hinge daran auch §19 in der Luft —
   die Regel „Streifen sichtbar → ←, verdeckt → ✕" braucht einen
   Streifen, der wirklich sichtbar bleibt.
   ------------------------------------------------------------ */

.app-gestell {
  display: flex;
  align-items: flex-start;
  min-height: 100vh;
}

.app-gestell__rail {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: 10;
  /* Links an der Bühne, nicht am Fenster. */
  left: var(--buehne-links);
  overflow-y: auto;
  /* Kein Scrollbalken am Streifen — er ist kürzer als der
     Screen, außer bei sehr niedrigen Fenstern. */
  scrollbar-width: none;
}

.app-gestell__rail::-webkit-scrollbar {
  display: none;
}

.app-gestell__inhalt {
  flex: 1 1 auto;
  min-width: 0;
  /* Platz für den fixierten Streifen. */
  margin-left: var(--nav-rail-breite);
}

/* Der Inhaltsbereich eines App-Screens. 24 Rand, und die
   Cover-Reihen erfahren über --sektion-rand, wie weit sie nach
   rechts hinauslaufen dürfen. */
.app-screen {
  --sektion-rand: var(--space-lg);
  display: flex;
  flex-direction: column;
  padding: var(--space-lg);                /* 24 */
}

/* ------------------------------------------------------------
   10. Vor Ort
   ------------------------------------------------------------
   Figma-Node 13863:60420, ausgelesen am 04.09.2026.
   ------------------------------------------------------------ */

/* Kopfzeile: Suchleiste und Zahnrad, 8 Abstand, beide 45 hoch.
   Das Zahnrad steht nur auf den vier Nav-Hauptseiten (§26.3). */
.kopfzeile {
  display: flex;
  align-items: center;
  gap: var(--space-xs);                    /* 8 */
}

/* 24 unter der Kopfzeile, dann Karte, Hero, Willkommen. */
.vorort__oben {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);                    /* 24 */
  margin-top: var(--space-lg);
}

/* 674 x 220 aus Figma. Radius md, wie jede Content-Fläche (§9). */
.vorort__hero {
  width: 100%;
  aspect-ratio: 674 / 220;
  object-fit: cover;
  border-radius: var(--radius-md);
  background-color: var(--label-fill);
}

.vorort__willkommen {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);                    /* 8 */
}

.vorort__willkommen-titel {
  font-family: var(--font-family-display);
  font-size: var(--font-size-h1);
  line-height: var(--line-height-h1);
  font-weight: var(--font-weight-extrabold);
  color: var(--text-primary);
}

/* Fließtext in text-primary, nicht in text-description — aus dem
   Figma-Export nachgemessen und zugleich die Regel (AGENTS.md
   §8).

   ZWISCHEN DEN ABSÄTZEN LIEGT EINE LEERZEILE, kein Abstand von
   der Skala. In Figma ist der ganze Text EIN Textknoten mit einer
   leeren Zeile in der Mitte: 84 px hoch = vier Zeilen à 21, wobei
   die dritte leer ist. Ein gap von 12 wäre 9 px zu wenig.

   Der Wert steht deshalb nicht als Zahl da, sondern wird aus den
   Tokens gerechnet — Schriftgröße mal Zeilenhöhe. Damit stimmt er
   auch, wenn die Typo-Skala am Breakpoint wechselt. */
.vorort__willkommen-text {
  display: flex;
  flex-direction: column;
  gap: calc(var(--font-size-small-text) * var(--line-height-small-text));
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  color: var(--text-primary);
}

/* Der Button steht mittig, nicht über die volle Breite. Das ist
   die Ausnahme zu §13.5 („ein einzelner Button ist immer
   Full-Width") — die Regel gilt für AKTIONS-GRUPPEN in Dialog,
   Sheet und Fußzeile. Hier liegen die Buttons im Fließinhalt und
   sind ein Angebot, kein Abschluss.

   ZWEI BUTTONS ZU GLEICHEN TEILEN, 12 dazwischen. So steht es in
   Figma (13927:26903): beide `flex: 1 0 0` in einer Zeile von
   674, also 330 und 332 — der Unterschied ist Rundung, nicht
   Absicht. Vorher stand hier ein einzelner Button.

   Der Primär ist die Hauptaktion, der Ghost daneben beantwortet
   die Frage, die sich davor stellt. Ghost und nicht Sekundär:
   Sekundär trägt die Akzentfamilie und würde neben dem Primär um
   dieselbe Aufmerksamkeit ringen (§10). */
.vorort__cta {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-sm);                    /* 12 */
  /* Kein margin-top: .vorort__oben trägt die 24 schon als gap.
     Beides zusammen wären 48 gewesen — der Button saß 24 px zu
     tief. */
}

.vorort__cta > .btn {
  flex: 1 0 0;
  min-width: 0;
}

/* Die zwei Standort-Angebote nebeneinander, 12 Abstand.
   align-items: stretch, damit die kürzere Karte mitwächst —
   in Figma sind beide gleich hoch.

   48 nach oben, nicht 24: der Willkommens-Block endet in Figma
   bei 649, die Angebote beginnen bei 697. Dasselbe Maß liegt
   zwischen Angeboten und Sektion (1022 → 1070) und entspricht
   .section + .section aus base.css. */
.vorort__angebote {
  display: flex;
  align-items: stretch;
  gap: var(--space-sm);                    /* 12 */
  margin-top: var(--space-2xl);            /* 48 */
}

.vorort__sektion {
  margin-top: var(--space-2xl);            /* 48 */
}

/* ------------------------------------------------------------
   11. Inhalte-Seite (Kategorie-Seite)
   ------------------------------------------------------------
   Figma-Node 13773:34864, ausgelesen am 04.09.2026.

   Kopfzeile: ← , Titel, Suchzeile mit Filter. Darunter die
   Genre-Chips, dann elf Sektionen mit Cover-Reihen.

   Der Titel in der festen Zeile ist medium text bold, nicht H3 —
   die Zeile ist Bedienoberfläche, kein Inhalt (§26.3). Outfit
   bleibt den Inhaltstiteln.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   DIE FESTE ZEILE (Lisi, 14.09.2026, nach der neuen Fassung von
   examples/scroll-verhalten-alle-screens.html, Varianten „Titel
   bleibt" und „kein aktiver Filter")
   ------------------------------------------------------------
   Aus der Demo, für Ebene 2:

     „Auf der Kategorieseite kollabiert auch der Filter. Suche und
      Filter werden zu Icons in der festen Zeile, die Chips kleben
      darunter. Die Chips sind der einzige Regler, den man beim
      Scrollen durch die Ergebnisse wirklich braucht — deshalb
      bleiben sie in voller Breite, während Suche und Filter auf
      Icons schrumpfen."

   Drei Schichten, von oben:
     · die feste Zeile   ← · Titel · Such-Zeichen · Filter-Zeichen
     · die Suchzeile     scrollt weg
     · das Chip-Band     klebt unter der festen Zeile

   KEIN LOGO, KEIN ZAHNRAD. Ebene 2 hat ihren eigenen Kopf; die
   Leiste des Gestells ist auf dieser Seite ausgeblendet.

   DIE ZEILE KLEBT AM FENSTER, nicht in einem eigenen Rahmen. Der
   Prototyp scrollt die Seite, nicht einen Kasten darin — deshalb
   `position: sticky` und nicht `fixed`: sticky bleibt Teil des
   Flusses, und darunter rutscht nichts unter sie, solange sie
   noch nicht oben angekommen ist.

   SIE BRINGT IHREN EIGENEN RAND MIT. Der Screen polstert seitlich
   mit --sektion-rand; die Zeile zieht ihn per negativem
   Außenabstand wieder ab und setzt ihn selbst als Polster. Sonst
   endete ihr Grund vor der Screenkante und die Cover schauten im
   angedockten Zustand links und rechts daran vorbei.

   POLSTER 16 / 12, WIE DIE LEISTE DES GESTELLS (Lisi,
   14.09.2026: „das padding ist zu wenig unten, gleich machen wie
   die anderen screens sich verhalten bei scroll").

   Zwischendurch stand hier 16 / 4, aus der Demo übernommen, die
   die fehlenden 8 als Abstand über die Suchzeile legt. Das ergibt
   denselben Rhythmus zum Suchfeld, macht die Zeile aber 65 statt
   73 hoch — und beim Scrollen lief der Inhalt vier Pixel unter
   den Zeichen durch. Auf der Zeitungen-Übersicht, wo keine Chips
   die Kante tragen, sah man es sofort.

   Jetzt sind alle drei festen Zeilen gleich hoch: 16 + 45 + 12.
   ------------------------------------------------------------ */
/* ZWEI ELEMENTE, EINE ZEILE. Mobil ist die Kopfzeile selbst die
   feste Zeile; ab Tablet ist es die Klammer um Kopfzeile und
   Suchzeile, damit die Suche NEBEN dem Titel steht (Figma
   13783:20561). Beide sehen gleich aus und sind hier deshalb
   einmal beschrieben.

   DIE UNBENUTZTE VERSCHWINDET VON SELBST. Mobil steht die Klammer
   auf `display: contents` und erzeugt gar keinen Kasten — Grund,
   Polster und Kleben gelten dann für sie nicht, ganz ohne sie
   einzeln zurückzunehmen. */
.inhalte-seite__kopf,
.inhalte-seite__kopfbereich {
  display: flex;
  align-items: center;
  gap: var(--space-sm);                    /* 12 */

  position: sticky;
  top: 0;
  /* AUF DERSELBEN STUFE WIE DIE LEISTE DES GESTELLS (10). Sie ist
     deren Gegenstück auf Ebene 2, und sie verhält sich beim
     Inhalte-Panel genauso: das Panel (9) und sein Scrim (8)
     legen sich über den Inhalt, nicht über die Kopfzeile.

     Hier standen zuerst 19 und 18, aus der Demo abgeschrieben.
     Dort gibt es kein Panel; hier lag die Chip-Leiste dadurch
     über der geöffneten Inhalte-Liste. Die Stufen dieses
     Prototyps sind: 8 Scrim, 9 Panel, 10 Leiste und Streifen. */
  z-index: 10;
  background-color: var(--surface-primary);

  margin-inline: calc(-1 * var(--sektion-rand));
  padding: var(--space-md) var(--sektion-rand) var(--space-sm);    /* 16 / 12 */
}

/* ------------------------------------------------------------
   AB TABLET: die Suche steht neben dem Titel
   ------------------------------------------------------------
   Gemessen an Figma 13783:20561 („top", Tablet 834). Die Zeile ist
   674 breit und 45 hoch:

     Zurück 45 · 12 · Titel (füllt) · 12 · Suchblock 361

   Die 12 zwischen Zurück und Titel bringt die Kopfzeile mit, die
   12 zwischen Titel und Suchblock die Klammer — dieselbe Zahl,
   zweimal dasselbe Gap.

   DIE KOPFZEILE IST HIER NUR NOCH DIE LINKE HÄLFTE. Sie gibt
   Kleben, Grund und Polster an die Klammer ab, sonst läge ein
   Kasten im Kasten und der Grund doppelt.

   KEINE ZEICHEN. Sie sind die eingeklappte Fassung der Suchzeile —
   und die ist hier gar nicht eingeklappt, sondern steht die ganze
   Zeit da. Im Rahmen gibt es sie entsprechend nicht.
   ------------------------------------------------------------ */
@media (min-width: 768px) {
  .inhalte-seite__kopfbereich > .inhalte-seite__kopf {
    position: static;
    z-index: auto;
    background: none;
    margin-inline: 0;
    padding: 0;
    flex: 1 0 0;
    min-width: 0;
  }

  /* 361 fest, wie im Rahmen. Die Suchleiste darin nimmt sich den
     Platz (`flex: 1 0 0` in searchbar.css), der Filter-Knopf
     behält seine Größe. */
  .inhalte-seite__kopfbereich > .inhalte-seite__suchzeile {
    flex: 0 0 361px;
  }

  .inhalte-seite__kopfbereich .inhalte-seite__ikon {
    display: none;
  }
}

/* ------------------------------------------------------------
   16 ZWISCHEN ZEILE UND CHIPS — und zwar wirklich 16
   ------------------------------------------------------------
   Es waren 28 (Lisi, 15.09.2026: „bist du sicher dass hier 16px
   gap ist? das sieht deutlich mehr aus"). Sie kamen aus zwei
   Stellen, die sich addierten: die feste Zeile bringt 12 nach
   unten mit, das Chip-Band 16 nach oben.

   Wo Chips folgen, gehört der Abstand ganz dem Band — es deckt ihn
   im angedockten Zustand zu, ein Polster der Zeile täte das nicht
   (siehe „hier scheint etwas durch" weiter unten). Die Zeile hört
   deshalb an ihrer 45er Reihe auf.

   Im Rahmen: Zeile 0–45, Chips bei y 61 (13783:20561).

   Mobil braucht die Suchzeile darunter ihre 12 dann selbst — sie
   hat sie bis hierher vom Polster der Zeile bekommen.
   ------------------------------------------------------------ */
[data-eigener-kopf]:has([data-kategorie-chips]) .inhalte-seite__kopf,
[data-eigener-kopf]:has([data-kategorie-chips]) .inhalte-seite__kopfbereich {
  padding-bottom: 0;
}

/* ------------------------------------------------------------
   DIE TRENNLINIE — nur, wo sie niemand anders trägt
   ------------------------------------------------------------
   Dieselbe Linie wie unter der Leiste des Gestells: 1 px,
   gray-800, randlos über die Breite, 120 ms linear.

   SIE GEHÖRT DER ZEILE NUR AUF SCREENS OHNE CHIPS. Auf der
   Kategorie-Seite klebt das Chip-Band darunter und trägt sie
   selbst — zwei Kanten übereinander wären eine zu viel, so nimmt
   die Demo sie dort auch heraus. Auf der Zeitungen-Übersicht gibt
   es kein Band, und dort fehlte sie (Lisi, 14.09.2026).

   Die Bedingung steht im Selektor, nicht im JS: „hat dieser
   Screen ein Chip-Band?" ist eine Frage an das Markup, und
   `:has()` kann sie stellen.
   ------------------------------------------------------------ */
[data-eigener-kopf]:not(:has([data-kategorie-chips])) .inhalte-seite__kopf::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background-color: var(--gray-800);
  opacity: 0;
  transition: opacity 120ms linear;
}

[data-eigener-kopf]:not(:has([data-kategorie-chips]))
.inhalte-seite__kopf[data-scrolled="true"]::after {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .inhalte-seite__kopf::after {
    transition: none;
  }
}

/* Die zwei Zeichen blenden mit demselben Fortschritt ein wie das
   Such-Zeichen in der Leiste des Gestells — die Werte schreibt
   prototyp.js an die Zeile. Nur Deckkraft und Größe ändern sich,
   nie die Breite: die Zeichen stehen von Anfang an im Layout,
   deshalb wandert der Titel beim Scrollen nicht.

   Die Skalierung sitzt am Zeichen, nicht am Knopf — am Knopf
   greift kein transform (components/topbar.css, OFFEN).

   BEDIENBAR ERST AB 0,6, wie überall: ein halb sichtbares Ziel,
   das schon auslöst, ist eine Falle. */
.inhalte-seite__ikon {
  opacity: var(--such-icon-p, 0);
  pointer-events: none;
  flex-shrink: 0;

  /* DER PLATZ WÄCHST MIT DER SICHTBARKEIT (15.09.2026, Lisi: „auf
     mobile wird hier der text abgeschnitten obwohl platz ist. es
     soll nur mit ... sein wenn wirklich kein platz ist").

     Vorher standen die zwei Zeichen von Anfang an in voller Größe
     im Layout und waren nur durchsichtig. Sie nahmen dem Titel
     damit 114 (2 x 45 plus 2 x 12), auch wenn nichts zu sehen war:
     „Magazine & Zeitungen" braucht 197 und bekam 182 — drei
     Buchstaben fehlten für nichts.

     Jetzt wächst der Platz mit demselben Fortschritt, der auch die
     Deckkraft steuert. Bei 0 ist die Breite 0, und der negative
     Außenabstand hebt das Gap der Zeile auf — die Zeichen kosten
     dann wirklich nichts. Bei 1 stehen sie voll da, und DANN kürzt
     der Titel, weil dann tatsächlich kein Platz mehr ist.

     Der Titel bleibt trotzdem stehen: er ist linksbündig und
     dehnbar, es wandert also nur sein rechtes Ende, nicht sein
     Anfang.

     DIE BREITE WIRD ABGELESEN, NICHT ABGESCHRIEBEN: prototyp.js
     misst sie am Zurück-Knopf daneben — derselbe .ikon-button, nur
     ohne diese Regel. Die 45 hier sind der Rückfall, falls das
     Skript nicht läuft. */
  width: calc(var(--zeichen-b, 45px) * var(--such-icon-p, 0));
  margin-inline-start: calc((var(--such-icon-p, 0) - 1) * var(--space-sm));
  overflow: hidden;
}

.inhalte-seite__ikon .ikon-button__ikon {
  transform: scale(calc(0.85 + 0.15 * var(--such-icon-p, 0)));
}

.inhalte-seite__ikon[data-bedienbar] {
  pointer-events: auto;
}

.inhalte-seite__titel {
  flex: 1 0 0;
  min-width: 0;
  font-family: var(--font-family-inter);
  font-size: var(--font-size-medium-text);
  line-height: var(--line-height-medium-text);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* DIE SUCHZEILE LÄUFT VON KANTE ZU KANTE (Lisi, 15.09.2026: „da
   ist in tablet auf einmal die suche nicht end to end").

   Hier standen 320 — das Maß des Frames im Figma-Rahmen. Auf dem
   Tablet ist die Inhaltsbreite aber 790, und die Zeile stand
   dadurch als kurzer Streifen links, während Kopfzeile, Chips und
   Gitter darüber und darunter die ganze Breite nehmen. Eine
   Suche, die schmaler ist als alles andere, sieht aus wie ein
   Rest.

   Ohne feste Breite füllt die Zeile ihren Screen, und die
   Suchleiste darin nimmt sich den Platz (`flex: 1 0 0` in
   searchbar.css); der Filter-Knopf behält seine Größe und sitzt
   am rechten Ende. Mobil ändert sich nichts — dort war die Zeile
   schon voll breit.

   Sie steht seit dem 14.09.2026 unter der festen Zeile statt
   darin, und ohne eigenen Abstand: die 12 bringt das Polster der
   Zeile mit, genau wie bei der Leiste des Gestells. */

/* Die Chip-Leiste ist seit dem 11.09.2026 eine eigene
   Komponente (components/chip-leiste.css) — sie kommt jetzt auch
   auf Entdecken vor. Hier steht nur noch, was zu DIESER Seite
   gehört: der Abstand zur Kopfzeile.

   16 unter der Kopfzeile (Figma y=61 bei 45 Kopfhöhe), minus das
   Polster, das die Leiste für Ring und Glow mitbringt — sonst
   säße sie 10 px zu tief. */
/* HIER STAND DER ABSTAND ZUR SUCHZEILE
   (margin-top: calc(16 - fokus-luft) an der Leiste selbst).

   Er sitzt seit dem 14.09.2026 am Band. Solange die Leiste im
   Fluss stand, war beides dasselbe; jetzt steckt sie in einem
   klebenden Band, und ein Abstand INNEN klebt mit — die Chips
   hingen dadurch 16 unter der festen Zeile statt bündig darunter
   (nachgemessen: 81 statt 65).

   Die Regel ist ganz weg und nicht auf 0 gesetzt: eine 0 hätte
   den negativen Außenabstand mit überschrieben, den die
   Komponente für Ring und Glow mitbringt — dann standen die
   Chips 10 zu tief (nachgemessen: 75 statt 65). */

/* ------------------------------------------------------------
   DAS CHIP-BAND — es klebt, die Leiste darin scrollt
   ------------------------------------------------------------
   Zwei Aufgaben, zwei Elemente. Die Leiste ist die unveränderte
   Komponente (chip-leiste.css) und scrollt waagerecht; das Band
   hält sich unter der festen Zeile fest und bringt den Grund
   mit.

   OHNE GRUND KEIN KLEBEN. Ein durchsichtiges Band ist im
   angedockten Zustand nicht zu unterscheiden von gar keinem —
   die Cover würden durch die Chips hindurchscrollen.

   ES HÄNGT AN DER GEMESSENEN HÖHE DER FESTEN ZEILE
   (--kategorie-kopf-h, setzt prototyp.js). Die Höhe steht
   nirgends fest; sie ergibt sich aus dem Polster und der 45er
   Reihe darin. Der Rückfallwert ist die Rechnung: 16 + 45 + 4.

   --chip-luft IST GEMESSEN, NICHT ABGESCHRIEBEN. Die Leiste
   polstert sich oben und unten um Ring und Glow (chip-leiste.css
   nennt es --fokus-luft) und zieht das Polster per negativem
   Außenabstand wieder ab. Das Band muss dieselbe Luft kennen:
   sonst deckt sein Grund nur die 45 der Chips, und Ring und Glow
   stünden auf durchscheinendem Inhalt. Dieselbe Rechnung hier
   ein zweites Mal hinzuschreiben wäre die Sorte Doppelung, die
   in diesem Prototyp schon dreimal auseinandergelaufen ist —
   prototyp.js liest den Wert deshalb an der Leiste ab.

   ZWISCHEN ZEILE UND CHIPS LIEGEN 16 (Lisi, 14.09.2026: „16 px
   zwischen chips und top"). Gerechnet wird auf die CHIPS, nicht
   auf das Band: das Band steht um seine Luft weiter oben, damit
   Ring und Glow Grund unter sich haben. Der Grund reicht dadurch
   unter die feste Zeile; die liegt eine Ebene höher und deckt
   ihn zu.

   Angedockt stehen die Chips also genauso weit unter der Zeile
   wie im Fluss unter der Suchzeile — derselbe Abstand, in beiden
   Zuständen.
   ------------------------------------------------------------ */
.inhalte-seite__chip-band {
  position: sticky;
  /* Das Band dockt BÜNDIG an der festen Zeile an. Die 16 stecken
     in seinem Polster, nicht in diesem Wert — siehe unten. */
  top: var(--kategorie-kopf-h, 65px);
  /* Unter dem Scrim (8): das Band gehört zum Inhalt der Seite und
     soll mit abgedunkelt werden, wenn die Inhalte-Liste darüber
     liegt. Über dem übrigen Inhalt liegt es ohnehin — der trägt
     keine Stufe. */
  z-index: 7;
  background-color: var(--surface-primary);

  /* Bis an beide Screenkanten, wie die feste Zeile darüber. */
  margin-inline: calc(-1 * var(--sektion-rand));
  padding-inline: var(--sektion-rand);

  /* DIE 16 SIND POLSTER DES BANDES, KEIN ABSTAND DAVOR
     (Lisi, 14.09.2026: „hier scheint etwas durch").

     Zuerst standen sie als Außenabstand über dem Band und im
     `top`. Das stimmte auf den Punkt — und ließ zwischen der
     festen Zeile und dem Band einen Streifen frei, durch den
     beim Scrollen die Cover liefen. Ein Abstand ist nichts; er
     deckt nichts zu.

     Jetzt gehören die 16 dem Band: sein Grund beginnt an der
     Unterkante der festen Zeile, die Chips stehen 16 tiefer.
     Sichtbar ist dasselbe, nur ohne Lücke.

     UNTEN BLEIBT ES BEI DER LUFT der Leiste. Sie polstert sich um
     Ring und Glow und zieht das Polster per negativem
     Außenabstand wieder ab (chip-leiste.css); das Band macht
     denselben Kniff, damit sein Grund dahinter liegt, ohne die
     Außenmaße zu ändern.

     Der Außenabstand nach oben ist 0: im Fluss stehen die Chips
     durch das Polster schon 16 unter der Suchzeile. Derselbe
     Abstand in beiden Zuständen, aus derselben Zahl. */
  padding-top: var(--space-md);            /* 16 */
  padding-bottom: var(--chip-luft, 10px);
  margin-bottom: calc(-1 * var(--chip-luft, 10px));
}

/* DIE TRENNKANTE TRÄGT DAS BAND, NICHT DIE ZEILE. Die Demo nimmt
   die Linie unter der festen Zeile heraus, wo Chips folgen: zwei
   Kanten übereinander wären eine zu viel. Sichtbar wird sie
   genau dann, wenn das Band angedockt ist — steht es noch im
   Fluss, gibt es nichts zu trennen. */
.inhalte-seite__chip-band::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background-color: var(--gray-800);
  opacity: 0;
  transition: opacity 120ms linear;
}

.inhalte-seite__chip-band[data-angedockt="true"]::after {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .inhalte-seite__chip-band::after {
    transition: none;
  }
}

/* ------------------------------------------------------------
   Das Cover-Gitter
   ------------------------------------------------------------
   Eine Kategorie zeigt nicht drei Cover mit dem Hinweis „hier
   geht es weiter", sondern alles auf einmal. Deshalb ein Gitter
   und keine scrollende Reihe.

   ES FÜLLT DIE BREITE RESTLOS. auto-fill mit einer Mindestbreite
   und 1fr heißt: der Browser nimmt so viele Spalten, wie ganz
   hineinpassen, und verteilt den Rest auf sie — es bleibt nie
   Platz rechts übrig, und die Cover wachsen mit dem Fenster.

   DIE MINDESTBREITE WECHSELT MIT DEM BREAKPOINT, nicht die Zahl
   der Spalten. Eine feste Zahl wäre falsch — auf einem breiteren
   Telefon sollen mehr Spalten entstehen dürfen (Lisi,
   11.09.2026). Was dabei herauskommt:

     390 Gerät (350 Inhalt)   2 Cover à 169
     514 Gerät und breiter    3 Cover
     768 Tablet (609 neben
         dem Streifen)        4 Cover à 143

   BIS 400 SIND ES ZWEI. Mit einer Mindestbreite von 100 waren es
   dort drei à 109 — „hier wirken die cover aktuell zu klein"
   (Lisi, 11.09.2026). 150 ist die Schwelle, ab der ein Telefon
   erst bei rund 514 auf drei geht.

   ------------------------------------------------------------
   DIE KOMPONENTE STAND HIER EINMAL KOMPLETT DANEBEN

   Bis zum 14.09.2026 wiederholte dieser Abschnitt, was seit dem
   11.09. in components/cover-gitter.css steht: Spalten,
   Abstände, `width: 100%` am Cover und die zweizeilige Klemme am
   Titel — Wort für Wort dasselbe.

   Und schlimmer als eine Dopplung: die Komponente war gar nicht
   eingebunden. Das Gitter im Prototyp lief die ganze Zeit auf
   der Kopie, und was Cowork an der Komponente änderte, kam hier
   nie an. Aufgefallen ist es erst, als ich nachsehen wollte,
   welche der beiden gewinnt — es gab keine zwei.

   Jetzt ist die Komponente in index.html verlinkt, und hier
   steht nur noch, was wirklich diesem Screen gehört: der Abstand
   nach oben.
   ------------------------------------------------------------ */

.cover-gitter {
  margin-top: var(--space-lg);             /* 24, wie die Sektionen */
}

/* ------------------------------------------------------------
   Chips filtern die Seite
   ------------------------------------------------------------
   „Alle" zeigt alles. Ein Genre zeigt nur, was dazugehört —
   und bei Lifestyle & People statt der Abschnitte das Gitter.
   Welcher Abschnitt zu welchem Chip gehört, steht als data-genre
   im Markup; das Aus- und Einblenden macht prototyp.js.

   [hidden] BRAUCHT HIER NACHDRUCK: .sektion ist display: flex,
   und das schlägt das display: none des Browsers. Ohne diese
   Regel bliebe ein versteckter Abschnitt stehen (AGENTS.md §17).
   ------------------------------------------------------------ */

.sektion[hidden],
.cover-gitter[hidden] {
  display: none;
}

/* PLATZHALTER-COVER: eine Karte ohne Bild und ohne Titel.
   Steht in den Kategorien, die es gibt, für die aber noch keine
   Titel ausgesucht sind (Lisi, 11.09.2026). Die Fläche und der
   Strich kommen aus .cover__bild — hier fehlt nur das Bild, es
   ist also kein eigener Zustand, sondern dieselbe Karte mit
   leerem Inhalt.

   Kein Zeigefinger und kein Ziel: die Karte tut nichts, und ein
   Cursor, der Klickbarkeit behauptet, wäre gelogen. */
.cover--platzhalter {
  cursor: default;
}

.inhalte-seite__sektionen {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);                   /* 48 */
  margin-top: var(--space-lg);             /* 24 */
}

/* ------------------------------------------------------------
   11b. Zeitungen — die Übersicht unter der Kategorie
   ------------------------------------------------------------
   Figma „Magazine und Zeitungen / Top Zeitungen" (7863:10796,
   393 x 1228), ausgelesen am 14.09.2026.

   Der Screen borgt sich den Kopf der Kategorie-Seite (dieselben
   Klassen, dieselbe Scroll-Mechanik) und ersetzt Chips und
   Sektionen durch ein einziges Gitter.

   DAS GITTER IST DIE KOMPONENTE, in der Fassung
   `cover-gitter--zeitung`: drei Spalten mobil, ab 768 zählt der
   Browser mit der Untergrenze 110. Zeitungscover sind schmaler
   als Magazincover (in der Reihe 100 statt 156, cover.css),
   deshalb passen mehr nebeneinander.

   Die Werte standen bis zum 14.09.2026 hier, samt der Rechnung
   zum Figma-Rahmen — beides ist jetzt in
   components/cover-gitter.css, und dort gehört es hin. Hier
   bleibt nur der Abstand nach oben.
   ------------------------------------------------------------ */

/* Das Gitter beginnt 16 unter der Suchzeile — derselbe Abstand
   wie zu den Chips auf der Kategorie-Seite (Figma: Suchzeile
   endet bei 130, Gitter beginnt bei 154, gemessen im Rahmen
   7863:10796 relativ zum Screen: 106 + 24 und 154). */
.zeitungen-seite__gitter {
  margin-top: var(--space-md);             /* 16 */
}

/* ------------------------------------------------------------
   12. Lage des Inhalte-Overlays
   ------------------------------------------------------------
   Das Panel sitzt direkt rechts am Navigationsstreifen, und der
   Scrim beginnt an derselben Kante. Beide liegen außerhalb von
   .app und rechnen deshalb aus --buehne-links.
   ------------------------------------------------------------ */

.inhalte-overlay,
.scrim--inhalte {
  --rail-rechts: calc(var(--buehne-links) + var(--nav-rail-breite));
}

/* ------------------------------------------------------------
   DAS PANEL KOMMT HINTER DEM STREIFEN HERVOR
   ------------------------------------------------------------
   Es liegt UNTER dem Navigationsstreifen (z-index 9 gegen 10),
   nicht darüber. Beim Hereinfahren schiebt es sich also hinter
   ihm hervor, statt über ihn hinwegzuwischen — der Streifen
   bleibt die ganze Zeit stehen und deckt den Weg ab.

   Der Scrim bleibt darunter (8): er dunkelt den Inhalt ab, nicht
   das Panel.

   Vorher lag das Panel bei 21 und der Scrim bei 20 — es kam
   sichtbar von der Screenkante über den Streifen gefahren.
   ------------------------------------------------------------ */

.inhalte-overlay {
  z-index: 9;
}

.scrim--inhalte {
  z-index: 8;
}

/* Scrim und Panel müssen GLEICH LANG laufen, sonst liest man
   zwei Ereignisse statt eines (motion.css, Abschnitt Scrim).
   dialog.css gibt dem Scrim die Dialog-Dauer (250 ms), das Panel
   fährt aber wie eine Schublade (500 ms). Hier wird der Scrim
   auf dieselbe Dauer und dieselbe Kurve gezogen. */
.scrim--inhalte {
  transition:
    opacity calc(var(--motion-sheet) * var(--motion-scale)) var(--motion-ease-drawer);
}

/* Ein Panel mit eigenem Scrollbereich, das bewegt wird, muss dem
   Browser angekündigt werden — sonst legt er die Ebene erst beim
   ersten Frame an, und der Anfang der Bewegung ruckelt. */
.inhalte-overlay {
  will-change: transform;
}

/* Rechts endet der Scrim an der Bühnenkante, nicht am Fensterrand —
   sonst dunkelt er bei breiten Fenstern die leere Fläche daneben mit
   ab, und die gehört nicht zum Screen. */
.scrim--inhalte {
  right: var(--buehne-links);
}

/* ------------------------------------------------------------
   13. Meine Titel
   ------------------------------------------------------------
   Figma-Node 13856:15446, ausgelesen am 04.09.2026.

   Kopfzeile, Seitentitel, dann zwei Sektionen: „Fortsetzen" als
   Raster aus zwei Spalten, „Deine Favoriten" als Raster aus
   fünf.
   ------------------------------------------------------------ */

/* 48 unter der Kopfzeile (Figma: Kopf endet bei 69, Titel bei
   117). Der Titel ist H1 wie auf den anderen Screens.

   IN FIGMA STEHT HIER 29 px — das ist der MOBILE H1-Wert auf
   einem Tablet-Frame, an einer losgelösten Textebene ohne
   benannten Stil. „Herzlich willkommen" auf Vor Ort und
   „Anmelden" tragen beide 34, also den Tablet-Wert. Deshalb hier
   H1 aus dem Token. In Figma nachzuziehen. */
.meinetitel__titel {
  margin-top: var(--space-2xl);            /* 48 */
  font-family: var(--font-family-display);
  font-size: var(--font-size-h1);
  line-height: var(--line-height-h1);
  font-weight: var(--font-weight-extrabold);
  color: var(--text-primary);
}

.meinetitel__sektionen {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);                   /* 48 zwischen Sektionen */

  /* 24 UNTER DEM SEITENTITEL, NICHT 48 (Lisi, 14.09.2026:
     „abstand zu ‚meine titel' und ‚fortsetzen' ist 24px").

     Nachgemessen im Rahmen „Meine Titel Mobile" (13994:35338):
     Seitentitel bei y 16, 32 hoch; Sektionen bei y 72. Also 24.
     Die 48 waren der Abstand ZWISCHEN Sektionen, hier
     versehentlich auch nach oben gesetzt. */
  margin-top: var(--space-lg);             /* 24 */
}

/* Der Sektions-Kopf hat hier keinen Link „Alle" — nur Titel und
   Sub-Info. Das ist Klasse 2 aus §8. Die Kopfhöhe folgt deshalb
   dem Text, nicht dem Link Button. */
.meinetitel__sektion .sektion__kopf {
  min-height: 0;
}

/* Fortsetzen: zwei Spalten, 12 waagerecht, 16 senkrecht.
   Gemessen: Karten 331 breit bei 674 Gesamtbreite (331·2+12),
   zweite Reihe bei 125,3 (109,3 + 16). */
.meinetitel__fortsetzen {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--space-sm);             /* 12 */
  row-gap: var(--space-md);                /* 16 */
}

/* Favoriten: fünf Spalten, dieselben Abstände.
   Gemessen: 5 x 125,02 + 4 x 12 = 673,1 bei 674. */
.meinetitel__favoriten {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: var(--space-sm);             /* 12 */
  row-gap: var(--space-md);                /* 16 */
}

/* ------------------------------------------------------------
   MOBIL SIND ES EINE UND DREI SPALTEN
   ------------------------------------------------------------
   Figma „Meine Titel Mobile" 13994:35338, 393 breit, ausgelesen
   am 14.09.2026 (Lisi: „mobile sollten die weiterlesen cards
   sein wie hier in figma. volle breite end to end und favoriten
   grid mit 3").

   NACHGEMESSEN IM RAHMEN, Inhaltsbreite 353:
     Fortsetzen  drei Karten 353 breit, y 67 / 208 / 349
                 → eine Spalte, Abstand 16
     Favoriten   je 109,67 breit, x 0 / 121,67 / 243,33
                 → drei Spalten, Abstand 12, Reihenabstand 16
                 (Reihen bei y 0 / 222,16 / 444,32)

   Vorher standen hier zwei bzw. vier Spalten — das war die
   Tablet-Regel, die mangels eigener mobiler Regel mit
   durchgeschlagen ist. Die Karte war dadurch halb so breit wie
   im Rahmen, und von den Favoriten passten vier statt drei
   nebeneinander.

   HIER STAND FRÜHER `@media (max-width: 749px)` mit vier Spalten
   („sonst fallen die Cover unter 100 px"). Die Regel ist weg:
   sie hat nur Breiten getroffen, die heute mobil sind, und dort
   gilt jetzt die gemessene Drei. Ab 768 bleibt es bei fünf.
   ------------------------------------------------------------ */
/* MOBIL GIBT ES DIE KLAMMER NICHT. `display: contents` heißt: kein
   eigener Kasten, die beiden Kinder stehen direkt im Screen — die
   Kopfzeile klebt wieder selbst, die Suchzeile steht darunter im
   Fluss und scrollt weg. Genau wie vor der Klammer. */
@media (max-width: 767px) {
  .inhalte-seite__kopfbereich {
    display: contents;
  }

  /* Die 12 unter der Zeile, die dort jetzt fehlen (siehe oben). */
  .inhalte-seite__suchzeile {
    margin-top: var(--space-sm);           /* 12 */
  }
}

@media (max-width: 767px) {
  .meinetitel__fortsetzen {
    grid-template-columns: minmax(0, 1fr);
  }

  /* DIE HÖHE STAND HIER EINEN NACHMITTAG LANG. Ich hatte aus
     den Instanz-Rahmen in „Meine Titel Mobile" 125 gelesen und
     das an Cowork gemeldet; die Komponente selbst ist 280 x 109
     (Lisi, 14.09.2026). fortsetzen-karte.css steht wieder auf
     einem Wert ohne Media Query, also ist hier nichts mehr zu
     korrigieren. Ersatzlos weg.

     Was bleibt, ist die Breite — und die ist genau das, was
     dieser Block regelt: mobil eine Spalte über die ganze
     Breite. */

  .meinetitel__favoriten {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------
   14. Entdecken
   ------------------------------------------------------------
   Figma-Node 13863:60037, ausgelesen am 04.09.2026.
   4538 px hoch, dreizehn Sektionen.
   ------------------------------------------------------------ */

/* Die Abkürzungen stehen 16 unter der Kopfzeile (Figma y=61 bei
   45 Kopfhöhe).

   `ul` VOR DER KLASSE, sonst greift der Abstand nicht: base.css
   setzt `ul[role="list"] { margin: 0; padding: 0 }`, und Element
   plus Attribut ist spezifischer als eine Klasse allein. Das ist
   jetzt die dritte Stelle, an der diese Regel etwas verschluckt
   hat — deshalb steht sie auch im README unter den offenen
   Punkten am System. */
ul.entdecken__shortcuts {
  margin-top: var(--space-md);             /* 16 */
}

/* 48 zwischen allen Sektionen — gemessen: Frame 325 endet bei
   189, Frame 320 beginnt bei 237. */
.entdecken__sektionen {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);                   /* 48 */
  margin-top: var(--space-2xl);            /* 48 */
}

/* Der große Slider und die zwei Karten darunter sind EIN Block.
   In Figma ist das Frame 320 (674 x 487): Slider 253, 16
   Abstand, dann die Doppelreihe 218. Die 48 zwischen den
   Sektionen gelten außen herum, nicht zwischen den beiden. */
.entdecken__slider-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);                    /* 16 */
}

/* Zwei gleich breite Karten mit 12 Abstand. Gemessen: je 331 bei
   674 Gesamtbreite. Kein festes Maß, sondern zwei gleiche
   Anteile — der Prototyp läuft von 750 bis 950 und die Karten
   müssen mitgehen. */
.entdecken__doppel {
  display: flex;
  gap: var(--space-sm);                    /* 12 */
}

.entdecken__doppel > * {
  flex: 1 0 0;
  min-width: 0;
}

/* Eine Reihe, die waagerecht scrollt und über den Rand läuft —
   dieselbe Mechanik wie .sektion__reihe, nur für Karten statt
   Cover. Der Fokus-Ring braucht dieselbe Luft. */
.entdecken__reihe {
  --fokus-luft: calc(var(--focus-ring-offset) + var(--focus-ring-width));

  display: flex;
  align-items: stretch;
  gap: var(--space-sm);                    /* 12 */

  overflow-x: auto;
  overscroll-behavior-x: contain;
  /* NACH BEIDEN SEITEN, NICHT NUR NACH RECHTS (15.09.2026, Lisi:
     „der horizontal scroll sollte wenn man scrollt bis ans ende
     gehen, nicht abgeschnitten. bis an an die kante").

     Nur rechts zu überlaufen reicht nicht: beim Scrollen wurden
     die Kacheln schon am Screenrand-Abstand abgeschnitten, also
     24 (bzw. mobil 20) VOR der Kante. Dazwischen blieb ein toter
     Streifen, in dem nichts mehr zu sehen war — im Rahmen laufen
     sie bis an die Kante heraus.

     Das Polster hält den ersten Eintrag trotzdem am Screenrand,
     solange nicht gescrollt ist. Sichtbar ändert sich also nur
     der ABGANG. */
  margin-inline: calc(-1 * var(--sektion-rand, var(--space-lg)));
  padding-inline: var(--sektion-rand, var(--space-lg));
  padding-block: var(--fokus-luft);
  margin-block: calc(-1 * var(--fokus-luft));
  scrollbar-width: none;
}

.entdecken__reihe::-webkit-scrollbar {
  display: none;
}

/* Die Zeitungs-Reihen haben 16 Abstand statt 12 (Figma: Karten
   bei 0, 116, 232 → 100 + 16). */
.entdecken__reihe--zeitungen {
  gap: var(--space-md);                    /* 16 */
}

/* „Bereit für den Sommer": über dem Titel steht ein Status-Label
   statt einer Sub-Info. Es ist die Auszeichnung eines Anlasses,
   kein Zustand des Nutzers — deshalb ein Label und kein Chip. */
.entdecken__anlass {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xs);                    /* 8 */
  flex: 1 0 0;
  min-width: 0;
}

/* „Aktuelles aus aller Welt": zwei Spalten, 12 Abstand. */
/* Raster und Fläche stehen seit dem 10.09.2026 in
   components/newsfeed-karte.css als .newsfeed-gruppe — der
   Abschnitt ist in Figma eine Karte, keine losen Zeilen. Hier
   bleibt nichts übrig; die Klasse steht im Markup. */

/* „Meist gelesen" endet mit einem einzelnen Button, mittig.
   Das ist die Ausnahme zu §13.5 (einzelner Button = Full-Width):
   die Regel gilt für Aktions-Gruppen in Dialog, Sheet und
   Fußzeile. Hier lädt der Button weitere Zeilen einer Liste
   nach — er gehört zur Liste, nicht zum Screen. So steht er in
   Figma: 115 breit, zentriert. */
.entdecken__mehr {
  display: flex;
  justify-content: center;
  margin-top: var(--space-md);             /* 16 */
}


/* ------------------------------------------------------------
   15. QR-Scanner
   ------------------------------------------------------------
   Figma-Node 13880:15185 (Sucher) und 13880:15312 (Feld aktiv),
   ausgelesen am 04.09.2026.

   Oben der Sucher über die volle Breite, unten eine Karte mit
   der manuellen Eingabe. Der Screen gehört zu keinem Tab — kein
   Navigationsstreifen.

   ✕ OBEN LINKS, KEIN ←. Die Navigation ist verdeckt, also ✕
   (§19.1); es ist ein Voll-Screen und keine Fläche über dem
   Inhalt, also links (§19.2). Genau der Fall, den §19.2 mit der
   Suche beschreibt: „Ein Screen kann modal sein und trotzdem
   Voll-Screen: dann ✕, und zwar links."

   DIE TASTATUR IST DIE DES BETRIEBSSYSTEMS. Der zweite
   Figma-Frame zeichnet eine Tastatur, um zu zeigen, wie sich das
   Feld verhält — die wird hier NICHT nachgebaut. Ein echtes
   <input> öffnet auf dem Tablet die Systemtastatur, und die
   Karte wandert nach oben, weil `interactive-widget=
   resizes-content` im viewport-Meta den sichtbaren Bereich
   verkleinert. Keine nachgebaute Tastatur, keine Rechnerei im JS.
   ------------------------------------------------------------ */

.qr {
  justify-content: space-between;
  background-color: var(--surface-primary);
  overflow: hidden;
}

/* Im Prototyp gibt es kein Kamerabild — das kann HTML nicht
   zeigen, und ein erfundenes Bild wäre irreführend. Die Fläche
   bleibt deshalb der Screen-Grund. */
.qr__scrim {
  position: absolute;
  inset: 0;
  background-color: var(--surface-primary);
}

/* 24 rundum, unten 20 (--layout-screen-margin), 80 zwischen
   Knopfreihe und Sucher. So gemessen. */
/* ------------------------------------------------------------
   Suche — zwei Zustände
   ------------------------------------------------------------
   Figma „Screens: App und Web": Search / Suche – Start und
   Search / Suche – Kategorie gewählt, Tablet 834. Maße aus dem
   Screenshot von Lisi abgelesen, am 05.09.2026 — die Frames
   waren nicht ausgewählt. Nachzuziehen.

   Die Kopfzeile bleibt stehen, darunter tauscht der Inhalt. Beim
   Wählen einer Kategorie soll die Suche nicht wegspringen; man
   bleibt in derselben Suche und schränkt sie ein.

   DER INHALT SCROLLT, DIE KOPFZEILE NICHT. Mit der
   Systemtastatur bleibt sonst nichts von den Vorschlägen übrig —
   und das Feld, in das getippt wird, muss immer zu sehen sein.
   ------------------------------------------------------------ */

.suche {
  background-color: var(--surface-primary);
  padding-inline: var(--space-lg);         /* 24 */
}

/* OBEN 48, UNTEN 24 (Tablet; mobil 36/24). Am 09.09.2026 an
   allen vier Rahmen nachgemessen — vorher standen hier 24/24.

   DIE 24 NACH UNTEN SIND KEIN BLOCKABSTAND. Kopfzeile und erster
   Block stehen in Figma in EINEM Rahmen (Frame 329 / 330 / 328 /
   331) und damit näher beieinander als die Blöcke untereinander,
   die 48 tragen. Die Suchleiste und das, was direkt darunter
   angeboten wird, gehören zusammen. */
.suche__kopf {
  display: flex;
  align-items: center;
  gap: var(--space-sm);                    /* 12 */
  flex-shrink: 0;
  padding-block: var(--space-2xl) var(--space-lg);   /* 48 / 24 */
}

/* Das Feld nimmt, was Knopf und Filter übrig lassen. */
.suche__kopf .suchleiste {
  flex: 1 0 0;
  min-width: 0;
}

/* MIT KATEGORIE STEHT EIN CHIP UNTER DER SUCHLEISTE. Er sitzt
   16 unter der Leiste (der Kopf gibt seine 24 dafür ab, siehe
   unten) und 24 über dem ersten Block — also genau dort, wo
   sonst die Kopfzeile endet. */
/* Seit dem 11.09.2026 können hier ZWEI Chips stehen: die
   Kategorie und, wenn die Seite gefiltert war, die
   Unterkategorie. Sie stehen nebeneinander und brechen um, wenn
   die Zeile nicht reicht — abschneiden wäre hier falsch, denn
   der zweite Chip trägt seinen eigenen Ausgang. */
.suche__kontext {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);                    /* 8 (§7) */
  flex-shrink: 0;
  padding-bottom: var(--space-lg);         /* 24 */
}

.suche[data-suche="kategorie"] .suche__kopf {
  padding-bottom: var(--space-md);         /* 16 */
}

.suche__inhalt {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);                   /* 48 zwischen den Blöcken */
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  padding-bottom: var(--layout-screen-margin);
}

.suche__block {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);                    /* 36 Titel → erste Zeile */
}

/* DIE ABKÜRZUNGEN UND DIE CHIPS STEHEN NÄHER AM TITEL als die
   Listen: 16 statt 36. Über :has, weil der Unterschied am INHALT
   des Blocks hängt und nicht an einer eigenen Klasse —
   dieselbe Technik wie in filter-option-row.css. */
.suche__block:has(> .suche__kategorien),
.suche__block:has(> .suche__chips) {
  gap: var(--space-md);                    /* 16 */
}

/* DIE BLOCKTITEL SIND H3, NICHT „title text" (nachgemessen am
   09.09.2026 an 2143:21558 und 13970:16666).

   Hier stand Inter 14 / 21 mit 1 % Laufweite. In Figma ist es
   der Stil H3: family/display (Outfit), Bold, 19 / 22,8, keine
   Laufweite. Das erklärt auch die 2 Pixel, die ich als
   „Token stimmt vielleicht nicht" gemeldet hatte — die Titel
   sind in Figma 23 hoch, und 22,8 rundet auf 23. Es war kein
   falscher Wert, sondern der falsche Stil.

   HIER STEHT DAS TOKEN. --font-size-h3 ist mobil 19 und auf dem
   Tablet 22 (§5), und genau so lösen die Rahmen es auch auf —
   an den Variablen nachgesehen am 09.09.2026. Der generierte
   Code schreibt zwar var(--size/H3, 19px), aber die 19 sind dort
   nur der Standardwert der Variablen, nicht der aufgelöste. */
.suche__titel {
  margin: 0;
  font-family: var(--font-family-display);
  font-size: var(--font-size-h3);
  line-height: var(--line-height-h3);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
}

/* Die Kategorien sind dieselben Abkürzungen wie auf Entdecken —
   dieselbe Komponente, nur ohne den Überlauf nach rechts: mit
   dreien sind es 241 von 353, sie passen.

   IM WLAN-ZUGANG SIND ES SECHS, und dann passen sie nicht mehr:
   6 x 75 + 5 x 8 = 490. Dort gilt der Überlauf der Komponente
   wieder, die Reihe scrollt also wie auf Entdecken. Deshalb
   hängt diese Ausnahme am Zustand und nicht an der Klasse. */
:root:not([data-zugang="wlan"]):not([data-zugang="qr"]) ul.suche__kategorien {
  overflow-x: visible;
  margin-right: 0;
  padding-right: 0;
}

/* Die Vorschlags-Chips laufen um, sie scrollen nicht: es sind
   wenige, und eine zweite Zeile liest sich besser als eine
   Reihe, die rechts verschwindet. */
ul.suche__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);                    /* 8 */
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ------------------------------------------------------------
   Intro — drei Folien
   ------------------------------------------------------------
   Figma „Screens: App und Web": intro 1–3, Tablet 834.

   Aufteilung aus Figma: Kopf 73, Inhalt 828, Fuß 211. Der Rahmen
   steht, nur die Mitte tauscht — sonst sprängen ✕, Punkte und
   Knopf bei jedem Schritt neu herein.

   DER INHALT IST DER ELASTISCHE TEIL. Kopf und Fuß sind so hoch,
   wie ihr Inhalt es verlangt; was übrig bleibt, geht an die
   Illustration. Auf einem kürzeren Fenster schrumpft also das
   Bild und nicht der Text.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     73     Kopfhöhe (16 Polster + 45 Knopf + 12).
     828    Inhalt.
     211    Fuß (24 + 7 Punkte + 12 + 75 Knopf + 12 + 45 Link + 36).
     96,6   Kreis um ein Merkmal auf Folie 3.
     36     Abstand zwischen den Merkmalen.
   ------------------------------------------------------------ */

/* WAAGERECHT WISCHEN GEHÖRT DEM INTRO, NICHT DEM BROWSER.
   Ohne diese Zeile deutet der Browser einen waagerechten Zug als
   Scroll- oder Zurück-Geste, bricht den Zeiger ab, und die Geste
   kommt nur manchmal an (Lisi am iPhone 14, 11.09.2026). pan-y
   lässt das senkrechte Scrollen unberührt.

   Dasselbe gilt für den Hero-Slider; er trägt es dort selbst. */
.intro {
  touch-action: pan-y;
}

.intro {
  /* DER GRUND IST DER DER ILLUSTRATION — und der ist
     surface-primary. Am 05.09.2026 stand hier #0A1329, von Hand
     aus einer Vorschau geschätzt; das war falsch und erzeugte
     genau die Kante, die es vermeiden sollte.

     Aus den drei Bilddateien ausgelesen (07.09.2026, alle drei
     Ecken, alle drei Bilder): rgb(18, 26, 45) = #121A2D. Das ist
     surface-primary, also derselbe Grund wie im Figma-Frame.
     Damit gibt es zwischen Bild und Screen nichts mehr zu sehen.

     Der Verweis bleibt als eigene Variable stehen: kommen neue
     Illustrationen mit anderem Grund, wird nur hier gedreht. */
  --intro-grund: var(--surface-primary);
  background-color: var(--intro-grund);

  /* DER SCREEN IST GENAU SO HOCH WIE DAS FENSTER, nicht
     mindestens. .screen--voll bringt nur min-height: 100vh mit —
     damit WÄCHST der Intro-Screen, wenn die Illustration nicht
     hineinpasst, statt sie schrumpfen zu lassen. Auf einem 830
     hohen Fenster war der Screen 1241 hoch und der Knopf lag
     unter der Kante.

     Der Kopf sagt weiter oben, die Illustration sei der
     elastische Teil. Ohne diese Zeile stimmte das nicht.
     Nachgezogen am 07.09.2026.

     svh statt vh am 14.09.2026: `100vh` rechnet auf dem Telefon
     mit eingefahrenen Browserleisten und ist damit höher als das
     Sichtbare — unten fiel weg, was die Leisten hoch sind. Es
     ist derselbe Fehler, den Lisi am Onboarding-Knopf gesehen
     hat; hier hat er die „Los geht's"-Zeile getroffen. Die
     vh-Zeile bleibt als Rückfall. */
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}

.intro__kopf {
  flex-shrink: 0;
  padding: var(--space-md) var(--space-lg) 12px;   /* 16 / 24 / 12 */
  /* Über der Kulisse: die beginnt auf Folie 3 schon bei y 30 und
     läge sonst über dem ✕. */
  position: relative;
  z-index: 1;
}

.intro__inhalt {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  padding-inline: var(--space-lg);         /* 24 */
  /* Bezug für die Kulisse auf Folie 3: sie soll sich an der
     ELASTISCHEN MITTE messen, nicht am ganzen Screen — nur so
     weiß sie, wie viel Platz zwischen Kopf und Fuß übrig ist.
     Siehe .intro__kulisse. */
  position: relative;
}

.intro__folie {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  min-height: 0;
  width: 100%;
}

.intro__texte {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);                    /* 16 — gemessen: Titel 38, Unterzeile bei 54 */
  text-align: center;
  flex-shrink: 0;
  padding-block: var(--space-md);          /* 16 */
}

/* H1, nicht H2. Gemessen: die Textebene ist 38 hoch, und H1 auf
   dem Tablet ist 34 / 37,4. Der Titel bricht damit auf zwei
   Zeilen um — so ist es in Figma. */
.intro__titel {
  margin: 0;
  font-family: var(--font-family-display);
  font-size: var(--font-size-h1);
  line-height: var(--line-height-h1);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
}

.intro__unterzeile {
  margin: 0;
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  font-weight: var(--font-weight-regular);
  color: var(--text-description);
}

/* Die Illustration bekommt, was übrig bleibt, und wird darin
   eingepasst — nie beschnitten. */
/* Das Bild läuft bis an die Screen-Kanten, nicht bis an das
   Polster des Inhalts: mit seitlichem Rand stünde links und
   rechts ein Streifen in einer anderen Dunkelheit.

   DIE OBERKANTE WIRD AUSGEBLENDET, NICHT ABGESCHNITTEN. In Figma
   läuft die Illustration nach oben in den Grund aus; mein
   Beschnitt setzt mitten hinein und ergäbe eine harte Kante
   (Lisi, 05.09.2026: „hier ist es gradient, im Prototyp
   schneidet es hart"). Eine Maske über die obersten 18 %
   übernimmt den Verlauf — sie blendet das Bild aus, nicht den
   Grund, deshalb passt es unabhängig davon, wo beschnitten
   wurde. */
.intro__bild {
  flex: 1;
  min-height: 0;
  /* max-width: none, sonst greift die Regel aus base.css
     (img { max-width: 100% }) und kappt die Breite wieder auf das
     Polster — das Bild bliebe 786 statt 834 breit und die Kante
     wäre zurück. */
  width: calc(100% + 2 * var(--space-lg));
  max-width: none;
  margin-inline: calc(-1 * var(--space-lg));
  /* CONTAIN, NICHT COVER (geändert 14.09.2026, Lisi: „mobile
     sieht besser aus aber tablet schneidet nun den kopf an").

     Hier stand cover, mit der Begründung, contain lasse links und
     rechts einen Streifen Grund stehen — eine harte Kante dort, wo
     in Figma keine ist. Das stimmt; nur schneidet cover dafür oben
     ab, und dort steht der Kopf der Figur. Ein schmaler Streifen
     Grund fällt kaum auf, ein angeschnittener Kopf sofort.

     Damit verhält sich die Zeichnung auf dem Tablet wie die auf
     dem Telefon: sie wird kleiner, statt beschnitten zu werden.

     Unten verankert, weil die Figur auf dem Boden sitzt — bleibt
     Höhe übrig, bleibt sie oben. */
  object-fit: contain;
  object-position: center bottom;

  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 18%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 18%);
}

/* Auf dem Tablet bleibt die flache Illustration; die mobile
   Zeichnung ist eine andere und wird erst unter 768 sichtbar
   (siehe „MOBIL — Intro"). */
.intro__bild-mobil {
  display: none;
}

/* ------------------------------------------------------------
   Folie 2: die zwei Zugangswege
   ------------------------------------------------------------ */

.intro__wege {
  display: flex;
  gap: var(--space-sm);                    /* 12 */
  width: 100%;
  flex-shrink: 0;
}

.intro__weg {
  display: flex;
  align-items: center;
  gap: var(--space-sm);                    /* 12 */
  flex: 1 0 0;
  min-width: 0;

  padding: var(--space-sm);                /* 12 */
  border-radius: var(--radius-md);
  background-color: var(--surface-card);
  /* Innerer Schatten statt border (AGENTS.md §8a). */
  box-shadow: inset 0 0 0 var(--outline-default) var(--label-outline);
}

.intro__weg-ikon {
  display: block;
  overflow: visible;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  color: var(--text-accent);
}

.intro__weg-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.intro__weg-titel {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-title-text);
  line-height: var(--line-height-title-text);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--letter-spacing-small-text-bold);
  color: var(--text-primary);
}

.intro__weg-erklaerung {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-extra-small-text);
  line-height: var(--line-height-extra-small-text);
  font-weight: var(--font-weight-regular);
  letter-spacing: var(--letter-spacing-small-text-bold);
  color: var(--text-description);
}

/* Der dritte Weg steht nur als Zeile da, nicht als Karte: er ist
   für Betreiber und nicht für die Wartenden, an die sich das
   Intro richtet. */
.intro__nebenweg {
  margin: 0;
  flex-shrink: 0;
  padding-block: var(--space-md);          /* 16 */
  font-family: var(--font-family-inter);
  font-size: var(--font-size-extra-small-text);
  line-height: var(--line-height-extra-small-text);
  font-weight: var(--font-weight-regular);
  letter-spacing: var(--letter-spacing-small-text-bold);
  color: var(--text-description);
  text-align: center;
}

/* ------------------------------------------------------------
   Folie 3: Kulisse und drei Merkmale
   ------------------------------------------------------------
   Gemessen an Figma 13964:17243 am 05.09.2026:

     Kulisse    834 x 692,5, beginnt bei y 30 — also schon über
                der Kopfzeile
     Textblock  600 breit, mittig, 48 Polster innen, 12 Abstand
     Titel      45 / 1,1, Outfit Bold, mittig
     Merkmale   786 breit bei x 24, drei Spalten à 240,67 mit 8
                Abstand, Kreis 120, Beschriftung 24 darunter
   ------------------------------------------------------------ */

/* Der Textblock steht oben, die Merkmale unten, die Kulisse
   dahinter. */
.intro__folie--drei {
  justify-content: space-between;
  padding-block: var(--space-md) 0;        /* 16 oben, gemessen */
}

/* Die Kulisse hat keinen Platz im Fluss: sie liegt hinter allem
   und ragt über die Kopfzeile hinaus. Deshalb absolut zum Screen,
   nicht zur Folie. */
/* DIE KULISSE WIRD NICHT BESCHNITTEN. Bis zum 07.09.2026 stand
   hier eine Höhe von 62,3 % — 692,5 von den 1112 des Figma-Frames
   — zusammen mit object-fit: cover. Der Prototyp ist aber nur so
   hoch wie das Fenster, nicht 1112. Bei einem 830 hohen Fenster
   sind 62,3 % nur 517, die Breite aber 950: cover hat die
   Illustration auf das Anderthalbfache gezoomt und Sessel, Tisch
   und Lampe herausgeschnitten (Lisi, 07.09.2026: „es ist hier
   wieder abgeschnitten").

   ZWEI REGELN STATT EINER:

   1. Die Höhe hängt an der BREITE, nicht an der Screen-Höhe —
      wie in Figma, wo die Illustration so breit ist wie der
      Frame:
        13972:19462   x −1,09   y 30,36   830,22 x 692,48
      Als Seitenverhältnis 830,22 : 692,48. Damit ist immer das
      ganze Bild zu sehen.

   2. Sie darf nicht in den Fuß hineinlaufen. Auf einem kurzen
      Fenster wäre sie sonst breiter als hoch Platz ist und läge
      hinter dem Knopf. Die Obergrenze ist deshalb die Mitte
      zwischen Kopf und Fuß (das ist .intro__inhalt) zuzüglich
      der 42,64, um die die Kulisse nach oben über die Kopfzeile
      hinausragt. Greift sie, wird das Bild als Ganzes kleiner
      und bleibt mittig — beschnitten wird es nie.

   DASS DAS UNSICHTBAR BLEIBT, LIEGT AM GRUND: seit er auf
   surface-primary steht, ist er derselbe Farbwert wie die Fläche
   der Illustration. Wo das Bild endet, ist deshalb nicht zu
   sehen — weder seitlich noch unten. */
.intro__kulisse {
  position: absolute;
  /* 30,36 in Figma, gemessen vom Frame-Rand — .intro__inhalt
     beginnt aber erst bei 73 (Kopfhöhe: 16 + 45 + 12). */
  top: -42.64px;
  /* x und Breite ebenfalls aus Figma, als Anteil von 834:
       −1,09 → −0,1307 %      830,22 → 99,547 %
     Die Illustration reicht rechts also 4,9 vor die Kante — in
     Figma tut sie das auch, und da der Grund derselbe Farbwert
     ist, ist davon nichts zu sehen. */
  left: -0.1307%;
  z-index: 0;

  /* 99,547 % meint hier den POLSTERKASTEN von .intro__inhalt —
     für ein absolut gesetztes Kind zählt dessen Außenmaß, die 24
     Polster sind darin schon enthalten. Der Anteil bezieht sich
     also auf die volle Screen-Breite, wie in Figma. */
  width: 99.547%;
  max-width: none;
  height: auto;
  aspect-ratio: 830.22 / 692.48;
  max-height: calc(100% + 42.64px);

  /* CONTAIN, und das ist hier kein Beschnitt, sondern das
     Gegenteil. Greift die Obergrenze, drückt CSS den KASTEN
     flach, ohne die Breite nachzuziehen — das Bild darin wäre
     gestaucht. Mit contain bleibt es unverzerrt und wird als
     Ganzes kleiner; rechts und links bleibt Grund stehen, und
     der ist derselbe Farbwert wie die Fläche im Bild. Das
     object-fit steht am Bild darin, siehe unten. */

  pointer-events: none;
}

/* Alles andere liegt darüber. */
.intro__folie--drei > :not(.intro__kulisse) {
  position: relative;
  z-index: 1;
}

/* Der Textblock ist schmaler als der Screen: 600 mit 48 Polster
   innen, also 504 Textbreite. */
.intro__texte--schmal {
  width: 600px;
  max-width: 100%;
  /* Kein Polster oben und unten: die 16 nach oben trägt schon die
     Folie (.intro__folie--drei). Mit beidem wäre der Block 136
     statt der gemessenen 104 hoch. */
  padding-block: 0;
  padding-inline: var(--space-2xl);        /* 48 */
  gap: var(--space-sm);                    /* 12 — gemessen, nicht 16 */
}

/* 45 px. NICHT AUF DER SKALA: H1 ist auf dem Tablet 34 und auf
   dem Desktop 44. Die 45 sind in Figma von Hand gesetzt
   (13964:17249) — gemessen ist gemessen, aber es gehört
   entschieden, ob daraus ein Stil wird oder ob es 44 werden
   soll. Siehe README.

   Die Laufweite von −1 % ist NICHT übernommen: negative
   Laufweite kommt im ganzen Prototyp nicht vor (Entscheidung
   Lisi, 04.09.2026). */
.intro__titel--gross {
  font-size: 45px;
  line-height: 1.1;
}

/* DIE REIHE STEHT SEIT DEM 08.09.2026 IN DER FUSSZEILE. Damit
   ändern sich die Maße: Der „icons"-Rahmen sitzt jetzt bei x 24
   in einer 834 breiten Fußzeile, ist also 786 breit, und die drei
   Spalten füllen ihn ganz aus — 256,67 + 8 + 256,67 + 8 + 256,67.
   Das seitliche Polster von 24 ist damit weg; es steckt schon in
   der Fußzeile.

   36 oben und unten: der Rahmen ist 235 hoch, sein Inhalt 163 —
   36 + 120 Kreis + 16 + 27 Text + 36 geht genau auf
   (Figma 13964:17251). */
ul.intro__merkmale {
  display: flex;
  gap: var(--space-xs);                    /* 8 — gemessen */
  align-self: stretch;
  margin: 0;
  padding-block: var(--space-xl);          /* 36 — gemessen */
  padding-inline: 0;
  list-style: none;
}

/* Nur auf Folie 3. Der Screen trägt die Nummer schon als
   data-intro, gesetzt in introZeige(). */
.intro__fuss .intro__merkmale {
  display: none;
}

[data-screen="intro"][data-intro="3"] .intro__fuss .intro__merkmale {
  display: flex;
}

.intro__merkmal {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);                    /* 16 — gemessen */
  flex: 1 0 0;
  min-width: 0;
}

/* Der Kreis mit Glow. Hier ist der Glow SCHMUCK und kein
   Zustand — §4 verbietet ihn nur als alleiniges Zustands-Signal,
   nicht als Gestaltungsmittel. */
.intro__merkmal-kreis {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 120px;                            /* gemessen, siehe oben */
  height: 120px;
  border-radius: var(--radius-full);
  background-color: var(--surface-card);
  box-shadow:
    inset 0 0 0 var(--outline-default) var(--label-outline),
    var(--glow-hover);
}

.intro__merkmal-kreis img {
  display: block;
  width: 47px;                             /* gemessen: 46,9 x 41,3 */
  height: 47px;
  object-fit: contain;
}

/* OUTFIT, NICHT INTER (Lisi, 08.09.2026: „intro 3 sollte H3 haben
   mit outfit für die icon texte"). H3 ist eine Überschrift, und
   Überschriften stehen im System in der Display-Familie; hier
   stand versehentlich Inter bei sonst gleichen Werten. */
.intro__merkmal-text {
  font-family: var(--font-family-display);
  font-size: var(--font-size-h3);
  line-height: var(--line-height-h3);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
  text-align: center;
}

/* ------------------------------------------------------------
   Die Folie fliegt ein
   ------------------------------------------------------------
   Quelle: Figma, Keyframes an intro 1 (13964:16603), ausgelesen
   am 05.09.2026.

   IN FIGMA FLIEGT JEDES COVER EINZELN. Sechs Titel und ein Glow,
   gestaffelt um je 300 ms, jeder 1,1 s lang, aus 180 px von
   unten, von Deckkraft 0 und Maßstab 0,88 auf 1. Gesamtdauer
   2,52 s, Kurve cubic-bezier(0.22, 1, 0.36, 1).

   HIER FLIEGT DIE ILLUSTRATION ALS GANZES. Der Grund ist
   handfest: die Illustration liegt als ein Bild vor. Die
   einzelnen Cover ließen sich nur animieren, wenn es sie als
   eigene Dateien gäbe UND einen Hintergrund OHNE sie — sonst
   stünden sie doppelt da, einmal ruhend im Hintergrund und
   einmal fliegend darüber. Siehe README.

   Übernommen sind Kurve, Dauer und Staffelung: Texte zuerst,
   dann der Rest, 300 ms auseinander. Damit stimmt das Gefühl,
   auch wenn die Choreografie einfacher ist.

   ------------------------------------------------------------
   GEMESSENE WERTE OHNE TOKEN-GRUNDLAGE
     1100 ms   Dauer je Element. Länger als alles in motion.css
               (dialog 250, sheet 500) — eine Einführung darf
               sich Zeit nehmen, ein Dialog nicht.
     300 ms    Staffelung.
     0.22 1 0.36 1   Kurve. Nicht in motion.css; sie bremst
               deutlich weicher aus als --motion-ease-out.
     180 px    Weg von unten.
     0,88      Anfangsmaßstab.
   ------------------------------------------------------------ */

@keyframes intro-ein {
  from {
    opacity: 0;
    transform: translateY(180px) scale(0.88);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Die Merkmalsliste ist ausgenommen: ihre Kinder fliegen einzeln
   ein, und beides zusammen würde den Weg verdoppeln. */
/* Die Szene ist ausgenommen: dort fliegt nicht der ganze Block
   ein, sondern die sechs Cover einzeln (siehe „Der Auffächer").
   Beides zusammen wäre doppelte Bewegung. */
.intro__folie--ein > *:not(.intro__merkmale):not(.intro-szene) {
  animation: intro-ein 1100ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.intro__folie--ein > *:nth-child(2) { animation-delay: 300ms; }
.intro__folie--ein > *:nth-child(3) { animation-delay: 600ms; }
.intro__folie--ein > *:nth-child(4) { animation-delay: 900ms; }

/* Die drei Merkmale auf Folie 3 kommen einzeln — das ist die
   Stelle, an der die Staffelung aus Figma am nächsten liegt.
   Sie hängen seit dem 08.09.2026 an der Screen-Nummer und nicht
   mehr an der Folie: sie stehen in der Fußzeile, und die ist kein
   Kind der Folie. Wenn der Selektor zu greifen beginnt, läuft die
   Animation — dasselbe Ergebnis wie vorher über die Klasse. */
[data-screen="intro"][data-intro="3"] .intro__merkmal {
  animation: intro-ein 1100ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

[data-screen="intro"][data-intro="3"] .intro__merkmal:nth-child(1) { animation-delay: 300ms; }
[data-screen="intro"][data-intro="3"] .intro__merkmal:nth-child(2) { animation-delay: 600ms; }
[data-screen="intro"][data-intro="3"] .intro__merkmal:nth-child(3) { animation-delay: 900ms; }

/* Wer weniger Bewegung will, bekommt den Endzustand sofort.
   Nicht „schneller", sondern gar nicht: eine Einführung, die
   sich bewegt, ist Schmuck, und Schmuck fällt hier weg (§23). */
@media (prefers-reduced-motion: reduce) {
  .intro__folie--ein > *,
  [data-screen="intro"][data-intro="3"] .intro__merkmal {
    animation: none;
  }
}

/* ------------------------------------------------------------
   Fuß
   ------------------------------------------------------------ */

.intro__fuss {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);                    /* 12 — gemessen */
  flex-shrink: 0;
  width: 100%;
  padding: var(--space-lg) var(--space-lg) var(--space-xl);   /* 24 / 24 / 36 */

  /* Über der Kulisse. Ohne z-index deckt die Illustration den
     Knopf zur Hälfte zu — sie ist absolut positioniert, die
     Fußzeile nicht, also gewinnt sie beim Zeichnen. */
  position: relative;
  z-index: 1;

  /* DIE FUSSZEILE BLENDET DIE ILLUSTRATION AUS, statt sie
     abzuschneiden (Figma 13899:15664 und 13964:17251, am
     08.09.2026 von Lisi ergänzt: „ein blur hinter dem button,
     sodass es leicht faded wenn das bild abgeschnitten wird").

     Es ist kein echter Weichzeichner, sondern ein Verlauf — so
     heißen die Stile im System (`card blur`, `surface primary
     blur`, `navbar blur`), und beide Stopps sind Tokens:
     --surface-blur-gradient-0 ist surface-primary mit Deckkraft
     0. Genau so steht es an beiden Figma-Knoten.

     DECKEND WIRD ER, WO DER INHALT DER FUSSZEILE BEGINNT — also
     nach dem oberen Polster. Von dort abwärts steht die Fußzeile
     auf festem Grund und die Zeichnung ist weg (Lisi,
     08.09.2026: „bei intro 1 ist der fuß noch voll sichtbar
     hinter dem button, das sollte mehr verschwinden"). Mit einer
     Rampe bis 100 % blieb sie bis zur Unterkante durchscheinend.

     VORHER STAND HIER 43, DIE OBERKANTE DES KNOPFES (24 Polster
     + 7 Punkte + 12). Das war eine Marke zu tief: die Punkte
     lagen damit selbst noch in der Rampe, bei 56 bis 72 %
     Deckkraft. Und die mobile Zeichnung auf Folie 2 hängt 28 in
     die Fußzeile hinein — ihre Unterkante fiel also mitten in
     die Rampe und war als Kante zu sehen (Lisi, 10.09.2026:
     „bei den pagination dots scheint unten etwas durch").

     Jetzt sind es 24, das obere Polster der Fußzeile. Damit
     stehen die Punkte, der Knopf und die Unterkante der
     Zeichnung (28) alle auf deckendem Grund. Die Rampe ist mit
     24 kürzer als vorher, aber immer noch ein Verlauf und keine
     Kante — und §22.6 gibt für ein Verlaufsband 36 Verlauf bei
     40 Höhe vor, dieselbe Größenordnung.

     Folie 3 bleibt bei ihrem eigenen Wert: dort liegen die drei
     Merkmale ABSICHTLICH im Verlauf, genau dafür hat Lisi sie in
     die Fußzeile gestellt. Deckend wird er dort erst an der
     Oberkante des Knopfes — 290 (Tablet), 189 (mobil, wo die
     Merkmalsreihe 134 statt 235 hoch ist). */
  --intro-fuss-deckend: var(--space-lg);   /* 24 — siehe oben */
  background-image: linear-gradient(
    to bottom,
    var(--surface-blur-gradient-0) 0,
    var(--surface-primary) var(--intro-fuss-deckend)
  );
}

[data-screen="intro"][data-intro="3"] .intro__fuss {
  --intro-fuss-deckend: 290px;
}

/* AUF FOLIE 3 IST „ÜBERSPRINGEN" WEG — SEIN PLATZ BLEIBT
   (Lisi, 14.09.2026: „auf dem screen muss überspringen weg. aber
   selbe position für den los gehts button … aber button soll
   nicht springen").

   Das ist genau das, was Figma vormacht: in der Fußzeile von
   intro 3 (14043:38993) steht an der Stelle des Links ein leerer
   Rahmen namens „filler", 112,73 × 45 — dieselbe Höhe wie der
   Link auf Folie 1 und 2. Der Platz ist reserviert, nur nichts
   darin.

   Deshalb `visibility: hidden` und nicht `display: none`: das
   eine nimmt dem Element die Sichtbarkeit, das andere nähme ihm
   auch seine Höhe — und dann rutschte „Los geht's" beim Wechsel
   von Folie 2 auf 3 um 45 plus 12 Abstand nach unten. Genau
   dieses Springen soll nicht passieren.

   Aus der Tastatur-Reihenfolge fällt der Knopf dabei mit heraus;
   das ist richtig, denn es gibt auf der letzten Folie nichts
   mehr zu überspringen — „Los geht's" tut dasselbe. */
[data-screen="intro"][data-intro="3"] [data-intro-ueberspringen] {
  visibility: hidden;
}

/* Das Kamerabild füllt den ganzen Screen und liegt UNTER dem
   Scrim — im Markup steht es davor, und beide sind positioniert,
   also entscheidet die Reihenfolge.

   KEIN z-index: -1. Damit lag es am 05.09.2026 hinter dem
   Hintergrund des Screens selbst (.qr trägt surface-primary) und
   der Screen blieb schwarz, obwohl die Kamera lief. Ein
   negativer z-index schiebt ein Element nicht nur hinter seine
   Geschwister, sondern hinter den Grund seines Elternteils. */
.qr__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: none;
}

.qr[data-kamera="an"] .qr__video {
  display: block;
}

/* Läuft die Kamera, wird der Scrim durchsichtig statt deckend.
   Er bleibt aber liegen: das Kamerabild kann beliebig hell sein,
   und ✕, Blitz und der Hinweistext müssen darauf lesbar bleiben
   (§18). Derselbe Wert wie über einem Cover. */
.qr[data-kamera="an"] .qr__scrim {
  background-color: var(--transparent-scrim-full-black-60);
}

.qr__kamera {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 80px;                               /* gemessen */
  padding: var(--space-lg) var(--space-lg) var(--layout-screen-margin);
}

.qr__knopfreihe {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.qr__rahmen-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);                    /* 16 */
}

/* Ein 400er Quadrat mit einem 98er Winkel in jeder Ecke, gebaut
   als Raster — dann wachsen die Winkel mit, wenn der Screen
   schmaler wird.

   DER STRICH IST 5 PX und damit breiter als alles, was
   tokens.css kennt (1 und 2). Er ist auch kein Rand im Sinne
   des Systems, sondern eine Zeichnung: die Ecken eines Suchers.
   Deshalb steht die 5 hier und nicht als Token. */
.qr__rahmen {
  display: grid;
  grid-template-columns: 98px 98px;
  grid-template-rows: 98px 98px;
  justify-content: space-between;
  align-content: space-between;
  width: 400px;
  height: 400px;
  max-width: 100%;
}

.qr__ecke {
  border: 0 solid var(--text-accent);
}

.qr__ecke--ol { border-top-width: 5px;    border-left-width: 5px;  border-top-left-radius: 4px; }
.qr__ecke--or { border-top-width: 5px;    border-right-width: 5px; border-top-right-radius: 4px; }
.qr__ecke--ul { border-bottom-width: 5px; border-left-width: 5px;  border-bottom-left-radius: 4px; }
.qr__ecke--ur { border-bottom-width: 5px; border-right-width: 5px; border-bottom-right-radius: 4px; }

.qr__hinweis {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--letter-spacing-small-text-bold);
  color: var(--text-primary);
  text-align: center;
}

/* Die Karte unten. Sie sitzt an der Unterkante und wandert nach
   oben, sobald die Systemtastatur aufgeht — siehe Kopf. */
/* 258 hoch, obwohl der Inhalt nur 186 braucht — so steht die
   Karte in Figma, mit Luft unter dem Link. Deshalb min-height
   und oben ausgerichtet, nicht zentriert: mit Zentrierung säße
   der Titel zu tief.

   NICHT `screen` als Klasse am Screen: base.css gibt `.screen`
   20 px Seitenrand, und die Karte läuft hier bis an die Kante.
   Der Screen trägt nur .screen--voll. */
.qr__code {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);                    /* 16 */
  width: 100%;
  min-height: 258px;                       /* gemessen */
  padding: var(--space-md) var(--space-lg) var(--space-lg);
  background-color: var(--surface-card);
}

.qr__code-inhalt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);                    /* 16 */
}

.qr__code-titel {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--letter-spacing-small-text-bold);
  color: var(--text-description);
  text-align: center;
}

/* Sobald die Tastatur offen ist, wird der sichtbare Bereich
   niedrig. Dann schrumpft der Sucher, statt aus dem Bild zu
   laufen — die Eingabe bleibt vollständig sichtbar. */
/* 780 und nicht 700: bei 320 x 720 — dem kleinsten Fenster, das
   noch gebaut sein soll — brauchte der obere Teil 476 und die
   Karte 258, zusammen 734. Die 14 zuviel ließen den Screen
   scrollen. Nachgezogen am 07.09.2026. */
@media (max-height: 780px) {
  .qr__kamera {
    gap: var(--space-lg);
  }

  /* Bei offener Tastatur zählt jeder Pixel — die Karte gibt ihre
     Reserve ab und wird so hoch wie ihr Inhalt. */
  .qr__code {
    min-height: 0;
  }

  .qr__rahmen {
    width: 260px;
    height: 260px;
    grid-template-columns: 64px 64px;
    grid-template-rows: 64px 64px;
  }
}

/* ------------------------------------------------------------
   16. Einstellungen
   ------------------------------------------------------------
   Figma-Nodes 13872:16142 (Screen) und 13872:16236 (mit
   Abmelde-Dialog), ausgelesen am 04.09.2026.

   Voll-Screen-Überlagerung über den vier Nav-Seiten. Deshalb ein
   ✕ (die Navigation ist verdeckt, §19.1) und zwar LINKS
   (Voll-Screen, §19.2) — genau der Fall „modal und trotzdem
   Voll-Screen" aus §19.

   Der zweite Figma-Frame ist derselbe Screen mit einem Dialog
   darüber; er ist kein eigener Screen.
   ------------------------------------------------------------ */

.einstellungen {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);                    /* 24 */
  padding: var(--space-2xl) var(--space-lg);   /* 48 / 24 */
  background-color: var(--surface-primary);
}

.einstellungen__kopf {
  display: flex;
  align-items: center;
  gap: var(--space-sm);                    /* 12 */
  width: 100%;
}

/* Der Titel in der festen Zeile ist medium text bold, nicht H1 —
   die Zeile ist Bedienoberfläche, kein Inhalt (§26.3). Outfit
   bleibt den Inhaltstiteln. */
.einstellungen__titel {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-medium-text);
  line-height: var(--line-height-medium-text);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
}

/* Die Versionsnummer steht mittig unter allem, in text-primary —
   so gemessen, nicht in text-description. */
.einstellungen__version {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-extra-small-text);
  line-height: var(--line-height-extra-small-text);
  font-weight: var(--font-weight-regular);
  letter-spacing: var(--letter-spacing-small-text-bold);
  color: var(--text-primary);
  text-align: center;
}

/* ------------------------------------------------------------
   17. Dialog-Halter
   ------------------------------------------------------------
   dialog.css bringt den Dialog mit, aber nicht seine Lage —
   dieselbe Aufteilung wie beim Sheet. Der Dialog ist 353 breit
   (§22.1) und schwebt zentriert innerhalb der Ränder.
   ------------------------------------------------------------ */

.dialog-halter {
  position: fixed;
  inset: 0;
  z-index: 21;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--layout-screen-margin);
  /* Der Halter fängt keine Klicks — sonst wäre die Fläche neben
     dem Dialog eine unsichtbare Klickfalle und der Scrim darunter
     nicht erreichbar. */
  pointer-events: none;
}

.dialog-halter > .dialog {
  width: 353px;                            /* §22.1 */
  max-width: 100%;
  pointer-events: auto;
}

/* ------------------------------------------------------------
   16. Toast-Schicht
   ------------------------------------------------------------
   toast.css bringt die Komponente mit. Zwei Dinge kommen vom
   Screen dazu.

   ERSTENS DIE LAGE. toast.css setzt die Schicht auf
   left/right: 20 am Fenster. Auf dem Tablet gehört sie in den
   Inhaltsbereich, also rechts vom Navigationsstreifen — sonst
   liegt der Toast über der Navigation, und §7 nennt sie „die
   einzige jederzeit sichtbare Struktur der App". toast.css sagt
   im Kopf dasselbe für die Bottom Nav.

   ZWEITENS DIE BREITE. Über die volle Inhaltsbreite wäre der
   Toast 674 breit und der Text stünde verloren links. In Figma
   ist er so breit wie sein Inhalt und steht mittig.
   ------------------------------------------------------------ */

.toast-schicht {
  /* DERSELBE RAND WIE DIE SCREENS (Lisi, 14.09.2026: „der toast
     unten soll end to end sein mit selben margin wie screens.
     also 20px bei mobile und 24px abstand zum screenrand bei
     tablet"). --sektion-rand steht am Screen und ist hier nicht
     erreichbar — die Schicht liegt außerhalb —, deshalb dieselben
     zwei Token noch einmal an einem eigenen Namen. */
  --toast-rand: var(--space-lg);           /* 24, Tablet */

  left: calc(var(--buehne-links) + var(--nav-rail-breite) + var(--toast-rand));
  right: calc(var(--buehne-links) + var(--toast-rand));

  /* Von Kante zu Kante. Vorher stand hier `center` und der Toast
     war so breit wie sein Text; er sprang dadurch mit jeder
     Meldung in eine andere Breite. */
  align-items: stretch;
}

/* Auf Screens ohne Navigationsstreifen — Onboarding, Anmelden,
   QR — beginnt die Schicht an der Bühnenkante. */
.app:has([data-screen="app"][hidden]) ~ .toast-schicht,
body:has([data-screen="app"][hidden]) .toast-schicht {
  left: calc(var(--buehne-links) + var(--toast-rand));
  /* Ohne Gerüst gibt es auch keine Bar, über der etwas bleiben
     müsste. */
  bottom: var(--space-md);
}

/* ------------------------------------------------------------
   Der Erfolgs-Toast steht vollständig in der Komponente
   ------------------------------------------------------------
   Hier standen am 15.09.2026 einen Nachmittag lang die 36er
   Zeichenfläche, die Animation aus dem Bewegungs-JSON, die Maske
   für den Außenschein, der fehlende Abstand zwischen den
   Textzeilen und die graue zweite Zeile.

   Cowork hat alles nach components/toast.css genommen, in die
   Fassung erfolg — samt der drei Stolpersteine, die uns Zeit
   gekostet haben und jetzt dort als Begründung stehen: dass
   --motion-ease-bubble für einen Pop nicht reicht, dass die
   Länge des Hakens eine Einheit braucht, und dass die Maske
   einen ausdrücklichen Bereich braucht.

   Der Prototyp liefert nur noch das Markup und --haken-laenge,
   beides so, wie die Komponente es verlangt. Ersatzlos weg.
   ------------------------------------------------------------ */

/* 7 Sekunden statt der 8 aus toast.css. Entschieden von Lisi am
   04.09.2026. §20 nennt 8 für undo, weil der Nutzer lesen,
   entscheiden und treffen muss — der Wert ist im System
   nachzuziehen oder hier zurückzunehmen. */
/* Der Undo-Toast steht seit dem 04.09.2026 vollständig in
   components/toast.css — Polsterung, Abstand, Textgewicht,
   Schattenradius und die 8 Sekunden. Vorher standen die vier
   Abweichungen hier im Prototypen, weil die Komponente sie noch
   nicht hatte. Geblieben ist nur, was wirklich zum Screen
   gehört. */

.toast--undo .toast__texte {
  /* Icon und Text stehen als Block zusammen, die Aktion daneben —
     der Abstand kommt aus dem gap, nicht aus einem Padding. */
  padding-left: 0;
}

/* ============================================================
   MOBIL — Intro, ab 320 px
   ------------------------------------------------------------
   Quelle: Figma „Screens: App und Web" → intro 1 (13954:28482),
   intro 2 (13963:15898), intro 3 (13963:16015), Rahmen 393 x 852,
   ausgelesen am 07.09.2026.

   Die Breakpoints stehen schon im System (AGENTS.md §4):
     Mobile   bis 767
     Tablet   768 – 1199
     Desktop  ab 1200
   Deshalb hier max-width: 767px und keine neue Grenze.

   tokens.css schaltet die Schriftgrößen an derselben Stelle um —
   H1 wird von 34 auf 29, Large Text von 24 auf 22. Das passiert
   von allein; hier steht nur, was sich am LAYOUT ändert.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     20    Seitenrand statt 24 (--layout-screen-margin, mobil).
     12    Innenabstand im Textblock statt 48.
     80    Merkmal-Kreis statt 120.
     117,7 Spaltenbreite der Merkmale — 353 durch 3, ohne Abstand.
     393 x 384  Kulisse auf Folie 3, ab y 87.
   ------------------------------------------------------------ */

@media (max-width: 767px) {

  /* Kopf, Inhalt und Fuß rücken von 24 auf 20 ein. */
  .intro__kopf {
    padding-inline: var(--layout-screen-margin, 20px);
  }

  .intro__inhalt {
    padding-inline: var(--layout-screen-margin, 20px);

    /* DIE MITTE SCHNEIDET NICHT MEHR AB (geändert 08.09.2026).

       Vorher stand hier overflow: hidden. Das hielt die
       Illustration vom Knopf fern, hinterließ aber genau die
       harte Kante, die Lisi gemeldet hat: auf einem Fenster, das
       kürzer ist als die 852 des Rahmens, endete die Zeichnung
       mitten im Bild an einer geraden Linie.

       Jetzt darf sie weiterlaufen und wird von der Fußzeile
       ausgeblendet — die trägt seit dem 08.09.2026 den Verlauf
       aus Figma (siehe .intro__fuss weiter unten). Das ist
       dieselbe Lösung wie das Verlaufsband über einer fixierten
       Fußzeile (SKILL.md §22.6): kein Schnitt, sondern ein
       Übergang. Nach unten begrenzt weiterhin .intro selbst
       (height: 100vh; overflow: hidden). */
  }

  /* DIE FUSSZEILE BLENDET DIE ILLUSTRATION AUS, statt sie
     abzuschneiden (Figma 13899:15664, 08.09.2026 von Lisi
     ergänzt: „ein blur hinter dem button, sodass es leicht faded
     wenn das bild abgeschnitten wird").

     Es ist kein echter Weichzeichner, sondern ein Verlauf — so
     heißen die Stile im System (`card blur`, `surface primary
     blur`, `navbar blur`), und beide Stopps sind Tokens:
     oben --surface-blur-gradient-0 (surface-primary mit
     Deckkraft 0), unten --surface-primary. Genau so steht es am
     Figma-Knoten.

     Er liegt auf der ganzen Fußzeile und nicht auf einem 40er
     Band wie in §22.6. Der Grund ist ein anderer: dort soll
     scrollender TEXT lesbar bleiben und der Knopf auf festem
     Grund stehen; hier soll eine Zeichnung über die volle Höhe
     verschwinden. Der Knopf selbst ist deckend, ihm macht der
     Verlauf nichts aus. */
  .intro__fuss {
    padding-inline: var(--layout-screen-margin, 20px);
  }

  /* Mobil ist die Merkmalsreihe 134 statt 235 hoch, der Knopf
     beginnt deshalb bei 189 statt 290. */
  [data-screen="intro"][data-intro="3"] .intro__fuss {
    --intro-fuss-deckend: 189px;
  }

  /* DER TITEL STEHT OBEN, WIE AUF FOLIE 1 UND 2 (Lisi,
     08.09.2026: „hier wird nun der titel viel weiter unten als in
     screen 1 und 2 gezeigt").

     Kurz zuvor stand er hier mittig. Das kam aus dem Rahmen: seit
     die Merkmale in die Fußzeile gewandert sind, steht im
     „inhalt" von intro 3 nur noch der Text, und zwar bei y 150,5
     von 424 (13963:16019) — auf Folie 1 und 2 sitzt er direkt
     unter der Kopfzeile. Der Rahmen ist an dieser Stelle noch
     nicht nachgezogen; verbindlich ist die Ansage. */
  .intro__folie--drei {
    padding-block: 0;
  }

  /* Der Textblock ist nicht mehr auf 600 begrenzt — er nimmt die
     Breite und behält nur 12 Polster innen (Figma 13954:29376). */
  .intro__texte,
  .intro__texte--schmal {
    width: 100%;
    padding-inline: var(--space-sm);        /* 12 statt 48 */
    /* Kein Polster oben und unten: in Figma sitzt der Titel an
       der Oberkante des Textblocks (Header Container, y 0). Die
       16 stammten vom Tablet. */
    padding-block: 0;
    gap: var(--space-sm);                   /* 12 statt 16 */
  }

  /* DIE 45 SIND EINE TABLET-AUSNAHME. Mobil steht der Titel auf
     der Skala: H1 = 29/31,9 (Figma-Textknoten 329 x 32). Damit
     entfällt hier die handgesetzte Größe. */
  .intro__titel--gross {
    font-size: var(--font-size-h1);
    line-height: var(--line-height-h1);
  }

  /* Die drei Merkmale füllen die Zeile ohne Abstand und ohne
     Polster: 353 breit, drei Spalten à 117,67, Inhalt 127 hoch
     (80 Kreis + 24 + 23 Text) — das ist die ganze Rahmenhöhe
     (Figma 13963:17443). */
  ul.intro__merkmale {
    gap: 0;
    padding: 0;
  }

  .intro__merkmal-kreis {
    width: 80px;                            /* gemessen, siehe Kopf */
    height: 80px;
  }

  /* 8 ZWISCHEN KREIS UND BESCHRIFTUNG, nicht 24. Nachgemessen am
     08.09.2026 an 13963:17443: der Kreis endet bei 80, der Text
     beginnt bei 88.

     Damit stimmt auch die Zeilenhöhe: 80 + 8 + 46 = 134, und 134
     ist die Höhe des Rahmens in Figma. Vorher waren es mit 24
     genau die 149,6, die ich als Fehler gemeldet hatte — der
     Fehler war der Abstand, nicht der Umbruch. */
  .intro__merkmal {
    gap: var(--space-xs);                   /* 8, gemessen */
  }

  /* Das Zeichen im Kreis wächst mit dem Kreis: 47 mal 80/120.
     Es sind dieselben drei Symbole wie auf dem Tablet — Lisi hat
     die mobile Fassung am 07.09.2026 auf „Ohne Anmeldung ·
     Hygienisch · Papierlos" nachgezogen. */
  .intro__merkmal-kreis img {
    width: 31.3px;
    height: 31.3px;
  }

  /* Die Kulisse auf Folie 3 ist mobil eine andere Zeichnung:
     393 x 384 ab y 87 statt 830 x 692 ab y 30. 87 minus die 73
     Kopfhöhe sind die 14, um die sie in den Inhalt hineinragt. */
  .intro__kulisse {
    top: 14px;
    left: 0;
    width: 100%;
    aspect-ratio: 393 / 384;
    max-height: calc(100% - 14px);
  }

  /* DIE KARTEN BRAUCHEN LUFT NACH OBEN (Lisi, 10.09.2026: „2
     optionen klebt an den cards").

     Der Textblock hat mobil kein Polster mehr — richtig, denn in
     Figma sitzt der Titel an der Oberkante des Rahmens. Mit dem
     unteren Polster ist aber auch der Abstand ZUR nächsten
     Gruppe verschwunden: die Unterzeile und die erste Karte
     berührten sich auf 0.

     Der Abstand steht deshalb an den Karten und nicht wieder am
     Textblock — er gehört zwischen zwei Gruppen, und .intro__wege
     gibt es nur auf dieser Folie. 12 ist der Takt dieser Folie:
     Titel → Unterzeile 12, Karte → Karte 12, Polster in der
     Karte 12.

     ANZUPASSEN, WENN DER RAHMEN ETWAS ANDERES SAGT. Beim
     Nachmessen war die Figma-Datei nicht erreichbar (offen war
     ein FigJam-Board); 12 ist aus dem Takt der Folie
     abgeleitet, nicht am Rahmen abgelesen. */
  .intro__wege {
    margin-top: var(--space-sm);           /* 12 — siehe oben */
  }

  /* Folie 2: dieselbe Umstellung wie auf Folie 1 — die flache
     Tablet-Illustration verschwindet, die mobile Zeichnung tritt
     an ihre Stelle. */
  .intro__folie[data-intro-folie="2"] .intro__bild {
    display: none;
  }

  /* SIE LIEGT FEST, NICHT IM FLUSS. Wie die Szene auf Folie 1
     steht sie an der Stelle, an der Figma sie zeigt, und nicht
     dort, wo der Text zufällig endet. Bezug ist .intro__inhalt.

     KEINE MASKE OBEN. Die Tablet-Fassung blendet ihre Oberkante
     weich aus, weil dort hart beschnitten wird. Hier ist das
     nicht nötig: der Ausschnitt beginnt genau am oberen Rand des
     Glows, und der läuft von sich aus auf durchsichtig aus. */
  .intro__bild-mobil {
    display: block;
    position: absolute;
    left: 0;
    /* SIE HÄNGT AN DER FUSSZEILE, NICHT AN DER KOPFZEILE
       (geändert 08.09.2026, Lisi: „das klebt nun zu weit unten,
       vorher war es besser").

       Vorher stand hier top: 242,5 — die 315,5 aus Figma minus
       die 73 der Kopfzeile. Auf einem Fenster, das kürzer ist als
       852, rückt die Fußzeile hoch, die Zeichnung blieb aber
       stehen: die Punkte landeten mitten auf dem Telefon.

       Jetzt zählt der Abstand nach unten. In Figma endet die
       Zeichnung bei 671, die Fußzeile beginnt bei 643 — sie ragt
       also 28 hinein. Genau das steht hier, und .intro__inhalt
       endet an der Oberkante der Fußzeile. Auf 393 x 852 kommt
       damit dasselbe heraus wie vorher (316,3 gegen 315,5); auf
       kürzeren Fenstern wandert die Zeichnung mit.

       FOLIE 1 UND 3 BLEIBEN OBEN VERANKERT. Dort steht die
       Zeichnung mit ihrer Oberkante fest: die Szene auf Folie 1
       ist 468 hoch, an der Fußzeile aufgehängt liefe sie auf
       einem kurzen Fenster über den Titel hinaus. Sie darf
       stattdessen unten in den Verlauf laufen. */
    bottom: -28px;
    /* max-width: none, sonst kappt img { max-width: 100% } aus
       base.css die Breite auf den Polsterkasten — dasselbe wie
       bei .intro__bild. */
    max-width: none;

    width: 100%;
    height: auto;
    aspect-ratio: 393 / 355.5;
    z-index: 0;
    pointer-events: none;
  }

  /* SIE NIMMT DEN PLATZ, DER ÜBRIG IST — UND NICHT MEHR
     (Lisi, 14.09.2026: „bei bild 2 überlappt sehr viel").

     Vorher lag sie fest, und ihre Höhe hing allein an der
     Breite: 393 zu 355,5. Auf einem kurzen Fenster — ein Telefon
     mit Browserleiste hat oft nur 660 statt 852 — wuchs sie
     dadurch nach oben unter die Zugangs-Karten und lag halb
     hinter ihnen.

     Jetzt steht sie im Fluss und bekommt, was zwischen dem Text
     und der Fußzeile frei ist. `contain` hält dabei das
     Verhältnis: sie wird kleiner, nie beschnitten und nie
     verzerrt. Unten ragt sie weiter 28 in die Fußzeile, wie in
     Figma.

     DER PREIS: auf einem langen Fenster ist sie kleiner als
     vorher, weil sie den Karten nicht mehr in den Rücken wächst.
     Trennung geht hier vor Größe — eine Zeichnung hinter einer
     Karte liest sich als Fehler. */
  .intro__folie[data-intro-folie="2"] .intro__bild-mobil {
    position: static;
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    height: auto;
    aspect-ratio: auto;
    object-fit: contain;
    object-position: bottom center;
    margin-bottom: -28px;
  }

  /* Sie kommt zur selben Zeit herein wie die flache Illustration
     auf dem Tablet. Über nth-child geht das nicht: dort ist sie
     das fünfte Kind, das vierte ist das ausgeblendete Bild. */
  .intro__folie--ein .intro__bild-mobil {
    animation-delay: 900ms;
  }
}

/* DAS <picture> IST DER KASTEN, nicht das Bild darin. Mit
   display: contents am <picture> zählte der Browser ein drittes
   Element in die Flex-Verteilung der Folie und schob den Titel um
   142 nach unten. Deshalb trägt jetzt das <picture> selbst die
   Maße, und das Bild füllt es aus. */
.intro__kulisse > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;

  /* SIE KLEBT LINKS (10.09.2026, Lisi: „hier ist nun das bild
     abgeschnitten, es sollte am linken rand kleben. es kann
     größer oder kleiner werden aber nie abschneiden").

     contain schneidet nie ab — das war schon richtig. Es
     ZENTRIERT aber, was übrig bleibt, und genau das sah aus wie
     ein Schnitt: greift die Höhenbegrenzung, wird die Zeichnung
     kleiner, und links davon stand plötzlich leerer Grund.
     Gemessen bei 950 Bühne und 760 Fensterhöhe: Kasten 945,7
     breit, gemalt nur 327 — also 308 px Leere links, und die
     Hauskante der Zeichnung stand mitten im Screen.

     object-position entscheidet nur, WOHIN das Übrige fällt.
     Links heißt: die Zeichnung beginnt an der Kante, so wie im
     Rahmen (x −1,09 von 834). Kleiner werden darf sie dabei —
     abgeschnitten wird sie nach wie vor nie. */
  object-position: left center;
}

/* ============================================================
   OFFEN — Mobil
   ------------------------------------------------------------
   · Erledigt: alle drei Folien zeigen mobil ihre eigene
     Zeichnung. Folie 2 seit dem 08.09.2026.
   · Erledigt am 08.09.2026: die harte Kante auf kurzen Fenstern.
     Die Zeichnungen laufen jetzt bis hinter die Fußzeile und
     werden dort von ihrem Verlauf ausgeblendet. Siehe
     .intro__inhalt und .intro__fuss im Mobil-Block.
   · Erledigt am 08.09.2026: der Fuß war mobil 13 zu hoch. Ursache
     war nicht das Intro, sondern pagination.css — das <li> um den
     Punkt legte eine Textzeile an und war 21 statt 7 hoch. Jetzt
     643,8 / 208,2 gegen 643 / 209 in Figma.
   · Der Verlauf in der Fußzeile läuft über die ganzen 209, von
     durchsichtig bis deckend. Die beiden Blur-Stile im System
     sind „opak ab 90 %" (§22.6); ob das hier auch gilt, sagt der
     Figma-Knoten nicht — er nennt nur die zwei Stopps. Falls
     doch, wird der Verlauf unten 21 px früher deckend.
   · „Ohne Anmeldung" bricht unter 393 aus seiner Spalte heraus:
     bei 375 sind die drei Spalten 111,7 breit, das Wort
     „Anmeldung" ist breiter. Für unter 393 gibt es keinen
     Figma-Rahmen.
   · Erledigt: „Ohne Anmeldung" bricht in Figma GENAUSO auf zwei
     Zeilen. Der Textknoten ist dort 101 x 46 — 46 sind zwei
     Zeilen H3 (19 / 22,8). Die Spalte ist nicht anders gesetzt;
     zu hoch war die Reihe nur wegen des falschen Abstands
     zwischen Kreis und Text (24 statt 8).
   ============================================================ */

/* ============================================================
   MOBIL — Intro Folie 1: die Szene mit den Covern
   ------------------------------------------------------------
   Quelle: Figma „Screens: App und Web" → intro 1 mobil,
   Rahmen 13954:28482 (393 x 852), Illustration „lady image"
   13982:27719, ausgelesen am 07.09.2026.

   WARUM EINE SZENE UND KEIN BILD. Die sechs Cover fächern in
   Figma Motion nacheinander von unten auf. Als ein flaches Bild
   ginge das nicht — jedes Cover muss ein eigenes Element sein.
   Darunter liegt deshalb die Zeichnung OHNE Cover und ohne
   Schein; die sieben fehlenden Teile liegen als eigene Dateien
   darüber.

   ALLE MASSE ALS ANTEIL DER SZENE. Die Szene ist der Kasten der
   Illustration: 393 breit, 468,49 hoch, im Rahmen ab y 166. Die
   Kinder stehen in Prozent davon, damit die Szene als Ganzes mit
   der Fensterbreite wächst.

   Auch die Flugstrecken stehen in Prozent — aber der EIGENEN
   Größe des Covers, nicht der Szene. So bleibt der Weg im
   richtigen Verhältnis, wenn das Fenster 320 statt 393 ist.
   Umgerechnet aus den Figma-Werten in px:
     VOGUE   +101,75 / +180   auf 67,04 x 83,51
     GEO           0 / +180   auf 53,12 x 77,77
     FOCUS      −99  / +180   auf 69,72 x 84,75
     Gala      +93,5 / +180   auf 77,12 x 77,68
     BUNTE     −2,75 / +180   auf 49,83 x 68,80
     SPIEGEL  −104,5 / +180   auf 65,37 x 80,99

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     393 x 468,49  Szene, ab y 166 im Rahmen.
     1100 ms       Flugdauer je Cover.
     300 ms        Versatz von Cover zu Cover.
     900 ms        Aufblenden — kürzer als der Flug, wie in Figma.
     6,7°          Neigung von FOCUS.
   ------------------------------------------------------------ */

/* Auf dem Tablet bleibt das flache Bild; die Szene ist mobil. */
.intro-szene {
  display: none;
}

@media (max-width: 767px) {

  .intro__folie[data-intro-folie="1"] .intro__bild {
    display: none;
  }

  /* SIE WIRD KLEINER, STATT ABGESCHNITTEN ZU WERDEN
     (Lisi, 14.09.2026: „dame abgeschnitten unten").

     Bis dahin hing die Höhe allein an der Breite: 393 zu 468,5.
     Auf einem kurzen Fenster — und ein Telefon mit Browserleiste
     ist kurz, oft nur 660 statt 852 — lief die Szene unter die
     Fußzeile und wurde am Screenrand gekappt. Genau dort sitzt
     die Figur.

     Jetzt gibt die Höhe den Ausschlag, sobald sie knapp wird:
     was zuerst nicht passt, bestimmt beide Maße. Die Szene
     schrumpft dann gleichmäßig und bleibt mittig — alle Teile
     darin sind in Prozent gesetzt und gehen mit.

     100 % ist die Höhe von .intro__inhalt, davon ab die 93 des
     Abstands nach oben. Der zweite Wert ist die Höhe, die sich
     aus der vollen Breite ergäbe. */
  .intro-szene {
    display: block;
    position: absolute;
    /* 166 im Rahmen, minus die 73 der Kopfzeile — .intro__inhalt
       ist der Bezug. */
    top: 93px;
    left: 50%;
    translate: -50% 0;
    height: min(calc(100% - 93px), calc(100vw * 468.49 / 393));
    width: auto;
    aspect-ratio: 393 / 468.49;
    z-index: 0;
    pointer-events: none;
  }

  .intro-szene > * {
    position: absolute;
    display: block;
  }

  /* KEINE SAMMELREGEL FÜR .intro-szene img. Eine solche Regel
     (Klasse + Typ) schlägt jede Cover-Regel (nur Klasse) und hat
     am 07.09.2026 alle sechs Cover auf Szenengröße aufgeblasen —
     345 statt 77 breit. Jedes Teil bekommt sein Maß selbst. */
  .intro-szene > img {
    max-width: none;
  }

  /* Die Grundplatte füllt die Szene. */
  .intro-szene__platte {
    inset: 0;
    width: 100%;
    height: 100%;
  }

  /* Der Schein liegt hinter den Covern, aber über der Platte. */
  .intro-szene__schein {
    left: 21.391%;                           /* 84,067 von 393 */
    top: 5.739%;                             /* 192,884 − 166 von 468,49 */
    width: 96.046%;                          /* 377,461 */
    height: 80.601%;                         /* 377,608 */
  }

  .intro-szene__cover--gala {
    left: 51.247%;  top: 32.949%;  width: 19.623%;  height: 16.580%;
  }
  .intro-szene__cover--bunte {
    left: 66.972%;  top: 31.872%;  width: 12.681%;  height: 14.687%;
  }
  .intro-szene__cover--spiegel {
    left: 79.925%;  top: 33.431%;  width: 16.633%;  height: 17.288%;
  }
  .intro-szene__cover--vogue {
    left: 49.500%;  top: 44.842%;  width: 17.060%;  height: 17.824%;
  }
  .intro-szene__cover--geo {
    left: 66.047%;  top: 45.738%;  width: 13.516%;  height: 16.601%;
  }

  /* FOCUS liegt schräg. Der äußere Kasten ist die aufrechte
     Hülle (69,72 x 84,75), das Bild darin ist 61,01 x 78,16 und
     um 6,7° gedreht — die Hülle trägt den Flug, das Bild die
     Neigung. Zwei Elemente, weil ein transform beides nicht
     gleichzeitig kann, ohne dass die Animation die Drehung
     überschreibt. */
  .intro-szene__cover--focus {
    left: 79.457%;  top: 45.590%;  width: 17.740%;  height: 18.089%;
  }

  .intro-szene__cover--focus img {
    width: 87.512%;                          /* 61,014 von 69,719 */
    height: 92.229%;                         /* 78,16 von 84,746 */
    margin: 3.885% 6.244%;                   /* mittig in der Hülle */
    rotate: 6.7deg;
  }
}

/* ------------------------------------------------------------
   Der Auffächer
   ------------------------------------------------------------
   Er läuft EINMAL, wenn die Folie kommt — nicht in Schleife.
   Figma hat ihn auf Dauerschleife, aber dort springt die
   Deckkraft am Schleifenende von 1 auf 0 zurück: das blinkt. Die
   übrige Intro-Bewegung spielt ebenfalls einmal.

   Die Kurve ist dieselbe wie bei intro-ein: cubic-bezier(0.22,
   1, 0.36, 1), so steht sie in Figma an jedem der sieben Teile.
   ------------------------------------------------------------ */

@keyframes cover-auf {
  from {
    translate: var(--cover-von-x) var(--cover-von-y);
    scale: 0.88;
  }
  to {
    translate: 0 0;
    scale: 1;
  }
}

@keyframes cover-sichtbar {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes schein-auf {
  from { scale: 0; }
  to   { scale: 1; }
}

@media (max-width: 767px) {
  .intro__folie--ein .intro-szene__cover {
    animation:
      cover-auf      1100ms cubic-bezier(0.22, 1, 0.36, 1) var(--cover-ab) both,
      cover-sichtbar  900ms cubic-bezier(0.22, 1, 0.36, 1) var(--cover-ab) both;
  }

  .intro-szene__cover--vogue   { --cover-ab:    0ms; --cover-von-x:  151.76%; --cover-von-y: 215.56%; }
  .intro-szene__cover--geo     { --cover-ab:  300ms; --cover-von-x:       0%; --cover-von-y: 231.45%; }
  .intro-szene__cover--focus   { --cover-ab:  600ms; --cover-von-x: -142.00%; --cover-von-y: 212.40%; }
  .intro-szene__cover--gala    { --cover-ab:  900ms; --cover-von-x:  121.24%; --cover-von-y: 231.74%; }
  .intro-szene__cover--bunte   { --cover-ab: 1200ms; --cover-von-x:   -5.52%; --cover-von-y: 261.61%; }
  .intro-szene__cover--spiegel { --cover-ab: 1500ms; --cover-von-x: -159.87%; --cover-von-y: 222.25%; }

  /* Der Schein kommt zuletzt: in Figma ab 67,5 % einer 2,517 s
     langen Spur, also nach 1700 ms, und wächst in den restlichen
     817 ms von 0 auf 1. */
  .intro__folie--ein .intro-szene__schein {
    transform-origin: center;
    animation: schein-auf 817ms cubic-bezier(0.167, 0.167, 0.833, 0.833) 1700ms both;
  }
}

@media (prefers-reduced-motion: reduce) {
  .intro__folie--ein .intro-szene__cover,
  .intro__folie--ein .intro-szene__schein {
    animation: none;
  }
}

/* ============================================================
   MOBIL — QR-Code-Scanner, ab 320 px
   ------------------------------------------------------------
   Quelle: Figma „Screens: App und Web" →
     scanner.active     3817:8874    (393 x 862)
     scanner.codeInput  13875:15139  (derselbe Screen, Eingabe aktiv)
   ausgelesen am 07.09.2026.

   Der Aufbau ist derselbe wie auf dem Tablet. Vier Maße ändern
   sich, und die Kästchen brechen um.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     20        Seitenrand und Abstand nach oben (statt 24).
     274 x 274 Sucher (statt 400 x 400).
     67        Winkel in jeder Ecke (statt 98).
     80        Abstand Knopfreihe → Sucher — unverändert.
               20 + 45 + 80 = 145, genau die y des Suchers.
     258       Höhe der Karte unten — unverändert.
     272       Breite einer Kästchenzeile: 5 x 48 mit 8 Abstand.
   ------------------------------------------------------------ */

@media (max-width: 767px) {

  .qr__kamera {
    padding: var(--layout-screen-margin) var(--layout-screen-margin)
             var(--layout-screen-margin);
  }

  .qr__rahmen {
    width: 274px;                          /* gemessen, siehe Kopf */
    height: 274px;
    grid-template-columns: 67px 67px;
    grid-template-rows: 67px 67px;
  }

  .qr__code {
    padding-inline: var(--layout-screen-margin);
  }

  /* Bleibt das Fenster unter 700 hoch — kleines Gerät, oder die
     Systemtastatur ist offen —, schrumpft der Sucher weiter.
     Ohne das lief der Screen bei 320 x 568 um 94 über.

     Die Regel weiter unten (max-height 780) fasst hier nicht: sie
     steht VOR diesem Block und verliert deshalb gegen die 274.
     Deshalb noch einmal, und mit beiden Bedingungen.

     180 und 44 sind NICHT gemessen — für ein 568 hohes Fenster
     gibt es keinen Frame. Es ist dasselbe Verhältnis wie beim
     Tablet-Rückfall (400 → 260, also 65 %). */
  @media (max-height: 700px) {
    .qr__rahmen {
      width: 180px;
      height: 180px;
      grid-template-columns: 44px 44px;
      grid-template-rows: 44px 44px;
    }
  }

  /* DIE ZEHN KÄSTCHEN BRECHEN UM. Auf dem Tablet stehen die zwei
     Fünfergruppen nebeneinander — das sind 552 und passt dort.
     Mobil wären es 552 auf 353: die Eingabe lief bei 320 um 153
     über den Rand hinaus. In Figma stehen sie untereinander,
     zwei Zeilen à 272 mit 8 Abstand (13871:70172). */
  .code-eingabe {
    flex-direction: column;
  }
}

/* ============================================================
   OFFEN — QR mobil
   ------------------------------------------------------------
   · In Figma trägt der Knopf links oben mobil einen PFEIL
     („Back icon Button"), im Prototyp steht dort ein ✕. Das ist
     kein Maß, sondern eine Bedeutung: nach §19.1 geht ← einen
     Schritt zurück und ✕ schließt. Beides je Breakpoint anders
     wäre ein Widerspruch — deshalb bleibt hier vorerst das ✕,
     bis entschieden ist, was für beide gilt.
   · Der Frame „scanner.codeInput" zeigt eine Tastatur (393 x 318)
     und einen Scrim über dem Screen. Die Tastatur ist in Figma
     ein Bild des Systems; auf einem echten Gerät bringt sie das
     Betriebssystem selbst mit, und die Karte wandert nach oben —
     das tut sie im Prototyp bereits (Regel bei max-height 700).
     Nachgebaut wird sie nicht.
   ============================================================ */

/* ============================================================
   MOBIL — Bottom Nav statt Navigationsstreifen
   ------------------------------------------------------------
   Quelle: Figma „Bottom Nav" 11136:1399, Variante „vor ort"
   (11136:1400), 393 x 105, ausgelesen am 08.09.2026.

   Bis 767 steht die Navigation unten, ab 768 links als Streifen.
   Sichtbar ist immer genau eine von beiden; beide tragen
   dieselben data-tab-Werte und laufen durch denselben
   Umschalter.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     105       Höhe des ganzen Rahmens.
     81        Höhe der Bar. Die 24 darüber sind Luft für die
               Bubble, die über die Oberkante hinausragt.
     72 x 62   Ein Feld. Vier davon bei x 24, 115, 206, 297 —
               Rand 24, Abstand 19.
     22        Unterkante des Symbols im Ruhezustand, gemessen
               von der Oberkante des Feldes.
     30        Oberkante der Beschriftung, 18 hoch.
     40        Durchmesser der Bubble.
   ------------------------------------------------------------ */

/* Ab 768 gibt es die Bottom Nav nicht. */
.app-gestell__nav {
  display: none;
}

@media (max-width: 767px) {

  /* Der Streifen verschwindet, und mit ihm sein Einzug. */
  .app-gestell__rail {
    display: none;
  }

  .app-gestell__inhalt {
    margin-left: 0;
  }

  /* MOBIL GIBT ES KEINEN STREIFEN, und der Rand ist 20.
     Ohne diese Zeilen begann die Toast-Schicht bei 112 + 20 =
     132 statt bei 20 — die Breite des Streifens, den es hier gar
     nicht gibt. Nachgemessen am 14.09.2026 bei 393: Toast von
     132 bis 373. */
  .toast-schicht {
    --toast-rand: var(--layout-screen-margin);   /* 20 */
    left: calc(var(--buehne-links) + var(--toast-rand));

    /* DER ABSTAND NACH UNTEN STEHT SEIT DEM 15.09.2026 IN DER
       KOMPONENTE: `calc(var(--nav-h, 0px) + var(--space-sm))`,
       nach §20.1a. Hier stand dieselbe Rechnung einen Nachmittag
       lang; sie ist ersatzlos weg. Der Prototyp liefert nur noch
       --nav-h, gemessen in prototyp.js. */
  }

  /* Die Bar hängt am unteren Rand der Bühne — nicht am Fenster:
     bei einem breiteren Fenster steht die Bühne mittig, und eine
     am Fenster ausgerichtete Bar liefe darüber hinaus. */
  .app-gestell__nav {
    display: flex;
    position: fixed;
    bottom: 0;
    left: var(--buehne-links);
    width: min(100%, var(--prototyp-max));
    z-index: 10;

    /* 81 hoch, und die Felder sitzen darin. Das Polster oben
       trägt nicht die Bubble — die ragt darüber hinaus und liegt
       außerhalb der Bar. */
    /* Die Höhe ergibt sich: 15,85 + 62 + 3,15 = 81. Sie steht
       trotzdem da, weil die Bar am unteren Rand hängt und ein
       fehlerhaft gewachsener Inhalt sonst still nach oben liefe.
       Die Polster oben und unten kommen aus nav.css. */
    height: var(--nav-bar-h);
    padding-inline: var(--space-lg);         /* 24, gemessen */

    /* DER ABSTAND WÄCHST MIT, DIE FELDER NICHT. Vorher standen
       hier feste 19 — das ergibt zusammen mit 4 x 72 und 2 x 24
       genau 393 und stimmt nur dort. Auf einem breiteren Fenster
       klebte alles links (Lisi, 08.09.2026).

       space-between rechnet den Abstand aus, was übrig bleibt.
       Bei 393 sind das (393 − 48 − 288) / 3 = exakt die 19 aus
       Figma; darüber werden die Lücken größer und die Reihe
       bleibt mittig verteilt. */
    justify-content: space-between;
    gap: 0;

    /* Die Bubble ragt oben heraus und darf nicht abgeschnitten
       werden. */
    overflow: visible;
  }

  /* Ein Feld: 72 breit, 62 hoch, oben im 81er Kasten. Nicht
     flex:1 — die vier Felder stehen in Figma nicht auf gleiche
     Teile verteilt, sondern mit festem Maß und festem Abstand. */
  .app-gestell__nav .nav__item {
    flex: 0 0 72px;
    height: 62px;
    justify-content: flex-start;
    gap: 0;
    padding-block: 0;
  }

  /* Das Symbol steht mit seiner UNTERKANTE auf 22 — deshalb ein
     Kasten von 22 und der Inhalt unten hinein. Darunter beginnt
     bei 30 die Beschriftung, also 8 Abstand. */
  .app-gestell__nav .nav__icon {
    height: 22px;
    align-items: end;
    margin-bottom: var(--space-xs);          /* 8 */
  }

  /* JEDES SYMBOL HAT SEIN EIGENES MASS. Vorher standen alle auf
     26 — das war die Größe des Kompass, und die anderen drei
     wurden damit zu groß gegenüber der Bubble (Lisi,
     08.09.2026). Gemessen an Figma 11136:1400. */
  .app-gestell__nav .nav__ikon {
    display: block;
  }

  .app-gestell__nav [data-tab="vorort"] .nav__ikon {
    width: 17.11px;
    height: 22px;
  }

  .app-gestell__nav [data-tab="entdecken"] .nav__ikon {
    width: 26px;
    height: 26px;
  }

  .app-gestell__nav [data-tab="inhalte"] .nav__ikon {
    width: 18px;
    height: 18px;
  }

  .app-gestell__nav [data-tab="meinetitel"] .nav__ikon {
    width: 21.03px;
    height: 20px;
  }

  /* Aktiv und Ruhe sind zwei Zeichnungen, wie im Streifen.

     JEDE TRÄGT IHRE FARBE SELBST. motion.css blendet die Farbe
     am Wrapper .nav__icon über — gedacht für EIN Icon, das
     seine Farbe wechselt. Bei zwei Zeichnungen erscheint die
     gefüllte sofort, hängt aber noch an der alten Farbe: für
     einen Moment war das Symbol WEISS GEFÜLLT. Diesen Zustand
     darf es nicht geben, es gibt nur weiß-outline oder
     schwarz-gefüllt (Lisi, 08.09.2026).

     Mit einer eigenen Farbe am SVG greift die Überblendung des
     Wrappers nicht mehr durch. */
  .app-gestell__nav .nav__ikon--ruhe  { color: var(--nav-icon); }
  .app-gestell__nav .nav__ikon--aktiv { color: var(--nav-icon-active); }

  .app-gestell__nav .nav__ikon--aktiv { display: none; }
  .app-gestell__nav .nav__item[aria-current="page"] .nav__ikon--ruhe { display: none; }
  .app-gestell__nav .nav__item[aria-current="page"] .nav__ikon--aktiv { display: block; }

  /* Das aufsteigende Symbol. Wie weit, rechnet prototyp.js aus
     der gemessenen Geometrie — nur so landet es im Mittelpunkt
     der Bubble, unabhängig davon, wie hoch das einzelne Zeichen
     ist (nav.css sagt das ausdrücklich). */
  .app-gestell__nav .nav__item[aria-current="page"] .nav__icon {
    transform: translateY(calc(-1 * var(--nav-rise, 14px)));
  }

  /* Seitenrand 20 statt 24, und unter dem letzten Inhalt bleibt
     Platz für die Bar. Die 20 stehen so in Figma: der Container
     auf „Entdecken Mobile" beginnt bei x 20 und ist 353 breit
     (1678:13409). --sektion-rand geht mit, sonst laufen die
     Cover-Reihen um 4 zu weit nach rechts. */
  .app-screen {
    --sektion-rand: var(--layout-screen-margin);
    padding-inline: var(--layout-screen-margin);
    padding-bottom: calc(var(--nav-bar-h) + var(--space-lg));
  }
}

/* UNTER 393 GIBT DIE REIHE NACH. Die festen 72 mit 19 Abstand und
   24 Rand ergeben zusammen genau 393 — das ist das Maß des
   Figma-Frames und stimmt dort auf den Punkt. Auf einem
   schmaleren Gerät stünde das vierte Feld 73 px über den Rand
   hinaus.

   Darunter teilen sich die vier deshalb den Platz, so wie
   nav.css es von sich aus tut (flex: 1), mit kleinerem Abstand
   und kleinerem Rand. Bei 320 bleiben 68 je Feld — „Meine
   Titel" misst 62,6 und passt einzeilig hinein.

   Diese Werte stehen in keinem Figma-Frame: für 320 gibt es
   keinen. Sie sind so gewählt, dass die längste Beschriftung
   gerade noch einzeilig bleibt. */
@media (max-width: 392px) {
  .app-gestell__nav {
    padding-inline: var(--space-sm);         /* 12 statt 24 */
    gap: var(--space-xs);                    /* 8 */
    justify-content: flex-start;
  }

  /* Zu gleichen Teilen — flex-basis 0, nicht auto. Mit auto
     wächst jedes Feld von seiner Textbreite aus, und die vier
     wären 59, 77, 55 und 80 breit statt gleich. */
  .app-gestell__nav .nav__item {
    flex: 1 1 0;
    min-width: 0;
  }
}

/* ============================================================
   MOBIL — Inhalte als Voll-Screen
   ------------------------------------------------------------
   Quelle: Figma „Inhalte Screen — Voll-Screen (8 Kategorien)",
   11775:8824, 393 x 1047, ausgelesen am 08.09.2026.

   AUF DEM TABLET IST ES EIN PANEL, MOBIL EIN SCREEN. Auf dem
   Tablet liegt es als 416 breite Fläche rechts neben dem
   Streifen, mit ✕ oben rechts. Mobil füllt es die Breite und
   endet über der Bottom Nav — die Bar bleibt stehen.

   DESHALB FÄLLT DAS ✕ WEG. §19: solange die Navigation steht,
   gibt es kein ✕ — man geht über einen anderen Tab hinaus, oder
   über „Inhalte" ein zweites Mal. Ein ✕ neben einer sichtbaren
   Navigation behauptet, es gäbe etwas zu schließen, das gar
   nicht verdeckt.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     353 x 36   Suchleiste, schmale Fassung.
     16         Abstand von oben bis zur Suchleiste.
     76         Abstand Suchleiste → Überschrift (Figma y 16→76,
                also 24 unter der 36 hohen Leiste).
     353 x 57   Kopf: „Inhalte" 32 + 4 + Unterzeile 21.
     157        Beginn der Liste, also 24 unter dem Kopf.
     76 / 12    Zeile und Abstand — unverändert zum Tablet.
   ------------------------------------------------------------ */

/* Auf dem Tablet gibt es die Suchleiste im Panel nicht. */
.inhalte-overlay__suche {
  display: none;
}

@media (max-width: 767px) {

  .inhalte-overlay {
    /* Volle Breite statt 416 neben dem Streifen. */
    left: 0;
    width: 100%;
    max-width: none;
    padding-inline: var(--layout-screen-margin);   /* 20 */

    /* ES GEHT BIS GANZ NACH UNTEN, NICHT BIS ÜBER DIE BAR
       (09.09.2026, Lisi: „bei inhalte sieht man noch immer cover
       unten durch. da sollte nichts durscheinen bei mobile").

       Vorher endete das Panel bei 81, also genau an der
       Oberkante der Bar. Damit lag hinter der Bar UND hinter
       ihrem Verlaufsband weiter der Screen, von dem man kam —
       und weil das Band den Hintergrund weichzeichnet und nur
       teilweise verdeckt, schimmerten dort dessen Cover durch.

       Mobil ist „Inhalte" aber ein eigener Screen, und ein
       Screen endet am Screenrand. Die Bar liegt darauf, nicht
       daneben: sie steht auf z-index 10, das Panel auf 9, sie
       bleibt also sichtbar und bedienbar. Hinter dem Band liegt
       jetzt die eigene Fläche des Panels — dort kann nichts mehr
       durchscheinen, unabhängig davon, wie der Browser die
       Ebenen zusammenrechnet. */
    bottom: 0;
  }

  /* Dafür braucht die Liste unten Platz: die letzte Karte muss
     über die Bar hinausscrollen können. 24 wie oben, plus die
     81 der Bar. */
  .inhalte-overlay ul.inhalte-overlay__liste {
    padding-bottom: calc(var(--space-lg) + var(--nav-bar-h));
  }

  /* KEIN SCRIM. Ein Scrim sagt: dahinter liegt noch der Screen,
     von dem du kommst. Mobil liegt dort nichts mehr — das Panel
     IST der Screen und deckt alles ab. Sichtbar wäre er ohnehin
     nur die 250 ms, in denen das Panel aufblendet, und genau
     dort las er als dunkles Aufblitzen. */
  .scrim--inhalte {
    display: none;
  }

  /* ----------------------------------------------------------
     ES FÄHRT NICHT MEHR HEREIN, ES ERSCHEINT
     ----------------------------------------------------------
     Auf dem Tablet ist „Inhalte“ ein Panel: es kommt hinter dem
     Navigationsstreifen hervor, aus der Richtung, aus der man es
     aufgerufen hat. Das Hereinfahren erzählt dort, dass der
     Screen dahinter stehen bleibt.

     Mobil gibt es den Streifen nicht. „Inhalte“ ist dort ein
     eigener Screen wie Vor Ort oder Entdecken — und ein Screen
     kommt nicht von der Seite hereingeschoben, sonst wäre er das
     einzige Ziel der Bottom Nav, das sich anders verhält als die
     drei anderen.

     Deshalb hier dieselbe Bewegung wie beim Screenwechsel
     (Abschnitt 2a): aufblenden und ein Stück nach oben gleiten,
     250 ms, --motion-ease-out. Es sind wörtlich dieselben Werte
     — nur als Transition geschrieben statt als Animation, weil
     das Panel über eine Klasse geschaltet wird und nicht über
     [hidden].
     ---------------------------------------------------------- */
  .inhalte-overlay {
    transition:
      opacity   calc(var(--motion-dialog) * var(--motion-scale)) var(--motion-ease-out),
      transform calc(var(--motion-dialog) * var(--motion-scale)) var(--motion-ease-out);
  }

  .inhalte-overlay.is-zu {
    opacity: 0;
    transform: translateY(var(--screen-gleiten));
  }

  .inhalte-overlay__suche {
    display: flex;
    flex: 0 0 auto;
    margin-top: var(--space-md);           /* 16, gemessen */
  }

  /* Der Kopf steht 24 unter der Leiste und trägt kein ✕ mehr. */
  .inhalte-overlay__kopf {
    padding-top: var(--space-lg);          /* 24, gemessen */
  }

  .inhalte-overlay__kopf .ikon-button {
    display: none;
  }

  /* H1 STATT H3. Auf dem Tablet ist „Inhalte" die Überschrift
     eines Panels neben dem Streifen und trägt H3. Mobil ist es
     die Überschrift eines ganzen Screens: der Textknoten in
     Figma ist 32 hoch, das ist H1 mobil (29 / 31,9). Damit wird
     der Kopf 57 hoch und die Liste beginnt bei 157 — beides so
     gemessen. */
  .inhalte-overlay__titel {
    font-size: var(--font-size-h1);
    line-height: var(--line-height-h1);
  }
}

/* ============================================================
   MOBIL — Leiste oben mit Logo
   ------------------------------------------------------------
   Quelle: Figma „Top Navigation with Logo", 12945:33855,
   393 x 69, ausgelesen am 08.09.2026. Sie steht in jedem
   mobilen Frame am Kopf.

   AUF DEM TABLET GIBT ES SIE NICHT: dort trägt der
   Navigationsstreifen links das Logo, und das Zahnrad steht in
   der Kopfzeile neben der Suchleiste. Mobil fällt der Streifen
   weg — Logo und Zahnrad wandern nach oben, und die Suchleiste
   bleibt allein und schmal darunter.

   SIE STEHT FEST, WIE DIE BAR UNTEN. Im Frame ist sie oben
   angeschlagen; ob sie mitscrollt, sagt ein statischer Frame
   nicht. Fest ist die Entsprechung zum Tablet, wo der Streifen
   auch immer steht — und das Inhalte-Panel braucht eine feste
   Oberkante, an der es beginnen kann.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     69       Höhe. 24 oben + 45 Inhalt.
     79 x 45  Wortmarke, links bei x 20.
     45 x 45  Zahnrad, rechts bündig bei x 328 (373 = 393 − 20).
     16       Abstand von der Leiste zum Inhalt (Container y 85).
   ------------------------------------------------------------ */

/* AUCH AUF DEM TABLET (Lisi, 14.09.2026, mit Verweis auf
   examples/scroll-verhalten-alle-screens.html): „Gleiche Regel.
   Das Logo sitzt in der Rail und ist von der Kopfzeile
   unabhängig — dort stellt sich die Platzfrage nicht."

   Bis dahin gab es die Leiste nur mobil; auf dem Tablet scrollte
   die Kopfzeile mitsamt Suche weg und oben blieb nichts. Die
   Demo zeigt beide Breiten mit derselben festen Zeile.

   Zwei Unterschiede zum Telefon, beide aus der Lage:
     · Die Wortmarke entfällt — sie steht im Streifen.
     · Die Leiste beginnt rechts vom Streifen, nicht am Bühnenrand.
   ------------------------------------------------------------ */
.app-gestell__topbar {
  display: flex;

  position: fixed;
  top: 0;
  left: calc(var(--buehne-links) + var(--nav-rail-breite));
  width: min(
    calc(100% - var(--nav-rail-breite)),
    calc(var(--prototyp-max) - var(--nav-rail-breite))
  );
  z-index: 10;
}

/* Das Logo steht im Streifen, nicht in der Zeile. */
.app-gestell__topbar .wortmarke {
  display: none;
}

/* BÜNDIG MIT DEM INHALT DARUNTER. Die Komponente polstert
   seitlich mit dem Screen-Rand (20); auf dem Tablet steht der
   Inhalt aber bei 24. Vier Pixel Versatz sieht man, sobald der
   Knopf über dem Banner steht. */
.app-gestell__topbar {
  padding-inline: var(--space-lg);         /* 24 */
}

/* ALLES RECHTS (Lisi, 14.09.2026: „alles rechts ausgerichtet
   wenn man scrollt").

   Die Komponente verteilt mit `space-between` — mobil sitzt so
   die Wortmarke links und die Knöpfe rechts. Auf dem Tablet
   steht die Wortmarke im Streifen und ist hier ausgeblendet;
   damit bleibt EIN Kind übrig, und `space-between` legt ein
   einzelnes Kind an den ANFANG. Die Knöpfe standen dadurch links
   an der Inhaltskante statt am rechten Rand.

   Die Demo löst dasselbe mit zwei Platzhaltern vor den Knöpfen
   (`<div class="spacer">` zweimal). Ein Platzhalter ist Markup
   ohne Inhalt; hier reicht die Ausrichtung. */
.app-gestell__topbar {
  justify-content: flex-end;
}

/* Der Inhalt beginnt unter der Leiste. --topbar-h misst
   prototyp.js. */
.app-screen {
  padding-top: calc(var(--topbar-h, 73px) + var(--space-md));
}

/* Das Zahnrad ist nach oben gewandert — in der Kopfzeile bleibt
   die Suchleiste allein. */
.kopfzeile > .ikon-button {
  display: none;
}

/* SCREENS MIT EIGENEM KOPF BEKOMMEN KEINE LEISTE DARÜBER.

   Ausgewählt über `data-eigener-kopf` und nicht über den Namen
   des Screens: seit dem 14.09.2026 gibt es zwei davon — die
   Kategorie-Seite und die Zeitungen-Übersicht darunter —, und
   eine Regel, die Namen aufzählt, vergisst beim dritten einen.

   DIE KATEGORIE-SEITE BEHÄLT IHREN EIGENEN KOPF. Sie trägt ←
   und Titel im Screen und kein Logo (Figma 13826:41714); eine
   Leiste mit Zahnrad darüber wäre ein zweiter Kopf. Dieselbe
   Ausnahme wie mobil.
   ZU KLÄREN: die Demo zeigt für die Kategorieseite eine feste
   Zeile mit ← und Titel und klebende Chips. Das ist ein eigener
   Umbau, hier noch nicht gebaut. */
.app-gestell:has([data-eigener-kopf]:not([hidden]))
.app-gestell__topbar {
  display: none;
}

/* Kein Polster oben — die feste Zeile bringt ihre 16 selbst mit
   und klebt an der Fensterkante (14.09.2026, vorher 24). */
.app-gestell:has([data-eigener-kopf]:not([hidden]))
[data-eigener-kopf] {
  padding-top: 0;
}

/* Das Inhalte-Panel beginnt unter der Leiste, nicht am
   Screenrand — sonst liegt sein erstes Element dahinter. Seit
   die Leiste auch auf dem Tablet steht (14.09.2026), gilt das
   für beide Breiten. */
.inhalte-overlay,
.scrim--inhalte {
  top: var(--topbar-h, 73px);
}

@media (max-width: 767px) {

  /* NUR NOCH DIE LAGE. Aussehen, Trennlinie und das einblendende
     Such-Icon stehen seit dem 09.09.2026 in
     components/topbar.css — die Regel gehört ins System, nicht in
     einen Prototypen (Lisi: „ergänze auch sharemagazines-base
     falls dort sachen nicht definiert sind, damit die nicht
     wieder beim nächsten prototyp als fehler bleiben").

     Hier bleibt, was nur für diesen Prototypen gilt: die Leiste
     hängt an der BÜHNE, nicht am Fenster. Bei einem breiteren
     Fenster steht die Bühne mittig, und eine am Fenster
     ausgerichtete Leiste liefe darüber hinaus — dieselbe
     Rechnung wie bei der Bottom Nav.

     Die Höhe steht nirgends fest; sie kommt aus dem Inhalt. Wer
     sie braucht, liest --topbar-h (setzt prototyp.js). */
  .app-gestell__topbar {
    /* Mobil gibt es keinen Streifen: die Leiste beginnt am
       Bühnenrand und trägt die Wortmarke. */
    left: var(--buehne-links);
    width: min(100%, var(--prototyp-max));
  }

  .app-gestell__topbar .wortmarke {
    display: flex;
  }

  /* Mobil ist der Screen-Rand 20, und die Komponente bringt ihn
     selbst mit. Und die Wortmarke steht wieder in der Zeile:
     damit gibt es zwei Kinder, und `space-between` aus der
     Komponente stimmt wieder — Logo links, Knöpfe rechts. */
  .app-gestell__topbar {
    padding-inline: var(--layout-screen-margin);
    justify-content: space-between;
  }

  /* Der Inhalt beginnt unter der Leiste, plus 16 Abstand (Figma:
     Container bei y 85). Die Höhe der Leiste steht nicht mehr
     fest im CSS — prototyp.js misst sie und schreibt sie als
     --topbar-h. Der Rückfallwert ist die Rechnung aus der Demo:
     16 + 45 + 12. */
  .app-screen {
    padding-top: calc(var(--topbar-h, 73px) + var(--space-md));
  }

  /* Das Zahnrad ist nach oben gewandert — in der Kopfzeile
     bleibt nur die Suchleiste, und die ist schmal und über die
     ganze Breite (Figma 9018:8518, 353 x 36). */
  .kopfzeile > .ikon-button {
    display: none;
  }

  .kopfzeile .suchleiste {
    height: 36px;
  }

}

/* ============================================================
   MOBIL — Kopfzeile beim Scrollen
   ------------------------------------------------------------
   Quelle: sharemagazines-base/examples/scroll-verhalten-alle-
   screens.html (die Regel steht dort im Klartext, mit Demo).

     „Das große Suchfeld scrollt weg, ein Such-Icon blendet in
      der festen Zeile ein. Nichts animiert seine Höhe, deshalb
      springt nichts."

     „Das Logo weicht nicht dem Scrollen, sondern der Aktion."

   DAS LOGO BLEIBT HIER STEHEN. Es weicht nur, wenn etwas Neues
   in die Zeile kommt und der Platz sonst nicht reicht — in der
   Doku ist das der Zugangs-Button auf „Entdecken · Ziel B", also
   OHNE aktiven Zugang. Im Prototyp ist der Zugang aktiv
   („Frisör Mustermann · aktiv"), das ist Ziel A: nichts kommt
   hinzu, das Logo bleibt.

   VOR ORT ÄNDERT SICH NICHTS. Dort gibt es kein großes Suchfeld
   — die Suche ist schon bei Position 0 ein Icon in der Zeile.
   Das ist keine Ausnahme, sondern dieselbe Regel mit anderem
   Ergebnis: es ist nichts da, was kollabieren könnte.

   ------------------------------------------------------------
   WERTE AUS DER DEMO
     0,85 → 1   Skalierung des Such-Icons beim Einblenden.
     0 → 1      Deckkraft, an den Scroll-Fortschritt gekoppelt.
     p > 0,6    ab hier ist es bedienbar.
   ------------------------------------------------------------ */

@media (max-width: 767px) {

  /* Die Aktionen-Zeile, das einblendende Such-Icon und seine
     Skalierung stehen in components/topbar.css. */

  /* Vor Ort und Meine Titel: kein großes Feld, also auch keine
     Kopfzeile mit Suchleiste — das Icon oben ist die Suche.

     MEINE TITEL KAM AM 09.09.2026 DAZU (Lisi: „meine titel
     sollte so sein wie vor ort mit kleinem search icon"). Der
     Rahmen bestätigt es: die Instanz „Top Navigation with Logo"
     trägt dort die Variante mit Suchknopf (46 x 45) und Zahnrad
     (45 x 45, Abstand 8), und darunter folgt sofort der
     Seitentitel — kein Feld (Figma 13994:35338 / 13994:35340).
     Auf Inhalte trägt dieselbe Komponente dagegen NUR das
     Zahnrad, weil dort die schmale Leiste darunter steht
     (12895:17323). */
  [data-tab-screen="vorort"] .kopfzeile,
  [data-tab-screen="meinetitel"] .kopfzeile {
    display: none;
  }

  /* DIE KATEGORIE-SEITE HAT KEINE LOGO-LEISTE (Figma
     13826:41714, „Magazine und Zeitungen / Category"). Sie
     beginnt bei 24 mit ← und dem Titel, darunter die Suchzeile
     und die Chips. Ein Logo steht dort nicht — es ist eine
     Seite in einer Kategorie, kein Einstieg.

     Die Leiste wird ausgeblendet, und der Screen verliert seinen
     Platzhalter dafür: statt 69 + 16 bleiben die 24 aus dem
     Rahmen. */
  /* ES SEI DENN, DAS INHALTE-PANEL LIEGT DARÜBER (09.09.2026).
     Das Panel ist mobil ein eigener Screen MIT Logo-Leiste; es
     beginnt bei --topbar-h. Fehlte die Leiste, klaffte über dem
     Panel ein 73 px hoher Streifen, in dem der Kopf der
     Kategorie-Seite stehenblieb — zu sehen, wenn man von einer
     Kategorie aus wieder auf „Inhalte" tippt.

     Das :not(.is-zu) nimmt die Leiste im selben Augenblick
     zurück, in dem das Panel zu verblassen beginnt: was
     zurückkommt, ist die Kategorie-Seite, und die hat keine
     Leiste. Ohne das bliebe sie 250 ms zu lang stehen und
     verschwände dann mit einem Sprung. */
  body:not(:has(.inhalte-overlay:not([hidden]):not(.is-zu)))
  .app-gestell:has([data-eigener-kopf]:not([hidden]))
  .app-gestell__topbar {
    display: none;
  }

  /* KEIN POLSTER OBEN: das bringt die feste Zeile selbst mit
     (16), und sie muss bis an die Fensterkante kleben können.
     Bis zum 14.09.2026 standen hier 24. */
  [data-eigener-kopf] {
    padding-top: 0;
  }

  /* MOBIL UND TABLET SIND JETZT GLEICH GEBAUT. Bis zum
     14.09.2026 war der Kopf mobil ein zweizeiliges Raster (←
     und Titel oben, Suchzeile darunter), auf dem Tablet stand
     alles in einer Zeile.

     Das geht nicht mehr: die Suchzeile SOLL wegscrollen, und
     etwas, das neben dem Titel klebt, kann das nicht. Sie steht
     jetzt auf beiden Breiten unter der festen Zeile — womit die
     mobile Sonderregel von selbst wegfällt. Seit dem 15.09.2026
     ist auch die Breite keine Ausnahme mehr: die Zeile läuft auf
     beiden Breiten von Kante zu Kante, hier bleibt also gar
     nichts mehr zu regeln.

     Der Titel bekommt seine Auslassungspunkte zurück. In der
     festen Zeile stehen mobil neben ihm ← und zwei Zeichen; bei
     langen Kategorienamen kürzt er, so wie es die Demo für die
     Kategorieseite vorsieht. */
}

/* DAS SUCH-ICON STEHT AUF BEIDEN BREITEN (Lisi, 14.09.2026:
   „suche ist neben den einstellungen und alles rechts
   ausgerichtet wenn man scrollt").

   Hier stand bis dahin `display: none` mit der Begründung, auf
   dem Tablet gebe es die Leiste gar nicht. Das stimmte, solange
   die Leiste mobil war. Seit sie auf beiden Breiten steht, ist
   die Begründung hinfällig — und die Regel hat das Icon
   ausgeblendet, obwohl die Zeile da war: auf dem Tablet blieb
   beim Scrollen nur das Zahnrad übrig.

   Die Demo (examples/scroll-verhalten-alle-screens.html) zeigt
   für beide Breiten dieselbe Reihenfolge:
   Zugangs-Knopf · Such-Icon · Zahnrad. Es gibt also nichts mehr
   auszublenden — deshalb steht hier jetzt gar keine Regel. */

/* ============================================================
   MOBIL — Vor Ort
   ------------------------------------------------------------
   Quelle: Figma „Vor Ort — Einstieg ‚Wie funktioniert
   sharemagazines' (SOLL)", 13896:15580, 393 x 1533, ausgelesen
   am 08.09.2026.

   ÜBERNOMMEN IST DIE ANORDNUNG, NICHT DER INHALT. Der Frame
   erzählt ein Klinikum, der Prototyp durchgehend einen
   Friseursalon — Entscheidung Lisi, 08.09.2026: Friseursalon
   bleibt.

   Was sich mobil ändert: alles steht untereinander statt
   nebeneinander, und das Bild in der Angebotskarte wird breiter
   als hoch gerechnet, weil die Karte jetzt die volle Breite hat.

   ------------------------------------------------------------
   GEMESSENE MASSE OHNE TOKEN-GRUNDLAGE
     353 x 220     Hero. Auf dem Tablet 674 x 220.
     353 x 166,8   Bild in der Angebotskarte. Auf dem Tablet
                   331 x 166,8 — dieselbe Höhe, andere Breite.
     48            Abstand zwischen den Blöcken.
     12            Abstand zwischen den beiden Knöpfen.
   ------------------------------------------------------------ */

@media (max-width: 767px) {

  /* Der Hero ist breiter geworden, aber gleich hoch geblieben. */
  .vorort__hero {
    aspect-ratio: 353 / 220;
  }

  /* Die zwei Knöpfe stehen untereinander und nehmen die Breite.
     Nebeneinander wäre „So funktioniert's" bei 353 zweizeilig. */
  .vorort__cta {
    flex-direction: column;
    align-items: stretch;
  }

  /* Die Angebote stehen untereinander, mit 48 dazwischen — wie
     zwischen allen Blöcken auf diesem Screen. */
  .vorort__angebote {
    flex-direction: column;
    gap: var(--space-2xl);                 /* 48, gemessen */
  }

  /* UND SIE BRAUCHEN IHRE EIGENE HÖHE ZURÜCK. Die Karte trägt
     `flex: 1 1 0` — gedacht für die Reihe auf dem Tablet, wo die
     0 als Startbreite dafür sorgt, dass zwei Karten gleich breit
     werden. Untereinander ist die Hauptachse aber die HÖHE, und
     dieselbe 0 heißt dort: Starthöhe null.

     Wachsen konnten sie nicht, weil der Container keine feste
     Höhe hat und es also nichts zu verteilen gibt. Beide Karten
     standen damit auf 0 und waren mobil unsichtbar — der
     Container war genau 48 hoch, die Lücke zwischen zwei
     Nullen. Gefunden am 10.09.2026 beim Bauen der WLAN-Fassung;
     der Fehler ist älter.

     `0 0 auto` heißt: nimm die Höhe deines Inhalts. */
  .vorort__angebote .inhalt-karte {
    flex: 0 0 auto;
  }

  /* Volle Breite statt halbe: das Bild wird dadurch flacher. */
  .vorort__angebote .inhalt-karte__bild {
    aspect-ratio: 353 / 166.807;           /* gemessen, siehe Kopf */
  }
}

/* ============================================================
   OFFEN — Vor Ort mobil
   ------------------------------------------------------------
   · Der Frame hat unter den zwei Angebotskarten noch zwei
     „Article Item" — 145 hoch, Bild links 104 breit, Titel und
     Text rechts. Sie sind im Prototyp nicht angelegt: es gibt
     dafür weder Inhalt noch Bilder im Friseursalon-Strang.
     Struktur steht im README, Inhalt fehlt.
   · Die Standort-Karte zeigt im Frame die Variante „wifi"
     („Mit WLAN verbunden"), der Prototyp die mit Admin-Zugang.
     Beides sind Zustände desselben Screens.
   ============================================================ */

/* ============================================================
   MOBIL — Intro, Nachbesserung (08.09.2026)
   ------------------------------------------------------------ */

@media (max-width: 767px) {

  /* DER TEXT MUSS ÜBER DER ILLUSTRATION LIEGEN. Auf Folie 1
     beginnt die Szene bei 166, der Textblock endet bei 222 —
     sie überlappen um 57. Die Szene ist absolut gesetzt, der
     Text nicht: beim Zeichnen gewann die Szene, und der Titel
     war ganz weg (Lisi, 08.09.2026). Dieselbe Regel wie auf
     Folie 3, nur dort stand sie schon. */
  .intro__folie > :not(.intro-szene):not(.intro__kulisse):not(.intro__bild-mobil) {
    position: relative;
    z-index: 1;
  }

  /* Kein Polster oben — in Figma beginnt der Textblock direkt
     unter der Kopfzeile (Container y 0). Galt bisher nur für
     Folie 3. */
  .intro__folie {
    padding-block: 0;
  }

  /* DIE ZWEI WEGE STEHEN UNTEREINANDER. Nebeneinander sind sie
     bei 353 je 170 breit, und beide Beschriftungen brechen
     mehrzeilig um („Mit dem WLAN / verbinden", „Vor Ort ins /
     WLAN einloggen"). */
  .intro__wege {
    flex-direction: column;
  }

  .intro__weg {
    width: 100%;
  }
}

/* ============================================================
   Suchscreen — was mobil anders ist
   ------------------------------------------------------------
   Quelle: Figma „Screens: App und Web", am 09.09.2026 an allen
   vier ausgewählten Rahmen nachgemessen:
     mobil    Start 2143:21548 · Kategorie gewählt 2000:17568
     Tablet   Start 13970:16656 · Kategorie gewählt 13970:16788

   FAST ALLES IST AUF BEIDEN BREAKPOINTS GLEICH. Am Rahmen
   abgelesen, jeweils vom oberen Rand des Screens:

                                   mobil   Tablet
     Kopfzeile beginnt bei            36       48
     Kopfzeile → erster Block         24       24
     zwischen den Blöcken             48       48
     Titel → Liste                    36       36
     Titel → Abkürzungen / Chips      16       16
     Suchleiste → Kategorie-Chip      16       16
     Seitenrand                       20       24

   Es bleiben also genau zwei Unterschiede: wo die Kopfzeile
   beginnt und wie breit der Seitenrand ist. Alles andere steht
   als Grundregel weiter oben und in suchliste.css.

   Bis zum 09.09.2026 stand hier ein ganzer Mobil-Block, weil das
   Tablet noch auf 24/24/12 lief. Das war aus einem Screenshot
   abgelesen; jetzt sind beide gemessen und tragen dieselbe
   Ordnung.
   ------------------------------------------------------------ */

@media (max-width: 767px) {

  /* 20 statt 24 (Container x 20, 353 breit). */
  .suche {
    padding-inline: var(--layout-screen-margin, 20px);
  }

  /* 36 statt 48 bis zur Kopfzeile. Unten bleiben die 24. */
  .suche__kopf {
    padding-block: var(--space-xl) var(--space-lg);
  }
}

/* ============================================================
   OFFEN — Suchscreen
   ------------------------------------------------------------
   · Erledigt am 09.09.2026: die Blocktitel. Es war nicht der
     falsche Wert, sondern der falsche Stil — H3 in der
     Display-Familie statt Inter „title text". Siehe
     .suche__titel.
   · Erledigt am 09.09.2026: der Kategorie-Chip ist auf dem
     Tablet 48, mobil 45. Steht so in chip.css.
   · Erledigt am 09.09.2026: die Beschriftung der Abkürzungen ist
     regular, nicht bold (shortcut.css).
   · Drei Medienarten sind richtig (Lisi, 09.09.2026). Der Rahmen
     zeigt mobil acht, auf dem Tablet drei; der Prototyp bleibt
     bei drei. Die Reihe scrollt trotzdem, sobald mehr
     dazukommen.
   · Erledigt am 09.09.2026: die Abkürzungsreihe war 110 hoch
     statt 104, weil die Beschriftung in Figma auf 1,25 stand und
     hier auf dem Token 1,5. Der Stil dort war ein Überbleibsel
     („Bottom Navigation", den die Bottom Nav nicht benutzt);
     Lisi hat die Ebenen auf `small text` gestellt. Am Master
     nachgemessen: 75 x 89, Beschriftung 21 hoch. Damit stimmt
     der Prototyp ohne Änderung.
   · DIE TEXTKÄSTEN DER TABLET-TITEL SIND NICHT MITGEWACHSEN.
     Die drei Überschriften sind in beiden Tablet-Rahmen
     131 x 23 — dieselben Maße wie im mobilen Rahmen. Bei 22 px
     kann das nicht sein: „Häufig gesucht" wäre rund 152 breit
     und 27 hoch. Der Kasten steht also auf alten Maßen.

     Der Mode ist dabei NICHT das Problem, anders als ich zuerst
     gemeldet hatte: an den Variablen nachgesehen löst der
     mobile Knoten H3 auf 19 / 22,8 auf und der Tablet-Knoten auf
     22 / 26,4. Beide Rahmen stehen richtig.

     Hier gilt deshalb das Token. Folge: die Titel sind auf dem
     Tablet 26,4 hoch und alles darunter liegt 3,4 tiefer als im
     Rahmen — bis die Kästen dort auf Hug stehen.
   ============================================================ */

/* ============================================================
   Sheet „Dein Zugang" — nichts mehr eigenes
   ------------------------------------------------------------
   Aufbau und Maße der Zeilen stehen in components/dialog.css und
   gelten für Dialog und Sheet gleichermaßen: overlay__unterblock
   (8), overlay__zeilen (12), overlay__zeile mit Label und Wert.
   An Figma 13435:12766 („Sheet – Dein Zugang", QR-Fall)
   nachgemessen — die Komponente stimmt auf den Punkt.

   Hier stand zweimal etwas, das inzwischen dort steht: erst eine
   ganze Nachbildung der Zeilen unter eigenen Namen (bis zum
   15.09.2026, entstanden als der Rahmen noch nicht ausgewählt
   war), dann noch das Kürzen des Werts als Zwischenstand. Beides
   ist in der Komponente, also ist hier nichts mehr nötig.

   Die Regel dazu: SKILL.md §25a — in einer Zeile aus Merkmal und
   Wert gibt der WERT nach, nie das Merkmal.
   ============================================================ */

/* ============================================================
   Schloss — die PIN vor dem Prototyp
   ------------------------------------------------------------
   Kein Figma-Screen. Gebaut am 09.09.2026, weil der Prototyp
   nicht versehentlich vor Kundinnen und Kunden landen soll.

   DESHALB STEHEN HIER NUR TOKENS. Der Screen ist eine Zutat des
   Prototyps und nichts, was das System kennt; er darf ihm also
   erst recht keine neuen Werte hinzufügen. Alles Sichtbare
   darin — Wortmarke, Code-Eingabe, message, Knopf — sind
   bestehende Bauteile.

   MITTIG UND SCHMAL, wie jede Anmeldung: Es gibt genau eine
   Sache zu tun. Die Breite ist die des Sheets (393), damit die
   Kästchen nicht in einer leeren Fläche schwimmen.
   ============================================================ */

.schloss {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-lg);                /* 24 */
  background-color: var(--surface-primary);
}

.schloss__karte {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);                    /* 24 */
  width: 100%;
  max-width: 393px;                        /* Sheet-Breite, siehe Kopf */
}

/* DIE WORTMARKE BRAUCHT EIN MASS. Die Komponente bringt nur ein
   Seitenverhältnis mit; die Breite kommt immer von der Stelle, an
   der sie steht. Hier stehen die 79 x 45 aus der mobilen
   Kopfzeile — kein neuer Wert, sondern derselbe, den der Prototyp
   für das Logo schon benutzt. */
.schloss .wortmarke {
  width: 79px;
  height: 45px;
  aspect-ratio: auto;
}

.schloss__texte {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);                    /* 8 */
  width: 100%;
  text-align: center;
}

.schloss__titel {
  margin: 0;
  font-family: var(--font-family-display);
  font-size: var(--font-size-h2);
  line-height: var(--line-height-h2);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
}

.schloss__text {
  margin: 0;
  font-family: var(--font-family-inter);
  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  font-weight: var(--font-weight-regular);
  color: var(--text-description);
}

/* Der Knopf nimmt die Breite der Karte, nicht die des Textes. */
.schloss__karte > .btn {
  width: 100%;
}
