/* ============================================================
   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 {
  --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;
}

/* ------------------------------------------------------------
   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.
   ------------------------------------------------------------ */

.onboarding {
  overflow: hidden;
  justify-content: flex-end;
}

/* 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%;
}

/* ------------------------------------------------------------
   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;
}

/* ------------------------------------------------------------
   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.
   ------------------------------------------------------------ */

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

.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 ist zusammen 320 breit (Figma). */
.inhalte-seite__kopf .suchzeile {
  width: 320px;
}

/* Die Chip-Leiste läuft waagerecht über den Rand hinaus, genau
   wie die Cover-Reihen: in Figma ist sie 2076 breit in einem
   674 breiten Container. 16 unter der Kopfzeile (Figma y=61
   bei 45 Kopfhöhe). */
/* Die Chip-Leiste läuft waagerecht über den Rand hinaus, genau
   wie die Cover-Reihen: in Figma ist sie 2076 breit in einem
   674 breiten Container. 16 unter der Kopfzeile (Figma y=61
   bei 45 Kopfhöhe).

   DER FOKUS-RING BRAUCHT LUFT, UND DIE LUFT DARF NICHTS
   VERSCHIEBEN. overflow-x: auto schneidet auch oben und unten ab
   — ohne Polster wäre der Ring des ersten Chips gekappt. Das
   Polster wird deshalb durch negative Außenabstände wieder
   herausgerechnet, damit der Chip GENAU auf 85 sitzt wie in
   Figma und die Sektion darunter auf 154. */
.inhalte-seite__chips {
  /* Der Platz muss für ZWEI Dinge reichen, nicht nur für den
     Fokus-Ring: der aktive Chip trägt zusätzlich einen Glow mit
     Blur 4 (--glow-chip, §5), und der ragt über seine Kante
     hinaus. 4 Ring-Abstand + 2 Ring + 4 Glow = 10.
     Mit nur 6 war der aktive Chip oben sichtbar angeschnitten. */
  --fokus-luft: calc(var(--focus-ring-offset) + var(--focus-ring-width) + var(--glow-blur-s));

  display: flex;
  align-items: center;
  gap: var(--space-xs);                    /* 8 (§7) */

  overflow-x: auto;
  overscroll-behavior-x: contain;
  margin-right: calc(-1 * var(--space-lg));
  padding-right: var(--space-lg);

  /* LINKS BRAUCHT ES DIESELBE LUFT WIE OBEN UND UNTEN
     (Lisi, 09.09.2026: „der chip bei inhalte ist abgeschnitten").

     Die Reihe scrollt, und was scrollt, wird an seinen Kanten
     beschnitten — auch links. Der erste Chip begann genau an
     dieser Kante; sein Rand und sein Glow lagen davor und waren
     weg. Zu sehen war das am aktiven „Alle Themen": rechts ein
     blauer Bogen, links eine gerade Kante.

     Das Polster schiebt die Schnittkante um dieselben 10 nach
     links, die oben und unten schon stehen, und der negative
     Rand holt die Reihe an ihren Platz zurück. Der erste Chip
     steht damit weiter genau auf dem Seitenrand.

     Rechts stellt sich die Frage nicht: dort läuft die Reihe
     ohnehin über den Screenrand hinaus. */
  margin-left: calc(-1 * var(--fokus-luft));
  padding-left: var(--fokus-luft);

  padding-block: var(--fokus-luft);
  /* 16 unter der Kopfzeile, minus das Polster — sonst sitzt die
     Leiste 6 px zu tief. */
  margin-top: calc(var(--space-md) - var(--fokus-luft));
  margin-bottom: calc(-1 * var(--fokus-luft));

  scrollbar-width: none;
}

.inhalte-seite__chips::-webkit-scrollbar {
  display: none;
}

/* DIE CHIPS DÜRFEN NICHT SCHRUMPFEN. In einem scrollenden
   Flex-Container gibt ein Chip sonst Breite ab, sein Label bricht
   um, und die Leiste wird doppelt so hoch — statt zu scrollen.
   Gemessen: 99 px statt 45. In Figma ist die Leiste 2076 breit,
   also jeder Chip auf seiner natürlichen Breite. */
.inhalte-seite__chips > .chip {
  flex-shrink: 0;
  white-space: nowrap;
}

/* „Alle Themen" trägt in Figma ein Raster-Icon vor dem Label —
   das Zeichen für „keine Einschränkung". Es ist 11,05 groß mit
   5 Abstand, nicht 15 mit 8 wie das ✓ in chip.css: das ✓ meldet
   einen Zustand, dieses Icon gehört zum Namen.
   Gemessen an 13791:14478. */
.chip--alle-themen {
  gap: 5px;
}

.chip__ikon-klein {
  display: block;
  overflow: visible;
  flex: 0 0 auto;
  width: 11.05px;
  height: 11.05px;
}

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

/* ------------------------------------------------------------
   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 */
  margin-top: var(--space-2xl);            /* 48 */
}

/* 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 */
}

/* Unter 750 px wird aus fünf Spalten vier — sonst fallen die
   Cover unter 100 px und die Titel brechen. Die Spanne 750–950
   ist damit abgedeckt, darunter bleibt es lesbar. */
@media (max-width: 749px) {
  .meinetitel__favoriten {
    grid-template-columns: repeat(4, 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;
  margin-right: calc(-1 * var(--sektion-rand, var(--space-lg)));
  padding-right: 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. */
.suche__kontext {
  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 drei Kategorien sind dieselben Abkürzungen wie auf
   Entdecken — dieselbe Komponente, nur ohne den Überlauf nach
   rechts: hier sind es genau drei und sie passen. */
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.
   ------------------------------------------------------------ */

.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. */
  height: 100vh;
  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));
  /* COVER, NICHT CONTAIN. Mit contain passt das Bild in die Höhe
     und lässt links und rechts einen Streifen Grund stehen — eine
     harte Kante genau dort, wo in Figma nichts ist. Die
     Illustration läuft dort bis an die Screen-Kanten.

     Unten verankert, weil die Figur auf dem Boden sitzt: was
     abgeschnitten wird, wird oben abgeschnitten — und dort blendet
     die Maske ohnehin aus. */
  object-fit: cover;
  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;
}

/* 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 {
  left: calc(var(--buehne-links) + var(--nav-rail-breite) + var(--layout-screen-margin));
  right: calc(var(--buehne-links) + var(--layout-screen-margin));
  align-items: center;
}

/* 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(--layout-screen-margin));
}

.toast-schicht > .toast {
  width: auto;
  max-width: 100%;
}

/* 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. */
    width: 100%;
    max-width: none;
    height: auto;
    aspect-ratio: 393 / 355.5;
    z-index: 0;
    pointer-events: none;
  }

  /* 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;
}

/* ============================================================
   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;
  }

  .intro-szene {
    display: block;
    position: absolute;
    left: 0;
    /* 166 im Rahmen, minus die 73 der Kopfzeile — .intro__inhalt
       ist der Bezug. */
    top: 93px;
    width: 100%;
    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;
  }

  /* 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: 81px;
    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(81px + 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) + 81px);
  }

  /* 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).
   ------------------------------------------------------------ */

/* Auf dem Tablet gibt es sie nicht. */
.app-gestell__topbar {
  display: none;
}

@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 {
    display: flex;

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

  /* 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;
  }

  /* Das Inhalte-Panel beginnt unter der Leiste, nicht am
     Screenrand — sonst deckt es das Logo zu. */
  .inhalte-overlay,
  .scrim--inhalte {
    top: var(--topbar-h, 73px);
  }
}

/* ============================================================
   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-tab-screen="inhalte-seite"]:not([hidden]))
  .app-gestell__topbar {
    display: none;
  }

  [data-tab-screen="inhalte-seite"] {
    padding-top: var(--space-lg);          /* 24, gemessen */
  }

  /* DER KOPF IST MOBIL ZWEIZEILIG. Auf dem Tablet steht alles in
     einer Zeile (← + Titel + Suchzeile, Figma 12845:14653); bei
     393 ist dafür kein Platz — der Titel wurde auf „Mag…"
     gekürzt (Lisi, 09.09.2026).

     Im Rahmen (13826:41714) sind es zwei Zeilen:
       24   ← (45) + 12 + Titel
       85   Suchzeile mit Filter (46 hoch)
      147   Chips
     Also 16 zwischen den Zeilen — dieselben 16, die auch
     zwischen Suchzeile und Chips stehen. */
  .inhalte-seite__kopf {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    row-gap: var(--space-md);              /* 16, gemessen */
  }

  /* Die Suchzeile rutscht unter ← und Titel und nimmt die ganze
     Breite — 353 im Rahmen, hier also beide Spalten. */
  .inhalte-seite__kopf .suchzeile {
    grid-column: 1 / -1;
    width: auto;
  }

  /* Der Titel darf jetzt ganz dastehen: er hat die Zeile für
     sich, und im Rahmen ist er 197 breit bei 353 Platz. */
  .inhalte-seite__titel {
    overflow: visible;
    text-overflow: clip;
  }
}

/* Auf dem Tablet gibt es weder Leiste noch Icon. Die Leiste
   allein auszublenden würde reichen — das Icon steht darin. Es
   steht trotzdem hier, weil der Knopf sonst als einziges Element
   der Komponente von einer fremden Regel abhinge. */
.topbar__suchicon {
  display: none;
}

@media (max-width: 767px) {
  .topbar__suchicon {
    display: inline-flex;
  }
}

/* ============================================================
   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 */
  }

  /* 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" — die Standort-Zeile
   ------------------------------------------------------------
   Links das Merkmal, rechts der Wert; beide stehen unmittelbar
   auf der Sheet-Fläche, ohne Karte und ohne Trennlinie.

   NICHT AUS FIGMA GEMESSEN. Der Rahmen war nicht ausgewählt;
   Aufbau und Text stammen aus Lisis Screenshot vom 09.09.2026.
   Deshalb ist hier auch kein einziger neuer Wert erfunden: das
   Merkmal ist .overlay__text, wie jeder andere Text im Sheet
   (small text, text-description), und der Wert ist dieselbe
   Größe in bold auf text-primary — die Stufe, die das System für
   „das ist die Antwort, nicht die Frage" ohnehin benutzt. Der
   Abstand zum Absatz darunter kommt aus .overlay__inhalt (16).

   Sobald der Rahmen ausgewählt ist: nachmessen.
   ============================================================ */

.zugang-zeile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);                    /* 16 */
  width: 100%;
  margin: 0;
}

/* Der Wert gibt nach, nicht das Merkmal — „Standort" muss immer
   ganz dastehen, der Name darf kürzen. Dieselbe Regel wie in
   facette-header.css und in der Suchliste. */
.zugang-zeile__wert {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;

  font-size: var(--font-size-small-text);
  line-height: var(--line-height-small-text);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
}

/* ============================================================
   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%;
}
