/* majortom.ai — the site's only stylesheet.
   Register: freundlich, warm, ein bisschen verspielt. Die Marke heißt nach
   dem Astronauten, also ist die Bildwelt der Funkverkehr zwischen oben und
   unten — nicht Technik, sondern jemand, der mithört. Die Zielgruppe hat
   Respekt vor dem Thema; jede Gestaltungs&shy;entscheidung hier soll Druck
   herausnehmen statt Kompetenz behaupten.

   Verspieltheit kommt aus Farbe, Größe, Rundung und leichter Schieflage —
   nicht aus einer Schrift. Eine verspielte Schrift müsste geladen werden,
   und die Seite lädt bewusst nichts von außen: keine Schrift, kein Skript.
   Das eine Bild (das Visier, siehe „Das Visier“) liegt neben dem
   Stylesheet und kommt vom eigenen Server. Das hält sie schnell und die
   Datenflüsse erklärbar.

   Gewachsen aus dem Entwurf /mt-h/ (drafts/). Dessen Probierleiste — Palette,
   Wortbildmarke, Knopfform, Schrift, Headline-Größe live umschaltbar — ist
   hier weg; was dort gewählt war, steht jetzt fest: Palette Tiefsee, das
   Kassiopeia-Zeichen über dem Wort, eckige Knöpfe. */

/* ==========================================================================
   Marken
   ========================================================================== */

:root {
  color-scheme: light;

  /* Palette: Tiefsee. Kühl und ruhig, mit einem einzigen warmen Signal.
     Die Token-Namen sind historisch und beschreiben jetzt die Rolle, nicht
     den Farbton: --violet ist die Hauptfarbe, --coral das warme Signal,
     --amber die Hervorhebung auf Dunkel, --mint die Bestätigung. Sie
     bleiben, weil rund vierzig Regeln darauf zeigen.

     Die vorige Palette, falls sie zurück soll:
       --space #141043  --space-2 #1d1760  --cream #fff8ee
       --ink #191340  --ink-2 #4a4270  --ink-muted #6b6390
       --coral #ff6a4d  --amber #ffc043  --violet #7d5cff  --mint #35d39a
       --on-space #f2eeff  --on-space-muted #a9a0d8

     Alle Werte unten sind gemessen, nicht geschätzt — die Seite war beim
     Wechsel nicht sichtbar, also ersetzt der Kontrastwert das Auge.
     Schwelle 4.5:1 für Fließtext, 3:1 ab 24px. */

  --space: #08262e;            /* der Nachtgrund — Hero, Beweis, Funkspruch */
  --space-2: #0d3540;
  --cream: #eef6f5;            /* der helle Bogen */
  --white: #ffffff;
  --ink: #0a2229;
  --ink-2: #2c4f58;            /* 8.1:1 auf Creme */
  --ink-muted: #4d7079;        /* 4.9:1 auf Creme — trägt Fließtext */

  --coral: #c4471f;            /* 4.9:1 mit weißer Schrift */
  --amber: #ffc95c;            /* 10.4:1 auf dem Nachtgrund */
  --violet: #17697a;           /* 6.3:1 mit weißer Schrift */
  --mint: #6fd8c4;

  --on-space: #eafaf8;         /* 14.7:1 */
  --on-space-muted: #9dc2c4;   /* 8.3:1 */

  /* Abgeleitete Töne. Sie standen vorher als Zahl in den Regeln und wären
     beim Palettenwechsel als alte Farbe stehengeblieben. */
  /* Überfahren geht nach unten, nicht nach oben. Die Basis hellte den Knopf
     dabei auf; gemessen fällt weiße Schrift darauf in jeder der vier
     Paletten unter 4.5:1, und bei der Signalfarbe ist nach oben ohnehin
     kein Platz — sie liegt schon bei 4.6 bis 4.9. Das Anheben leistet der
     Versatz und der tiefere Schatten, die Farbe muss es nicht auch. */
  --violet-2: #0e414c;         /* der harte Schatten unter dem Hauptknopf */
  --violet-hi: #145968;        /* beim Überfahren — dunkler als die Grundfarbe */
  --coral-2: #7a2c13;
  --coral-hi: #a73c1a;
  --on-accent: #ffffff;        /* Schrift auf Haupt- und Signalfarbe */
  --on-mint: #06342c;          /* 8.0:1 auf der Minzfläche */

  /* Dieselben Farben als Kanäle, für die Verläufe und Schatten. CSS kann
     einer rgb()-Funktion keine fertige Farbe übergeben, nur Zahlen —
     deshalb diese zweite Fassung statt einer Wiederholung in jeder Regel. */
  --space-rgb: 8 38 46; /* @kind color */
  --ink-rgb: 10 34 41; /* @kind color */
  --violet-rgb: 23 105 122; /* @kind color */
  --coral-rgb: 196 71 31; /* @kind color */
  --mint-rgb: 111 216 196; /* @kind color */
  --cream-rgb: 238 246 245; /* @kind color */

  /* Die Schleier: alle halbdurchsichtigen Flächen, Linien und Punkte, die
     auf --space liegen. Sie waren weiß, weil --space immer dunkel war. Für
     die hellen Paletten muss das kippen können, sonst verschwinden Sterne,
     Merkkasten und Mitschnitt-Rahmen auf hellem Grund. */
  --veil-rgb: 255 255 255; /* @kind color */

  /* Schrift auf der Bernsteinfläche. War fest --ink, weil Bernstein immer
     hell war; auf hellem --space wird Bernstein dunkel und braucht Weiß. */
  --on-amber: var(--ink); /* @kind color */
  /* Gold: nur der Verweis in den Vault (GcVault) trägt es. Auf Hell, weil
     --amber dort nicht lesbar ist; --gold-ink 9.6:1 und --gold 5.2:1 auf
     --gold-lo. */
  --gold-hi: #fff7de; /* @kind color */
  --gold-lo: #f9eac0; /* @kind color */
  --gold-line: #dcb55a; /* @kind color */
  --gold: #7f5b0e; /* @kind color */
  --gold-ink: #4a3604; /* @kind color */

  /* Keine geholte Schrift. system-ui ist auf jedem Gerät die freundlichste
     verfügbare Grotesk; der Rest der Kette fängt ältere Systeme auf. */
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* @kind font */

  --fs-big: clamp(3rem, 1.2rem + 7.5vw, 7rem); /* @kind other */
  --fs-h2: clamp(1.875rem, 1rem + 3vw, 3.5rem); /* @kind other */
  --fs-h3: clamp(1.1875rem, 1rem + 0.6vw, 1.5rem); /* @kind other */
  --fs-lede: clamp(1.125rem, 1rem + 0.75vw, 1.5rem); /* @kind other */
  --fs-body: 1.0625rem; /* @kind font */

  --gut: clamp(1.25rem, 0.5rem + 3vw, 4rem); /* @kind spacing */
  --sec-y: clamp(4rem, 2rem + 8vw, 9rem); /* @kind spacing */
  --wrap: 76rem; /* @kind spacing */
  --bar-h: 4.25rem; /* @kind spacing */ /* Höhe der Kopfleiste; der Hero rückt um sie nach oben */

  --r-sm: 10px; /* @kind radius */
  --r: 18px; /* @kind radius */
  --r-lg: 28px; /* @kind radius */
  --r-pill: 999px; /* @kind radius */
}

/* ==========================================================================
   Grundlage
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 800; letter-spacing: -0.03em; line-height: 1.05; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
a { color: inherit; }

::selection { background: var(--amber); color: var(--on-amber, var(--ink)); }

:focus-visible { outline: 3px solid var(--violet); outline-offset: 3px; border-radius: 4px; }

.wrap { max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gut); }
.wrap--narrow { max-width: 50rem; }

/* ==========================================================================
   Wiederkehrende Teile
   ========================================================================== */

.eyebrow {
  margin: 0 0 1rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--violet);
}
.eyebrow--inv { color: var(--amber); }

.h2 { font-size: var(--fs-h2); text-wrap: balance; }
.h2--inv { color: var(--on-space); }

.lede {
  margin-top: 1.5rem;
  font-size: var(--fs-lede);
  line-height: 1.45;
  color: var(--ink-2);
  max-width: 54ch;
}
.lede--inv { color: var(--on-space-muted); }

/* Jeder Abschnittskopf kommt an, statt nur dazustehen: Zeile, Überschrift
   und Vorspann (beim Funkspruch die Überschrift und der Absatz darunter)
   steigen ein Stück und werden aus durchsichtig und unscharf klar, sobald
   sie unten ins Fenster kommen — jeder Block auf seiner eigenen
   View-Timeline, über die ersten 22vh seines Wegs, damit eine kurze Zeile
   und ein langer Absatz gleich schnell sind. Nur die direkten Kinder von
   .wrap: die Blöcke in den Bauteilen darunter (Silos, Etappen, Karten)
   stehen. Der Kopf des ersten Abschnitts nach dem Hero hängt stattdessen
   am Kasten (siehe „Der Kasten öffnet sich“); die Regel dort ist
   spezifischer und gewinnt. Ohne View-Timeline steht alles, wie es steht. */
@supports (animation-timeline: view()) {
  :is(.sec, .call) > .wrap > :is(.eyebrow, .h2, .lede, .call__h, .call__p) {
    animation: rise-in ease-out both;
    animation-timeline: view();
    animation-range: cover 0 cover 22vh;
  }
  @keyframes rise-in {
    from { opacity: 0; translate: 0 3rem; filter: blur(8px); }
    to   { opacity: 1; translate: 0 0;    filter: blur(0); }
  }
  @media (prefers-reduced-motion: reduce) {
    :is(.sec, .call) > .wrap > :is(.eyebrow, .h2, .lede, .call__h, .call__p) { animation: none; }
  }
}

.plain {
  font-weight: 700;
  text-decoration: none;
  border-bottom: 2px solid var(--coral);
  padding-bottom: 2px;
  white-space: nowrap;
}
.plain:hover { color: var(--coral); }
.plain--inv { color: var(--on-space); border-bottom-color: var(--amber); }
.plain--inv:hover { color: var(--amber); }

/* Der harte Schatten und die Überfahr-Farbe standen hier als Zahl. Beide
   gehören zur Palette und müssen mitziehen, wenn die Palette wechselt —
   sonst bleibt unter einem neuen Knopf der alte violette Schatten stehen.
   Der Ersatzwert hinter dem Komma ist der bisherige, damit die Datei auch
   ohne die neuen Token richtig bleibt. */
.btn {
  display: inline-block;
  background: var(--violet);
  color: var(--on-accent, #fff);
  font-weight: 700;
  font-size: 0.9375rem;
  text-align: center;                 /* bricht die Beschriftung auf schmalen Handys, steht sie mittig */
  text-decoration: none;
  padding: 0.8125rem 1.5rem;
  border-radius: 4px;
  border: 0;
  transition: transform 0.14s ease, box-shadow 0.14s ease, background 0.14s ease;
  box-shadow: 0 3px 0 var(--violet-2, #5a3fd0);
}
.btn:hover { background: var(--violet-hi, #6b48ff); transform: translateY(-2px); box-shadow: 0 5px 0 var(--violet-2, #5a3fd0); }
.btn:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--violet-2, #5a3fd0); }
.btn--sm { padding: 0.5625rem 1.125rem; font-size: 0.8125rem; }
.btn--lg { padding: 1.0625rem 2.25rem; font-size: 1.0625rem; }
.btn--warm { background: var(--coral); box-shadow: 0 3px 0 var(--coral-2, #d14a30); }
.btn--warm:hover { background: var(--coral-hi, #ff7e63); box-shadow: 0 5px 0 var(--coral-2, #d14a30); }
.btn--warm:active { box-shadow: 0 1px 0 var(--coral-2, #d14a30); }

/* Umrissen statt gefüllt: vier gleichwertige Wege zum selben Ziel, also darf
   keiner lauter rufen als die anderen. Steht nur auf dunklem Grund, darum
   Weiß mit Deckkraft statt einer Palettenfarbe — so trägt er jede Palette mit.

   Kein Schlagschatten, sondern ein inset-Rand: derselbe Kasten, nur ohne die
   3 px Sockel des gefüllten Knopfes, sonst stünden beide gleich schwer da.
   Das Anheben beim Hover kommt weiter von .btn:hover, hier wird nur
   überschrieben, was dort an Farbe und Sockel gesetzt wird. Reihenfolge ist
   das Einzige, was das entscheidet — gleiche Spezifität wie .btn:hover. */
.btn--ghost { background: none; color: var(--on-space); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.32); }
.btn--ghost:hover { background: rgb(255 255 255 / 0.08); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.58); }
.btn--ghost:active { box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.58); }

@media (prefers-reduced-motion: reduce) {
  .btn, .btn:hover, .btn:active { transform: none; transition: background 0.14s ease; }
}

/* ==========================================================================
   Logo
   ========================================================================== */

/* Das Kassiopeia-Zeichen über dem Wort, zentriert. Ein Bauteil in jeder
   Größe: alles hängt in em an --logo, der Schriftgröße des Worts — das
   Zeichen ist 2,5 Wortgrößen breit, der Abstand ein Viertel. Ohne Zusatz
   ist es klein, wie es in Kopf und Fuß steht; --lg füllt den Bildschirm
   und wächst mit ihm. Eine dritte Größe ist eine Zeile: --logo setzen.
   currentColor trägt Wort und Form, --a den Akzentstern; beides kommt vom
   Grund, auf dem das Logo steht. */
.logo {
  --logo: 0.765rem;
  --a: var(--amber);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25em;
  margin: 0;
  font-size: var(--logo);
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: inherit;
  text-decoration: none;
}
.logo--lg { --logo: clamp(1.5rem, 8vw, 6rem); }

/* Das Zeichen: ein <use> auf das Symbol #m15, das einmal pro Seite in
   .defs steht (am Ende von <body>). Der Kasten ist nicht mehr quadratisch,
   weil die viewBox des Symbols auf die Figur beschnitten ist: 2,5 × 22/32 =
   1,72em. Stünde hier weiter 2,5em, säße die Figur mittig in einem
   quadratischen Kasten und der Beschnitt hätte nichts gebracht — die leere
   Luft zwischen Zeichen und Wort wäre wieder da. */
.logo__sign { display: block; flex: none; width: 2.5em; height: 1.72em; }
.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Der Laufweitenrest hinter dem letzten Buchstaben würde das Wort aus der
   Mitte unter dem Zeichen schieben; er wird abgezogen. */
.logo__word { margin-right: -0.18em; }
.logo__tld { opacity: 0.6; }

/* ==========================================================================
   Sprach-Angebot
   ========================================================================== */

/* Schwebt unten am Bildschirmrand, losgelöst vom Fluss der Seite: keine
   Berührung mit der Kopfleiste oder ihrem Einblenden über dem Hero (siehe
   „Die Leiste nimmt den Ton des Abschnitts an" unten) — die Leiste sieht
   das Band gar nicht, sie steht genau, wie sie ohne es stünde. Es steht
   nur, wenn der Browser des Lesers eine andere Sprache bevorzugt als die
   Seite (der Worker liest Accept-Language und un-hidden das Band vor dem
   Versand). Es bietet an, es leitet nie um — ein geteilter Link landet,
   wo er hinzeigt. Wer geantwortet hat — Knopf oder der einfache
   DE/EN-Schalter in der Leiste oder im Fuß —, wird über ein Cookie nicht
   erneut gefragt.

   Die Sätze in der Sprache des Lesers (der Text des Bauteils ist der der
   *anderen* Seite), der zweite Satz als Link — dasselbe Idiom wie der
   DE/EN-Schalter, nur ausgesprochen statt abgekürzt. hidden (vom Worker
   un-hidden) statt display:none im Blatt: ohne Anfrage bleibt das Band
   stumm und beansprucht keine Fläche — auch als Fixierung wichtig, sonst
   läge ein leerer Rahmen über dem Inhalt. */
.lang {
  position: fixed;
  z-index: 30;
  inset-inline: 1rem;
  bottom: 1rem;
  max-width: 26rem;
  margin-inline: auto;
  background: var(--cream);
  color: var(--ink-muted);
  font-size: 0.875rem;
  line-height: 1.4;
  border-radius: var(--r);
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) /0.06), 0 10px 30px rgb(var(--ink-rgb) /0.18);
}
/* Steht nur an der Kante, wo der Blick zuerst hinfällt: sobald der Leser
   zu scrollen beginnt, tritt es zurück, statt über den Inhalt zu wandern
   — die Sprache lässt sich weiterhin über den Schalter in der Leiste oder
   im Fuß wechseln, das Band muss nicht mitreisen. An den Scrollweg
   gebunden, nicht an eine einmalige Geste: kehrt der Leser ganz nach oben
   zurück, kommt es wieder, wie die Kopfleiste ihren Grund über dem Hero
   verliert und zurückgewinnt (siehe „Kopfleiste" unten). Ohne
   Scroll-Timeline steht es fest, wie zuvor. */
@supports (animation-timeline: scroll()) {
  .lang {
    animation: lang-retreat linear both;
    animation-timeline: scroll(root);
    animation-range: 0 var(--bar-h);
  }
  @keyframes lang-retreat {
    from { opacity: 1; translate: 0 0; }
    to   { opacity: 0; translate: 0 0.75rem; pointer-events: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .lang { animation: none; }
  }
}
.lang__in {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 1rem 1.25rem;
}
.lang__text { margin: 0; }
.lang__text b { color: var(--ink); font-weight: 600; }
.lang__do { margin: 0; display: flex; gap: 1.25rem; }
.lang__do a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid rgb(var(--ink-rgb) / 0.32);
  padding: 0.125rem 0;
}
.lang__do a:hover { color: var(--coral); border-bottom-color: var(--coral); }

/* ==========================================================================
   Kopfleiste
   ========================================================================== */

.bar {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Der Ton der Leiste; ::before und .bar__in tragen ihn. Ohne View-Timeline
     bleibt er Nacht, wie der Hero; mit ihr richtet er sich nach dem
     Abschnitt darunter (siehe „Die Leiste nimmt den Ton des Abschnitts
     an“). */
  --bar-bg: rgb(var(--space-rgb) /0.88);
  --bar-fg: var(--on-space);
  --bar-fg-muted: var(--on-space-muted);
  --bar-accent: var(--amber);
}
/* Der Grund liegt auf einem Pseudo-Element, damit das Einblenden über dem
   Hero und der Tonwechsel sich nicht eine Animationsliste teilen müssen. */
.bar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--bar-bg);
  backdrop-filter: blur(10px);
}
.bar__in { display: flex; align-items: center; gap: 1.5rem; min-height: var(--bar-h); color: var(--bar-fg); }

/* Über dem Hero liegt die Leiste beim Laden ohne eigenen Grund auf dem
   Nachthimmel (der Hero rückt unter sie, siehe .hero). Erst beim Scrollen
   legt sie sich ihren Grund zu — an die Scrollposition gebunden, ohne
   Skript. Browser ohne Scroll-Timeline zeigen sie von Anfang an gefüllt.
   Die 404 hat keinen Hero und behält den Grund immer. */
@supports (animation-timeline: scroll()) {
  .bar:has(+ main > .hero:first-child)::before {
    animation: bar-settle linear both;
    animation-timeline: scroll(root);
    animation-range: 0 var(--bar-h);
  }
  @keyframes bar-settle {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
}

/* Die Leiste nimmt den Ton des Abschnitts an, der unter ihr liegt: Nacht
   auf Nacht, hell auf hell. Auch das ohne Skript — jeder Nachtabschnitt
   (Hero, Beweis, Funkspruch, Fuß) führt eine View-Timeline, deren
   Sichtbereich nur die Leiste selbst ist (unten um alles außer --bar-h
   eingerückt). Schiebt sich ein Nachtabschnitt unter die Leiste, kippt sie
   zur Nacht, sobald seine Oberkante die Mitte der Leiste passiert (entry);
   verlässt er sie, kippt sie mit seiner Unterkante zurück (exit);
   dazwischen hält „forwards“ den Ton. Zwei Animationen je Abschnitt, die
   spätere in der Liste gewinnt — die Liste steht darum in der Reihenfolge
   der Abschnitte auf der Seite; beide Enden der Keyframes stehen
   ausgeschrieben, ein fehlendes „from“ nähme den Wert unter der Animation
   — die noch haltende Einblendung — und die Leiste käme aus der Nacht nie
   zurück. Jeder Nachtabschnitt braucht seinen eigenen
   Namen — ein Name an zwei Elementen macht die Timeline stumm. body hebt
   die Namen in den Geltungsbereich der Leiste (bei der Navigation unten,
   zusammen mit --nav-*). Der Hero wird nicht erst mit seiner Unterkante
   hell, sondern schon mit dem hellen Kasten der vier Schreibtische:
   schiebt sich dessen Oberkante unter die Leiste, kippt sie zurück
   (--night-1-end, entry) — die zweite Timeline des Kastens; die erste,
   --desks, öffnet ihn (siehe Hero). Beim Öffnen steigt sein heller Grund
   aber bis an den oberen Fensterrand, lange bevor die Oberkante des
   Kastens selbst dort ankommt — darum kippt die Leiste außerdem mit dem
   Kasten zurück: sie liest den Schalter --desks-on von body (siehe Hero)
   und nimmt ihn aus --night heraus, solange der Kasten noch nicht unter
   ihr liegt (--desks-under, kippt auf --night-1-end entry; ab dort
   entscheidet wieder --night allein, sonst bliebe die Leiste für den Rest
   der Seite hell). Das ist der Fall, der im Bild zählt. Bei reduzierter
   Bewegung öffnet sich der Kasten nicht, --desks-on bleibt 0, dann greift
   nur --night-1-end. Das Visier (--night-2, siehe „Das
   Visier“) misst ohne eingerückten Sichtbereich, weil sein Kasten erst
   beim Scrollen unter die Leiste wächst: die Leiste kippt, wenn der
   Kasten oben angekommen ist (contain 6–14 %), und mit der Unterkante des
   Visiers zurück (exit, um --bar-h vor dem Ende) — der Kasten selbst
   bewegt sich und taugt nicht als Maß.

   Der Wechsel ist an den Scrollweg gebunden, sein Verlauf an die Zeit:
   die Animation kippt nur den Schalter --night (nicht registriert, also
   springt er bei der Hälfte des Bereichs, statt über 68 px mitzulaufen
   und beim Anhalten auf halbem Weg stehenzubleiben). --night-t folgt ihm
   als registrierte Zahl mit einer Transition, und aus ihr mischen sich
   die vier Farben der Leiste. Ohne View-Timeline bleibt --night auf 1
   und die Farben oben stehen. */
@property --night-t { syntax: "<number>"; inherits: true; initial-value: 1; }
@supports (animation-timeline: view()) {
  .hero, .call, .foot { view-timeline-inset: 0 calc(100% - var(--bar-h)); }
  .hero { view-timeline-name: --night-1; }
  /* Vier Namen an einem Element, vier Insets in derselben Reihenfolge.
     --desk-run ist der Weg durch die fünf Schritte (siehe „Vier
     Schreibtische am Scrollweg“); er steht hier, weil nur Nachfahren des
     Kastens ihn lesen — in timeline-scope am body muss er deshalb nicht.
     --nav-1 dagegen ist der erste Eintrag der Navigation: der Kasten hat
     den Abschnitt beerbt, der vorher unter dem Hero stand. */
  .hero__desks {
    view-timeline-name: --desks, --night-1-end, --desk-run, --nav-1;
    view-timeline-inset: auto, 0 calc(100% - var(--bar-h)), auto, 40% 0;
  }
  /* --night-2 trägt das Visier (siehe „Das Visier“), --night-3 #beweis,
     bei der Navigation unten neben --nav-4. */
  .call { view-timeline-name: --night-4; }
  .foot { view-timeline-name: --night-5; }
  .bar {
    --night: 0; /* @kind other */
    --desks-under: 0; /* @kind other */
    animation:
      bar-night linear forwards, bar-night linear reverse forwards, bar-under linear forwards, bar-night linear forwards,
      bar-night linear forwards, bar-night linear reverse forwards,
      bar-night linear forwards, bar-night linear reverse forwards,
      bar-night linear forwards, bar-night linear reverse forwards,
      bar-night linear forwards, bar-night linear reverse forwards;
    animation-timeline:
      --night-1, --night-1-end, --night-1-end, --night-1,
      --night-2, --night-2,
      --night-3, --night-3,
      --night-4, --night-4,
      --night-5, --night-5;
    animation-range:
      entry, entry, entry, exit,
      contain 6% contain 14%, exit calc(100% - var(--bar-h)) exit 100%,
      entry, exit,
      entry, exit,
      entry, exit;
  }
  @keyframes bar-night {
    from { --night: 0; }
    to   { --night: 1; }
  }
  @keyframes bar-under {
    from { --desks-under: 0; }
    to   { --desks-under: 1; }
  }
  /* Die Transition sitzt eine Ebene unter der Animation: eine Änderung,
     die per var() aus einer animierten Eigenschaft desselben Elements
     kommt, startet keine Transition — geerbt von .bar startet sie. Darum
     mischen Grund (::before) und Inhalt (.bar__in) ihre Farben selbst. */
  .bar::before, .bar__in {
    --night-t: calc(var(--night) * (1 - var(--desks-on) * (1 - var(--desks-under)))); /* @kind other */
    transition: --night-t 0.35s ease;
    --bar-bg: color-mix(in oklab, rgb(var(--cream-rgb) /0.88), rgb(var(--space-rgb) /0.88) calc(var(--night-t) * 100%));
    --bar-fg: color-mix(in oklab, var(--ink), var(--on-space) calc(var(--night-t) * 100%));
    --bar-fg-muted: color-mix(in oklab, var(--ink-muted), var(--on-space-muted) calc(var(--night-t) * 100%));
    --bar-accent: color-mix(in oklab, var(--violet), var(--amber) calc(var(--night-t) * 100%));
  }
  @media (prefers-reduced-motion: reduce) {
    .bar::before, .bar__in { transition: none; }
  }
  /* Solange das Visier klebt (--night-2, contain), verliert der Grund der
     Leiste seine Unschärfe: Safari setzt alles, was unter einem
     backdrop-filter liegt, im Hauptthread neu, statt es dem Scroll-Thread
     zu überlassen — die klebende Bühne hinkte dem Scrollen um einen Frame
     nach und wackelte samt Schrift auf und ab. Ohne fill-mode gilt die
     Animation nur im Bereich; davor und danach bleibt die Unschärfe. Die
     Einblendung über dem Hero (bar-settle, siehe oben) steht mit in der
     Liste, weil sie dasselbe Pseudo-Element trägt. */
  .bar::before {
    animation: bar-flat linear;
    animation-timeline: --night-2;
    animation-range: contain 0% contain 100%;
  }
  .bar:has(+ main > .hero:first-child)::before {
    animation: bar-settle linear both, bar-flat linear;
    animation-timeline: scroll(root), --night-2;
    animation-range: 0 var(--bar-h), contain 0% contain 100%;
  }
  @keyframes bar-flat {
    from, to { backdrop-filter: none; }
  }
}

/* Das Logo (siehe „Logo“) steht links und schrumpft nicht mit. */
.bar__brand { flex: none; }

/* Sprachwechsel: DE / EN, klein, neben dem Knopf. Ohne Abschnittsnavigation
   (404) rückt er selbst nach rechts; sonst übernimmt das die Navigation. */
.bar__langs {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 0 auto;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--bar-fg-muted);
}
.bar__nav + .bar__langs { margin-left: 0; }
.bar__langs b { color: var(--bar-fg); }
/* Der Link ist klein gesetzt; das Polster (mit negativem Rand, damit die
   Zeile nicht wächst) gibt ihm auf dem Handy eine Fläche, die ein Daumen
   trifft. */
.bar__langs a { text-decoration: none; padding: 0.75rem 0.375rem; margin: -0.75rem -0.375rem; }
.bar__langs a:hover { color: var(--bar-accent); }

.bar__nav { display: flex; gap: 1.5rem; margin-inline: auto; font-size: 0.875rem; font-weight: 600; }
.bar__nav a { position: relative; text-decoration: none; white-space: nowrap; color: var(--bar-fg-muted); }
.bar__nav a:hover { color: var(--bar-accent); }
.bar__nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.4em;
  height: 0.14em;
  border-radius: 999px;
  background: var(--bar-accent);
  transform: scaleX(0);
  transform-origin: left;
}

/* The filialcoach nav's six points each carry a one-word gloss (Report,
   Bestellung, …) under the label. Scoped to --sub so the site's own eight-
   point nav, which has no gloss, keeps its single-line layout untouched. */
.bar__nav--sub a { display: flex; flex-direction: column; align-items: center; gap: 0.02rem; }
.bar__navsub {
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--bar-fg-muted);
  opacity: 0.72;
}

/* Der Link zum Abschnitt, der gerade im Blick ist, leuchtet: Schrift hell,
   Strich in Bernstein. Jeder Abschnitt aus der Navigation (DE und EN, in
   der Reihenfolge der Links) führt eine View-Timeline; body hebt die Namen
   in den Geltungsbereich der Leiste. Ein Link ist an, solange sein
   Abschnitt die Linie bei 40 % der Fensterhöhe überdeckt (exit-crossing
   mit oben eingerücktem Sichtbereich) — ohne Skript, wie der Grund der
   Leiste oben. Browser ohne View-Timeline zeigen keine Hervorhebung. */
@supports (animation-timeline: view()) {
  body {
    timeline-scope:
      --night-1, --night-1-end, --desks, --night-2, --night-3, --night-4, --night-5,
      --nav-1, --nav-2, --nav-3, --nav-4, --nav-5, --nav-6, --nav-7, --nav-8;
  }
  /* --nav-1 gehört keinem Abschnitt, sondern dem Kasten mit den vier
     Schreibtischen im Hero; er steht bei .hero__desks, wo schon drei
     andere Timelines hängen. */
  #was, #what               { view-timeline-name: --nav-2; }
  #keine-angst, #no-fear    { view-timeline-name: --nav-3; }
  #beweis, #proof           { view-timeline-name: --nav-4, --night-3; }
  #reise, #journey          { view-timeline-name: --nav-5; }
  #wir, #us                 { view-timeline-name: --nav-6; }
  #fragen, #questions       { view-timeline-name: --nav-7; }
  #absage, #no              { view-timeline-name: --nav-8; }
  #was, #what, #keine-angst, #no-fear, #reise, #journey,
  #absage, #no, #wir, #us, #fragen, #questions {
    view-timeline-inset: 40% 0;
  }
  /* #beweis führt zwei Timelines: die der Navigation und --night-3 für
     den Ton der Leiste (Sichtbereich nur die Leiste, siehe oben). */
  #beweis, #proof { view-timeline-inset: 40% 0, 0 calc(100% - var(--bar-h)); }
  .bar__nav a, .bar__nav a::after {
    animation: nav-on linear;
    animation-range: exit-crossing 0% exit-crossing 100%;
  }
  .bar__nav a:nth-child(1), .bar__nav a:nth-child(1)::after { animation-timeline: --nav-1; }
  .bar__nav a:nth-child(2), .bar__nav a:nth-child(2)::after { animation-timeline: --nav-2; }
  .bar__nav a:nth-child(3), .bar__nav a:nth-child(3)::after { animation-timeline: --nav-3; }
  .bar__nav a:nth-child(4), .bar__nav a:nth-child(4)::after { animation-timeline: --nav-4; }
  .bar__nav a:nth-child(5), .bar__nav a:nth-child(5)::after { animation-timeline: --nav-5; }
  .bar__nav a:nth-child(6), .bar__nav a:nth-child(6)::after { animation-timeline: --nav-6; }
  .bar__nav a:nth-child(7), .bar__nav a:nth-child(7)::after { animation-timeline: --nav-7; }
  .bar__nav a:nth-child(8), .bar__nav a:nth-child(8)::after { animation-timeline: --nav-8; }
  /* Ohne fill-mode gilt die Animation nur innerhalb des Bereichs; davor und
     danach bleiben Farbe und Hover des Links unberührt. */
  @keyframes nav-on {
    from, to { color: var(--bar-fg); transform: scaleX(1); }
  }
}

.bar__in .btn { white-space: nowrap; }

/* Acht Links brauchen mit Logo, Sprachwechsel, Knopf und Rand gut 66rem in
   einer Zeile (die englischen Beschriftungen sind die längeren); darunter
   fällt die Abschnittsnavigation weg. */
@media (max-width: 68rem) {
  .bar__nav { display: none; }
  .bar__in { justify-content: space-between; gap: 1rem; }
}

/* Bis 26rem (iPhone mini und SE, die meisten Android-Handys mit 360 px)
   reichen Logo, Sprachwechsel und Knopf nicht mehr in eine Zeile — der
   Knopf ragte in die Randspalte und darunter aus dem Fenster, und die
   ganze Seite ließ sich quer schieben. Der Sprachwechsel zeigt nur noch
   die andere Sprache (die eigene steht ohnehin auf der Seite), der
   Abstand und das Polster des Knopfs werden enger. Wo keine Sprache die
   eigene ist (404, zwei Links) und unter 21rem überall fällt dazu das
   Wort unter dem Zeichen weg; das Zeichen allein ist auch das Favicon. */
@media (max-width: 26rem) {
  .bar__in { gap: 0.75rem; }
  .bar__langs [aria-current], .bar__langs [aria-hidden] { display: none; }
  .bar__in .btn--sm { padding-inline: 1rem; }
  .bar:not(:has(.bar__langs [aria-current])) .logo__word { display: none; }
}
@media (max-width: 21rem) {
  .bar__brand .logo__word { display: none; }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  /* Knapper als der übrige Abschnittsabstand, und zwar mit Absicht: unter
     dem Knopf beginnt der Kasten mit „Ich bin“, und der soll auf einem
     1440×900-Fenster noch mit hineinragen. Gemessen am 16.09.2026: mit
     7rem oben endete der Knopf bei 791 px und der Kasten begann bei 871 —
     ein Streifen von 29 px, in dem nichts zu erkennen war. Mit 4,5rem
     endet der Knopf bei 751 und der Kasten bei 788. */
  --hero-top: clamp(2.5rem, 0.5rem + 5vw, 4.5rem); /* @kind other */
  position: relative;
  /* clip, nicht hidden: hidden machte den Hero zum Scroll-Container, und
     die View-Timeline des Kastens unten richtete sich nach ihm statt nach
     dem Fenster. Nur quer: nach unten ragt der Schwanz des Kastens aus dem
     Hero (siehe --desks-tail). */
  overflow-x: clip;
  overflow-y: visible;
  /* Oben auf dem Nachtgrund liegt ein feines, helles Korn — ein SVG mit
     feTurbulence, das nur in den hellen Körnern durchscheint (die Matrix
     färbt weiß und macht die Helligkeit zur Deckkraft). Es nimmt dem
     Verlauf das Glatte, ohne den Text zu stören. */
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.07 0.07 0.07 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E") 0 0/220px 220px repeat,
    radial-gradient(ellipse 80% 60% at 78% 8%, rgb(var(--violet-rgb) /0.45), transparent 70%),
    radial-gradient(ellipse 60% 50% at 10% 95%, rgb(var(--coral-rgb) /0.28), transparent 70%),
    var(--space);
  color: var(--on-space);
  padding-block: var(--hero-top) clamp(4rem, 2rem + 6vw, 7rem);
}
/* Als erster Abschnitt rückt der Hero unter die Kopfleiste, damit sein
   Himmel hinter ihr durchscheint; der Inhalt bleibt, wo er war. */
main > .hero:first-child {
  margin-top: calc(-1 * var(--bar-h));
  padding-top: calc(var(--bar-h) + var(--hero-top));
}

/* Die Ground Control, als Bild hinter dem Verlauf: der Kontrollraum in
   Houston während Apollo 11 (NASA S69-34316, gemeinfrei; das Original liegt
   in assets/control-room.jpg und wird nicht ausgeliefert). Es ist nicht
   Dekoration, sondern die Zeile darüber — Ground Control Berlin · Empfang
   klar — als Bild.

   Es liegt auf einem eigenen Element und nicht als fünfte Ebene im
   Hintergrund des Hero, weil es nach unten auslaufen muss: eine Maske am
   .hero würde auch die Schrift und die Karten ausblenden. Entsättigt,
   im Kontrast angehoben und auf fünf Tonwerte heruntergebrochen ist schon
   die Datei (die Kette steht in assets/README.md). Die Tontrennung
   stilisiert den Raum zu Flächen statt Fotodetail.

   Das Bild legt Licht auf den Nachtgrund, es nimmt keines weg. Die
   Helligkeit des Raums ist nicht die Farbe der Datei, sondern ihre
   Deckkraft: der Alphakanal trägt die fünf Stufen 0, 42, 84, 126 und 168
   von 255, die Farbe ist auf allen Pixeln derselbe gedämpfte Ton der
   Palette (#9dc2c4, --on-space-muted). Wo der Raum dunkel ist, ist die
   Datei durchsichtig und der Verlauf steht unberührt darunter; wo er
   leuchtet, liegt Licht darauf. Vorher tönte eine zweite Ebene das
   Graubild per multiply — und multiply kann nur abdunkeln, also zog der
   Raum den Kopf über fast ein Drittel der Fläche unter den nackten
   Verlauf: 7,31,38 statt 8,38,46, unter dem violetten Schein 12,56,66
   statt 15,68,80. Genau das war das Düstere. Jetzt steigt die mittlere
   Helligkeit des Streifens von 2,06 auf 3,18 über dem Nachtgrund und von
   4,77 auf 6,87 unter dem Schein (Y in Prozent, gewichtet mit den
   Flächenanteilen der fünf Stufen), und nichts wird irgendwo dunkler als
   ohne Bild.

   Dass die Helligkeit im Alphakanal steht, macht die Kappe zum ersten Mal
   exakt: webp speichert Alpha verlustfrei, also liegen in der Datei
   genau fünf Werte und der oberste ist 168 — kein Überschwingen an den
   Stufenkanten mehr, und keine Aufweitung um 1,164, wie sie eine
   Luma-Ebene mit begrenztem Wertebereich beim Dekodieren erfährt. Die
   einzige verlustbehaftete Ebene ist die Farbe, und die ist auf jedem
   Pixel gleich; eine gleichmäßige Fläche kann nicht überschwingen.

   Deckkraft 0,28, und zwar an Ort und Stelle gemessen statt auf dem
   Papier: für jedes Textelement im Kopf wird die Seite ohne Schrift und
   ohne Himmel gerendert und das hellste Pixel unter dem Kasten des
   Elements gesucht. Der schlechteste Fall ist der gedämpfte Absatz mit
   4,57:1, auf dem Telefon 4,9:1; darüber die Navigation mit 5,2:1, der
   Sprachwechsel mit 5,0:1, die Schlagzeile mit 6,9:1 und die Signalzeile
   mit 12,1:1.

   Die 0,28 stehen hier, weil der Kopf enger geworden ist: --hero-top ist
   von 7rem auf 4,5rem heruntergegangen, damit „Ich bin“ mit ins erste
   Fenster rückt, und damit liegt der Absatz 40 px höher in einem helleren
   Band des Raums. Bei 0,30 traf er auf 4,500:1 — genau die Schwelle, und
   ein Wert, der auf die dritte Stelle genau aufgeht, ist kein Abstand.
   0,28 bringt 4,57:1. Die alte Kappe von 0,34 gilt weiter nicht.

   Gemessen wird am Element und nicht am hellsten Pixel des ganzen
   Streifens, weil das in der Ecke oben rechts liegt, wo der violette
   Schein am stärksten ist — und dort steht kein Fließtext, sondern nur
   die Kopfleiste, deren beide Werte oben mit dabeistehen. Die alte
   Rechnung nahm jenes Pixel als Maß für den ganzen Kopf und hielt die
   Ebene deshalb auf 0,18 fest, obwohl hinter der Schrift viel Luft war.

   Die Mitteltöne hebt darum weiter die Datei und nicht die Deckkraft:
   eine Gammastufe vor der Tontrennung schiebt mehr Pixel in die oberen
   Stufen, ohne die oberste Stufe zu verschieben. Die Deckkraft hebt
   dagegen alles mit, die Kappe eingeschlossen — wer sie anfasst, muss die
   Paare oben neu messen.

   Es bedeckt nicht den ganzen Hero, sondern nur die erste Bildschirmhöhe:
   der Hero ist mit dem Kasten der vier Schreibtische mehrere Fenster hoch
   (siehe --desks-tail), und ein „cover“ über diese Höhe hätte in den Kopf
   nur einen zufälligen Ausschnitt gestellt. 100svh ist der Streifen, der
   bis zum Kasten reicht; darunter läuft das Bild aus, damit es unter dem
   hellen Kasten nicht abgeschnitten endet. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 100svh;
  z-index: 0;
  pointer-events: none;
  background: url("control-room.webp") 50% 34% / cover no-repeat;
  opacity: 0.28;
  mask-image: linear-gradient(to bottom, #000 40%, transparent 94%);
}
/* Auf dem Telefon ist das Fenster hoch und schmal: über die ganze
   Bildschirmhöhe schnitte „cover“ aus dem Raum einen Streifen von einem
   Drittel Breite heraus, der nur noch wie Rauschen aussieht. Ein niedrigerer
   Streifen zeigt gut die Hälfte des Raums — und den Rest bekommt der
   Verlauf. Ein kürzeres Element und nicht ein kleineres Bild, damit die
   Maske am unteren Rand weiter den Übergang macht und nicht die Kante
   eines Bildes, das vor dem Elementrand endet. */
@media (max-width: 48rem) {
  .hero::before {
    height: 62svh;
    background-position: 45% 30%;
    mask-image: linear-gradient(to bottom, #000 26%, transparent 92%);
  }
}

.hero__in { position: relative; z-index: 1; }

.stars { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.stars span {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgb(var(--veil-rgb) / 1);
  /* Ein Hauch Schein um jeden Punkt: über dem Kontrollraum im Hero stand
     der nackte 3-px-Punkt gegen das Fotodetail und war nicht mehr zu
     finden. Im Fuß, wo kein Bild liegt, kostet er nichts. */
  box-shadow: 0 0 7px 1px rgb(var(--veil-rgb) / 0.5);
  opacity: 0.8;
  animation: twinkle 4s ease-in-out infinite;
  animation-delay: var(--d);
}
@keyframes twinkle {
  0%, 100% { opacity: 0.18; transform: scale(0.8); }
  50%      { opacity: 0.95; transform: scale(1.4); }
}
@media (prefers-reduced-motion: reduce) {
  .stars span { animation: none; opacity: 0.5; }
}

/* Kassiopeia über dem ganzen Kopf: dieselben fünf Sterne wie im Zeichen
   über dem Wort (#m15) und wie bei der Besatzung, nur über das Fenster
   gezogen — zwischen Bild und Text. Damit steht das Logo einmal groß im
   Kopf, ohne es zu wiederholen. Es liegt hinter der Schrift (.hero__in hat
   z-index 1) und über dem Foto, das als ::before vor allen Kindern
   gezeichnet wird; beide brauchen deshalb keinen eigenen z-index.

   Die Geometrie ist die des Zeichens, in Prozent umgerechnet: aus 2/9/14/22/30
   von 32 werden 6, 28, 44, 69 und 94 %, aus 20/6/17/4/15 von 1…23 werden
   86, 23, 73, 14 und 64 %. Die Sterne sind Spans an diesen Prozenten, die
   Linien ein SVG ohne viewBox mit Prozentkoordinaten — wie bei .crew, weil
   nur so der Strich eine Haarlinie bleibt statt mit dem Kasten gestreckt zu
   werden. Die Sternradien 2/3/1,6/2,3/1,9 des Zeichens werden 5/7/4/6/5 px;
   der zweite ist der Akzentstern und bleibt bernsteinfarben. Über die volle
   Breite hat die Figur nicht mehr die Proportion des Logos (32:22), sondern
   die des Fensters — gestreckt ist sie schon bei der Besatzung, die Figur
   bleibt erkennbar.

   Es gibt keine dauerhaften Linien. Alle 11 Sekunden läuft ein Impuls die
   Kette ab: er zeichnet seine Strecke, während er sie durchläuft, und was
   er gezeichnet hat, verglimmt danach über vier Sekunden. Zwischen zwei
   Durchläufen liegt der Himmel dunkel, nur die Sterne stehen da. Das ist
   der Funkspruch über die Stationen, und die Pause ist Absicht — ein
   Dauerstrich zöge den Blick von der Schlagzeile weg.

   Zwei Gruppen derselben vier Strecken: .sky__draw ist die Spur, .sky__run
   der Kopf des Impulses. pathLength="100" macht Strichmuster und Zeiten
   unabhängig von der Länge der Strecke, sodass eine Zeitangabe für alle
   vier gilt und 0,7 s pro Strecke überall 0,7 s sind. Beide Gruppen sind
   weich gezeichnet (blur) und weit unter Volldeckkraft: das Licht soll
   glimmen, nicht schneiden. Die Sterne heben sich mit, wenn der Impuls
   ankommt — Versatz 0,7 s je Stern, also genau die Laufzeit einer
   Strecke.

   Die Animationen laufen mit fill-mode backwards, und das ist keine
   Feinheit: während seines Versatzes zeigt ein Element seinen normalen
   Stil, nicht den ersten Keyframe. Ohne backwards stehen die drei noch
   nicht gezeichneten Strecken die erste Sekunde lang fertig gezogen da
   (Versatz 0, also gar kein Strichversatz) und der Impulskopf als
   heller Punkt am Stern. Im Screenshot bei 500 ms war das ganze M zu
   sehen — genau das Gegenteil des Lichtzeichnens. */
.sky {
  position: absolute;
  inset: 5svh 5vw auto 5vw;
  height: 70svh;
  z-index: 0;
  pointer-events: none;
}
.sky span {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--s);
  height: var(--s);
  margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2); /* die Mitte auf den Prozentpunkt, nicht die Ecke */
  border-radius: 50%;
  background: rgb(var(--veil-rgb) / 1);
  box-shadow: 0 0 12px 3px rgb(var(--veil-rgb) / 0.45);
  opacity: 0.62;
  animation: sky-pulse 11s ease-out infinite;
  animation-delay: calc(var(--i) * 0.7s);
}
.sky span.sky__a {
  background: var(--amber);
  box-shadow: 0 0 12px 4px rgb(255 201 92 / 0.35);
}
@keyframes sky-pulse {
  0%        { opacity: 0.62; transform: scale(1); }
  4%        { opacity: 1;    transform: scale(1.8); }
  18%, 100% { opacity: 0.62; transform: scale(1); }
}

.sky__web { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sky__web line {
  fill: none;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.sky__draw { filter: blur(1.6px); }
.sky__draw line {
  stroke: rgb(var(--veil-rgb) / 0.38);
  stroke-width: 1.5;
  stroke-dasharray: 100 100;      /* bei Versatz 100 ist nichts gezeichnet */
  animation: sky-draw 11s linear infinite backwards;
  animation-delay: calc(var(--i) * 0.7s);
}
@keyframes sky-draw {
  0%        { stroke-dashoffset: 100; opacity: 1; }
  6.4%      { stroke-dashoffset: 0;   opacity: 1; }   /* 0,7 s: der Kopf ist am Stern */
  10%       { stroke-dashoffset: 0;   opacity: 1; }
  48%, 100% { stroke-dashoffset: 0;   opacity: 0; }   /* verglimmt über vier Sekunden */
}
.sky__run { filter: blur(2.6px); }
.sky__run line {
  stroke: rgb(var(--veil-rgb) / 0.8);
  stroke-width: 4;
  stroke-dasharray: 7 93;      /* Muster 100 lang, also genau eine Streckenlänge */
  animation: sky-run 11s linear infinite backwards;
  animation-delay: calc(var(--i) * 0.7s);
}
/* Der Kopf läuft bis 93, nicht bis 100: ein Strichversatz rechnet modulo der
   Musterlänge, und die ist hier 100. Bei -100 sitzt der Strich also wieder
   bei 0 — der Impuls tauchte am Anfang der Strecke ein zweites Mal auf und
   verglomm dort, sichtbar 286 ms lang nach jedem Stern. Bei -93 füllt der
   7 lange Strich genau das Ende, 93 bis 100, und wandert nicht weiter. Das
   ist zugleich die richtige Ankunft: der Kopf erreicht den Stern bei 6,4 %,
   und da beginnt der Versatz der nächsten Strecke. */
@keyframes sky-run {
  0%       { stroke-dashoffset: 0;   opacity: 0; }
  1%       { opacity: 1; }
  6.4%     { stroke-dashoffset: -93; opacity: 1; }
  9%, 100% { stroke-dashoffset: -93; opacity: 0; }
}
/* Schmal ist das Fenster hoch: die Figur bleibt über die ganze Breite,
   aber im oberen Teil des Bildstreifens — tiefer stünde sie in der Wand
   aus Text, und der Streifen endet bei 62svh. */
@media (max-width: 48rem) {
  .sky { inset: 7svh 5vw auto 5vw; height: 44svh; }
}
/* Ohne Bewegung gibt es keinen Impuls, der die Linien zeichnen könnte —
   dann stehen sie still da, so leise wie die Spur im Verglimmen. */
@media (prefers-reduced-motion: reduce) {
  .sky span { animation: none; opacity: 0.7; }
  .sky__draw line { animation: none; stroke-dasharray: none; stroke: rgb(var(--veil-rgb) / 0.24); }
  .sky__run { display: none; }
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 2rem;
  padding: 0.4375rem 0.9375rem;
  border-radius: var(--r-pill);
  background: rgb(var(--veil-rgb) / 0.1);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.03em;
}
.tag__sign {
  width: 1.25em; height: 1.25em; flex: none;
  overflow: visible;                       /* der Puls darf über den Rand */
  fill: currentColor;
}
.tag__feed { fill: var(--mint); }
.tag__ring {
  fill: none; stroke: var(--mint); stroke-width: 1;
  transform-box: fill-box; transform-origin: center;
  animation: blip 2.2s ease-out infinite;
}
@keyframes blip {
  0%   { transform: scale(1);   opacity: 0.7; }
  70%  { transform: scale(3.2); opacity: 0; }
  100% { transform: scale(3.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .tag__ring { animation: none; opacity: 0; } }

.big {
  font-size: var(--fs-big);
  line-height: 0.94;
  letter-spacing: -0.045em;
  text-wrap: balance;
}
/* Das eine Wort, das die Angst benennt, bekommt den Unterstrich — von Hand
   gezeichnet wirkt er freundlicher als eine gerade Linie. */
.big__hi {
  color: var(--amber);
  position: relative;
  white-space: nowrap;
}
.big__hi::after {
  content: "";
  position: absolute;
  left: -0.02em;
  right: -0.02em;
  bottom: 0.02em;
  height: 0.09em;
  border-radius: var(--r-pill);
  background: var(--coral);
  transform: rotate(-1.2deg);
  /* Hinter den Text, nicht darüber: bei line-height 0.94 liegt der Strich
     der ersten Zeile auf den i-Punkten der zweiten. Von Hand gezeichnet
     läuft ein Strich hinter dem Buchstaben durch, also tut er das hier
     auch. Er bleibt über dem Nachtgrund, weil .hero__in (z-index 1) und
     .visor__head (z-index 1) je einen eigenen Stapel aufmachen. */
  z-index: -1;
}

.hero__lede {
  margin: clamp(1.75rem, 1rem + 2vw, 2.75rem) 0 0;
  font-size: var(--fs-lede);
  line-height: 1.5;
  color: var(--on-space-muted);
  max-width: 54ch;
}

.hero__act {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 0.5rem + 2vw, 2.25rem);
  flex-wrap: wrap;
  margin: clamp(2rem, 1rem + 3vw, 3rem) 0 0;
}

/* --- Funkmitschnitt ------------------------------------------------------ */

.radio {
  margin: clamp(3rem, 1.5rem + 5vw, 5rem) 0 0;
  max-width: 44rem;
}
.radio__cap {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-bottom: 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--on-space-muted);
}
.radio__dots { display: inline-flex; gap: 0.25rem; }
.radio__dots i { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: rgb(var(--veil-rgb) / 0.28); }
.radio__dots i:first-child { background: var(--coral); }
.radio__dots i:nth-child(2) { background: var(--amber); }

.radio__body {
  background: rgb(var(--veil-rgb) / 0.06);
  border: 1px solid rgb(var(--veil-rgb) / 0.14);
  border-radius: var(--r-lg);
  padding: clamp(1.25rem, 0.75rem + 1.5vw, 2rem);
}
.radio__ask {
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.3125rem);
  font-weight: 600;
  line-height: 1.45;
  color: var(--on-space);
  margin-bottom: 1.25rem;
}
.radio__ans, .radio__wait {
  display: flex;
  gap: 0.625rem;
  margin-bottom: 0.5rem;
  font-size: 0.9375rem;
  color: var(--on-space-muted);
}
.radio__ok { color: var(--mint); font-weight: 700; flex: none; }
.radio__hold { color: var(--amber); flex: none; }
.radio__wait { margin-bottom: 0; color: var(--amber); font-weight: 600; }
.radio__note {
  margin: 0.875rem 0 0;
  font-size: 0.875rem;
  color: var(--on-space-muted);
}

/* --- Vier Schreibtische ---------------------------------------------------
   Dasselbe Muster wie der Mitschnitt, aber auf hellem Grund: weiße Karte,
   nur die Uhrzeit darüber (die Rolle steht schon links), die Frage, drei
   Ergebniszeilen und die Pause vor dem Ja. Die Einordnung steht als
   .pick__intro vor den Karten, im Kasten selbst: sie erklärt die vier
   Schreibtische besser, als sie sich selbst erklären. Die Zeile „?“ ist
   das, was das Harness nicht selbst entscheidet und sichtbar liegen
   lässt. */

.pick {
  display: grid;
  /* Linke Spalte so breit wie der längste Satz — die Sätze brechen nicht. */
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  align-items: start;
  margin-top: clamp(2.5rem, 1rem + 4vw, 4rem);
}
@media (max-width: 58rem) { .pick { grid-template-columns: 1fr; } }
/* Über zwei Spalten steht die Karte links und die Sätze rechts. Links steht
   auf dieser Seite der Inhalt: der Hero darüber, die Einordnung im nullten
   Schritt und danach die Karte beginnen damit an derselben Kante. Die Sätze
   sind die Leiste daneben. In einer Spalte bleibt die Reihenfolge des
   Dokuments — erst die Sätze, dann die Karte, weil dort geklickt wird. */
@media (width > 58rem) {
  /* dense, weil die Bühne im Dokument nach den Sätzen steht und links
     hingehört: die lockere Platzierung setzt sie sonst in eine zweite
     Reihe, weil ihre Spalte links vom Zeiger liegt (gemessen 264 px zu
     tief). Dicht gepackt sucht sie von oben und findet die freie Zelle
     neben den Sätzen. Im Rückfall, wo die Einordnung im Fluss die erste
     Reihe füllt, findet sie dieselbe Reihenfolge wie vorher: Erklärung,
     darunter Sätze und Karte. */
  .pick { grid-template-columns: minmax(0, 1fr) auto; grid-auto-flow: dense; }
  .pick__stage { grid-column: 1; }
  .pick__who { grid-column: 2; }
}

/* Die Einordnung: eine eigene Reihe über beiden Spalten. So liest der
   Rückfall — ohne View-Timeline, bei reduzierter Bewegung, auf der
   Katalogseite — erst die Erklärung und dann die Auswahl. Im Scrollweg
   wird sie daraus herausgenommen (siehe „Vier Schreibtische am
   Scrollweg“), weil sie dort der nullte Schritt ist und nicht der Kopf. */
.pick__intro {
  grid-column: 1 / -1;
  max-width: 44rem;
}
.pick__intro > :last-child { margin-bottom: 0; }
/* Die Überschrift steht im Scrollweg in einer Spalte und nicht über die
   ganze Seite — 3,5rem füllten dort vier Zeilen. Der obere Wert ist auf
   die Spalte gemessen (16.09.2026, 1440 breit: 590 px, drei Zeilen wie
   die Frage auf der ersten Karte daneben). */
.pick__intro .h2 { font-size: clamp(1.625rem, 1rem + 2vw, 2.5rem); }

/* Links: „Ich bin“ und die vier Sätze, groß gesetzt. Die Labels sind die
   Reiter; der gewählte steht in Tinte, die anderen bleiben blass. */
.pick__lead {
  margin: 0 0 0.25rem;
  font-size: clamp(1.125rem, 1rem + 0.6vw, 1.5rem);
  font-weight: 600;
  color: var(--ink-muted);
}
.pick__opt {
  display: block;
  position: relative;
  padding: 0.1em 0 0.1em 1.1em;
  font-size: clamp(1.375rem, 0.8rem + 1.3vw, 2.125rem);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: rgb(var(--ink-rgb) /0.28);
  cursor: pointer;
  user-select: none;
  transition: color 0.25s ease, transform 0.25s ease;
}
.pick__opt::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.55em;
  height: 0.16em;
  border-radius: 999px;
  background: var(--coral);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}
.pick__opt:hover { color: rgb(var(--ink-rgb) /0.6); }
.pick:has(#desk-1:checked) .pick__opt--1,
.pick:has(#desk-2:checked) .pick__opt--2,
.pick:has(#desk-3:checked) .pick__opt--3,
.pick:has(#desk-4:checked) .pick__opt--4 { color: var(--ink); transform: translateX(0.15em); }
.pick:has(#desk-1:checked) .pick__opt--1::before,
.pick:has(#desk-2:checked) .pick__opt--2::before,
.pick:has(#desk-3:checked) .pick__opt--3::before,
.pick:has(#desk-4:checked) .pick__opt--4::before { transform: scaleX(1); }
.pick:has(#desk-1:focus-visible) .pick__opt--1,
.pick:has(#desk-2:focus-visible) .pick__opt--2,
.pick:has(#desk-3:focus-visible) .pick__opt--3,
.pick:has(#desk-4:focus-visible) .pick__opt--4 { outline: 2px solid var(--violet); outline-offset: 4px; border-radius: var(--r-sm); }

/* Wo die Scrollposition wählt, sind die vier Sätze Marken am Weg. Ein Klick
   darf dort nicht umschalten — er soll an die Stelle fahren, an der der
   Satz von selbst dran ist, und das Umschalten macht dann der Weg. Dafür
   liegt über jedem Satz ein leerer Anker: er schluckt den Klick (ein Label
   schaltet nicht, wenn der Klick ein Bedienelement darin getroffen hat) und
   die Seite springt an sein Ziel. Hier nimmt er keine Klicks an, damit im
   Fallback das Label wie bisher selbst schaltet; angeschaltet wird er erst
   im Scrollweg. Er ist leer, aria-hidden und nicht anspringbar: sonst hört
   der Vorleser jeden Satz zweimal, und zu bedienen gibt es hier nichts, was
   die Tastatur nicht schon kann — scrollen. */
.pick__jump {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* Die Ziele der Anker sind Punkte am Scrollweg, keine sichtbaren Dinge.
   Ohne Scrollweg gibt es sie nicht: ein leeres Inline-Element würde dort
   eine Zeile im Kasten aufmachen. */
.pick__mark { display: none; }

/* Im Hero steht die Auswahl in einem hellen, runden Kasten auf Nachtgrund —
   die Sätze bleiben in Tinte, die Karten weiß. Der Grund liegt auf einem
   Pseudo-Element, damit er beim Scrollen wachsen kann, ohne dass sich der
   Inhalt bewegt (siehe „öffnet sich“ unten). */
.hero__desks {
  --desks-pad: clamp(1.5rem, 1rem + 2.5vw, 3rem);
  /* Das Polster der Karte steht hier und nicht bei .radio--desk, weil die
     Einordnung es mitrechnen muss: sie hat keinen weißen Grund, also muss
     ihr Rahmen um dieses Polster einwärts liegen, damit ihre Wörter dort
     stehen, wo gleich die Wörter der Karte stehen. */
  --desk-card-pad: clamp(1.125rem, 0.75rem + 1vw, 1.5rem);
  /* „Erst mal mithören“ im Hero springt hierher. Der Kasten landet unter
     der Kopfleiste mit etwas Luft — neben den Sätzen liegt die Karte um
     Polster und --desk-lift über seiner Oberkante, die Luft zählt ab der
     Karte. Und nie tiefer als 40vh: der Schalter unten kippt, wenn die
     Oberkante 58vh über dem unteren Fensterrand steht, und die Fahrt
     dorthin soll ihn kippen, damit der Kasten sich beim Ankommen öffnet
     (auf flachen Fenstern läge bar + Luft sonst darunter). */
  scroll-margin-top: min(calc(var(--bar-h) + 2rem), 40vh);
  position: relative;
  isolation: isolate;
  /* Eng an den Knopf, aus demselben Grund wie --hero-top: was hier an Luft
     steht, schiebt „Ich bin“ unter den Fensterrand. Die Karte ragt ohnehin
     über die Oberkante des Kastens — um ihr Polster, auf flachen Fenstern
     um mehr —, der Abstand wirkt also größer, als die Zahl aussieht. */
  margin-top: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
  /* Nach rechts bis an den Bildschirmrand: der Kasten ragt um die rechte
     Randspalte hinaus, der Inhalt bleibt in der Spalte. Der Hero schneidet
     ab (overflow clip), also kein Querscrollen. */
  margin-right: calc(50% - 50vw);
  /* Links ragt der Kasten um sein Polster in die Randspalte, damit „Ich
     bin“ bündig mit der Spalte steht — mit der Zeile „Dieselben 14
     Bestellungen“ darunter. Wo die Randspalte schmaler ist als das
     Polster, endet der Kasten am Bildschirmrand. */
  --desks-out: min(var(--desks-pad), var(--gut));
  margin-left: calc(-1 * var(--desks-out));
  padding: var(--desks-pad);
  padding-left: var(--desks-out);
  padding-right: calc(var(--desks-pad) + 50vw - 50%);
  color: var(--ink);
}
.hero__desks::before {
  content: "";
  position: absolute;
  /* Unten reicht der Grund bis --desks-tail unter die Oberkante des
     Kastens, also aus dem Hero hinaus in den nächsten Abschnitt, wenn der
     Kasten kürzer ist als der Schwanz (100 % ist hier die Höhe des
     Kastens). Der Nachtstreifen links läuft so bis unter den Fensterrand,
     während der Kasten sich öffnet, statt mitten im Bild zu enden. */
  inset: 0 0 min(0px, 100% - var(--desks-tail, 0px)) 0;
  z-index: -1;
  /* Nur links oben rund: rechts liegt der Kasten am Rand, unten läuft er in
     den hellen Bogen des nächsten Abschnitts. */
  border-radius: var(--r-lg) 0 0 0;
  background: var(--cream);
}
/* Der Kasten öffnet sich, sobald „Ich bin“ in der Mitte des Fensters
   steht: der helle Grund wächst nach links bis an den Bildschirmrand und
   nach oben bis an den oberen Fensterrand, bis vom Nachtgrund nichts mehr
   zu sehen ist. Der Auslöser hängt am Scrollweg, der Ablauf an der Zeit —
   wie die Kopfleiste, ohne Skript: zwei Scroll-Animationen auf body
   kippen je einen Schalter (nicht registriert, also springt jeder bei der
   Hälfte seines Bereichs, statt mitzulaufen): --desks-near, wenn die
   Oberkante des Kastens 58vh über dem unteren Fensterrand steht, und
   --desks-down, wenn die Seite 15vh weit gescrollt ist. Erst beide
   zusammen sind der Schalter --desks-on (registriert, damit aus dem
   Produkt eine Zahl wird und die Leiste sie lesen kann). Der zweite ist
   da, damit die Seite beim Laden steht: auf einem hohen Fenster ist der
   Kasten schon beim Öffnen der Seite in der Mitte, und ohne den Weg
   liefe der Wechsel beim ersten Bild. Alles, was sich bewegt, folgt dem
   Schalter mit einer Transition — vorwärts beim Scrollen nach unten,
   rückwärts beim Scrollen nach oben, einmal pro Wechsel, nicht Pixel für
   Pixel. Die Transition muss eine Ebene unter der Animation sitzen
   (siehe Kopfleiste); body trägt die Schalter, weil --desks in seinem
   Geltungsbereich steht und der Abschnitt nach dem Hero mitgeht. Jedes
   Teil hat seine Verzögerung --t, und sie gilt in beide
   Richtungen: aus dem Schalter lässt sie sich nicht mischen, weil ein
   von einer Animation gesetzter Wert in transition-* ungültig ist
   („animation-tainted“). Dass rückwärts dieselbe Reihenfolge läuft,
   fällt nicht auf: der Grund des Kastens liegt über dem Text im Hero,
   also verschwindet der Text vorwärts, kurz bevor der Grund ihn erreicht,
   und rückwärts kommt er unter dem Grund wieder, der ihn beim Zurückweichen
   freigibt.
   Die Timeline trägt der Kasten selbst, nicht das Pseudo-Element: das
   bewegt sich ja und wäre als Maß seiner selbst ein Kreisel. Die linke
   Kante ist um die Fensterbreite von der rechten entfernt, die am Rand
   liegt — daher 100% − 100vw. Die Rundung läuft dabei aus, sonst bliebe
   in der Ecke des Fensters ein dunkler Rest. Browser ohne View-Timeline
   und Leser mit reduzierter Bewegung sehen den Kasten, wie er steht. */
@property --desks-on { syntax: "<number>"; inherits: true; initial-value: 0; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* view-timeline-name: --desks steht bei der Kopfleiste, neben --night-1-end. */
    body {
      --desks-near: 0; /* @kind other */
      --desks-down: 0; /* @kind other */
      --desks-on: calc(var(--desks-near) * var(--desks-down)); /* @kind other */
      animation: desks-near linear both, desks-down linear both;
      animation-timeline: --desks, scroll(root);
      animation-range: cover 54vh cover 62vh, 10vh 20vh;
    }
    @keyframes desks-near {
      from { --desks-near: 0; }
      to   { --desks-near: 1; }
    }
    @keyframes desks-down {
      from { --desks-down: 0; }
      to   { --desks-down: 1; }
    }
    .hero:has(.hero__desks) :is(.tag, .big, .hero__lede, .hero__act),
    .hero__desks::before {
      transition-delay: var(--t);
    }
    .hero__desks::before {
      /* Der Anstieg endet am oberen Fensterrand: beim Wechsel steht die
         Oberkante des Kastens höchstens 58vh über dem unteren Fensterrand,
         also höchstens 100vh − 58vh unter dem oberen — so weit muss der
         Grund hinauf, mit etwas Luft (steht der Kasten höher, weil erst
         der Scrollweg den Wechsel gibt, reicht es erst recht). Wer den
         Wechsel verschiebt, ändert beide Zahlen. dvh,
         weil der Scrollport auf dem Handy mit der Browserleiste wächst und
         schrumpft, die Range aber daran misst. */
      --desks-rise: calc(100dvh - 56vh);
      /* Nur so viel Vorsprung, wie der Text braucht, um vor dem Grund
         weg zu sein — nicht mehr (war 0,3 s). */
      --t: 0.12s;
      left: calc((100% - 100vw) * var(--desks-on));
      top: calc(-1 * var(--desks-rise) * var(--desks-on));
      border-top-left-radius: calc(var(--r-lg) * (1 - var(--desks-on)));
      transition-property: left, top, border-top-left-radius;
      /* Kurz und vorne steil: der Wechsel hängt am Scrollweg, also darf
         er nicht nachziehen. Mit 0,3 s Verzögerung und 0,5 s ease-in-out
         begann hier nach dem Auslösen fast eine Sekunde lang nichts
         Merkliches, und das las sich wie Trägheit statt wie Antwort.
         ease-out legt die Strecke vorne zurück, so dass der Grund sofort
         geht und am Fensterrand ausläuft. */
      transition-duration: 0.3s;
      transition-timing-function: ease-out;
    }
    /* Während der Kasten sich öffnet, geht der Text darüber: Zeile für
       Zeile, von oben nach unten — Zeile, Überschrift, Vorspann, Knöpfe —
       steigt jede ein Stück, verblasst und verschwimmt. Der Text geht
       voraus: er beginnt vor dem Kasten und ist fort, bevor der Grund den
       oberen Fensterrand erreicht — sonst schöbe sich der Grund über die
       Knöpfe. */
    .hero:has(.hero__desks) :is(.tag, .big, .hero__lede, .hero__act) {
      opacity: calc(1 - var(--desks-on));
      translate: 0 calc(-2rem * var(--desks-on));
      filter: blur(calc(12px * var(--desks-on)));
      transition-property: opacity, translate, filter;
      transition-duration: 0.18s;
      transition-timing-function: ease-in;
    }
    /* Der Versatz ist auf ein Drittel gekürzt (war 0,08 s je Zeile). Er
       soll die Reihenfolge lesbar machen, nicht den Wechsel verlängern:
       die letzte Zeile ist nach 0,27 s fort, der Grund braucht bis 0,42 s
       an den oberen Fensterrand. Die Ordnung — Text zuerst, Grund
       hinterher — bleibt damit erhalten. */
    .hero:has(.hero__desks) .tag        { --t: 0s; }
    .hero:has(.hero__desks) .big        { --t: 0.03s; }
    .hero:has(.hero__desks) .hero__lede { --t: 0.06s; }
    .hero:has(.hero__desks) .hero__act  { --t: 0.09s; }
    /* „Ich bin“ mit den vier Sätzen bewegte sich hier einmal mit: die
       Spalte stand 2,5rem tiefer und rückte am Schalter um bis zu 8rem
       nach oben an die Höhe der Karte. Das ist weg, und zwar aus zwei
       Gründen. Der Kasten reicht jetzt ins erste Fenster (siehe
       --hero-top), also fand die Bewegung vor den Augen des Lesers statt
       statt unter dem Fensterrand — und sie kam mit 0,3 s Verzögerung und
       0,5 s Dauer, was sich beim Scrollen wie Nachziehen anfühlt. Und die
       Höhe, die sie holen sollte, holt jetzt die Geometrie: der Block ist
       auf 24rem gekappt, damit die Spalte ohne jede Bewegung dort steht,
       wo sie hingehört.
       Die Spalte steht damit auf allen Breiten am Polster, wie auf dem
       Handy schon vorher. Die Karte liegt nach wie vor darüber — sie ragt
       über die Oberkante des Kastens hinaus, und der Versatz zwischen
       Karte und erster Zeile ist jetzt derselbe, ob der Kasten offen ist
       oder nicht. */
    /* Der Kopf des nächsten Abschnitts stieg hier einmal am Schalter mit,
       weil er direkt unter dem Kasten stand. Seit der Kasten vier
       Schreibtische hoch ist (siehe „Vier Schreibtische am Scrollweg“),
       liegt er knapp drei Bildschirme weiter unten: der Schalter kippte
       lange, bevor der Leser dort ankommt, und die Zeilen stünden schon
       fertig da. Ohne die Regel gilt wieder rise-in an der eigenen
       View-Timeline wie bei jedem anderen Abschnittskopf — dort ist das
       jetzt das Richtige. */
  }
}
.hero__desks .pick { margin-top: 0; }
/* Die Karte steht nicht im Kasten, sie liegt auf ihm: neben den Sätzen
   ragt sie um ihr eigenes Polster und ein Stück mehr über die Oberkante
   des Kastens hinaus in den Nachtgrund und um ihr Polster nach links über
   dessen Rand. Nach links, weil sie dort steht (siehe „Zwei Spalten“
   oben), und genau um das Polster: dann stehen ihre Wörter auf der Kante
   der Spalte, wie die des Heros darüber. Der Kasten ragt um sein eigenes,
   größeres Polster in die Randspalte, die Karte bleibt also innerhalb
   seines Grundes — gemessen am 16.09.2026 auf 1440 breit 24 px Karte
   gegen 48 px Kasten, auf 1024 breit 22 gegen 39.
   Ränder, nicht translate: so schließt der
   Kasten unter der Karte, statt eine Lücke zu lassen. Nur neben den
   Sätzen — in einer Spalte steht sie unter ihnen und bleibt im Kasten.
   Der Überstand nach oben steht beim Scrollweg (siehe „Vier Schreibtische
   am Scrollweg“), weil er nur dort stimmt: dort ist die Karte der Kopf
   des klebenden Blocks. Steht die Einordnung im Fluss über ihr, gibt es
   keine Oberkante zu überragen — die Karte zöge sich stattdessen über
   den Absatz der Einordnung. */
@media (width > 58rem) {
  .hero__desks {
    --desk-lift: clamp(1.5rem, 0.5rem + 2.5vw, 3rem);
    --desk-side: clamp(1.5rem, 1rem + 2vw, 3rem);
    scroll-margin-top: min(calc(var(--bar-h) + var(--desks-pad) + var(--desk-lift) + 2rem), 40vh);
  }
  .hero__desks .pick__stage {
    margin-inline: calc(-1 * var(--desk-card-pad)) var(--desk-side);
  }
}
/* Der Schwanz des Kastens: solange der Kasten sich öffnet, muss der
   Nachtgrund links neben ihm bis unter den Fensterrand reichen (der
   Wechsel kommt, wenn die Oberkante 42vh unter dem oberen Fensterrand
   steht, der Grund muss also 58vh unter ihr noch stehen — und weiter,
   weil der Kasten sich in der Zeit öffnet und der Leser derweil
   weiterscrollt). Gemessen wird ab der Oberkante des Kastens, nicht
   ab dem Hero: ist der Kasten kürzer als der Schwanz, ragen sein heller Grund
   (::before) und ein Nachtstreifen darunter (::after) um den Rest aus dem
   Hero hinaus über den nächsten Abschnitt — der Streifen schließt sich mit
   dem Kasten. Ist der Kasten höher, gibt es keinen Schwanz. Der Hero endet
   deshalb am Kasten und der nächste Abschnitt folgt ohne Versatz; nur sein
   Inhalt liegt über dem Schwanz, sein eigener heller Grund darunter (der
   Hero ist positioniert und malt über den Grund des statischen Nachbarn,
   der positionierte .wrap danach wieder über den Hero). Ohne View-Timeline
   (und bei reduzierter Bewegung) gibt es keinen Schwanz — der Streifen
   bliebe sonst stehen. */
.hero:has(.hero__desks) {
  padding-bottom: 0;
  /* Der Korallenschein unten links wandert in den Streifen (::after), damit
     er nicht an der Unterkante des Hero abreißt, sondern mit dem Schwanz
     zu Ende geht. */
  background:
    radial-gradient(ellipse 80% 60% at 78% 8%, rgb(var(--violet-rgb) /0.45), transparent 70%),
    var(--space);
}
.hero__desks::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: min(0px, 100% - var(--desks-tail, 0px));
  left: calc(100% - 100vw);
  width: 100vw;
  z-index: -2;
  background:
    radial-gradient(ellipse 60% 50% at 10% 100%, rgb(var(--coral-rgb) /0.28), transparent 70%),
    var(--space);
}
@supports (animation-timeline: view()) {
  .hero:has(.hero__desks) { --desks-tail: 100vh; }
  @media (prefers-reduced-motion: reduce) {
    .hero:has(.hero__desks) { --desks-tail: 0px; }
  }
}
/* Der Abschnitt danach setzt mit seinem eigenen Abstand an. Die Zeile
   „Dieselben 14 Bestellungen“ stand hier einmal und musste dicht am
   Kasten bleiben; sie ist jetzt der nullte Schritt im Kasten selbst. */
.hero:has(.hero__desks) + .sec > .wrap { position: relative; z-index: 1; }
/* Der übernächste Abschnitt hatte hier einmal weißen Grund und eine
   eigene Ebene, weil der Schwanz auf hohen Fenstern über ihn hinausragte.
   Seit der Kasten gut vier Schritte hoch ist, ist der Schwanz nur noch auf
   flachen Fenstern überhaupt da (siehe „Vier Schreibtische am
   Scrollweg“), und dort ist er ein Streifen von rund 100 px — er reicht
   nicht einmal über das Polster des nächsten Abschnitts. Die Regel traf
   nach dem Wegfall des alten Abschnitts „Ein Problem, vier Seiten“ auf
   einen cremefarbenen Abschnitt und hätte ihn weiß gemalt. */

/* Rechts: nur der gewählte Mitschnitt ist zu sehen, und er fährt beim
   Wechsel ein. Alle vier liegen in derselben Rasterzelle übereinander, so
   ist die Bühne immer so hoch wie die höchste Karte und beim Wechsel
   rutscht nichts unter ihr. Die drei anderen sind nur unsichtbar, nicht
   weg — deshalb hängt der Animationsname an einer Variablen: none für die
   unsichtbaren, der Name für die gewählte. Der Wechsel des Namens startet
   die Animation jedes Mal neu. */
.pick__stage { min-width: 0; display: grid; }
.pick .desk {
  grid-area: 1 / 1;
  visibility: hidden;
  animation: var(--desk-in, none) 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.pick:has(#desk-1:checked) .desk--1,
.pick:has(#desk-2:checked) .desk--2,
.pick:has(#desk-3:checked) .desk--3,
.pick:has(#desk-4:checked) .desk--4 {
  visibility: visible;
  --desk-in: desk-in;
  --desk-line: desk-line;
}
.desk .radio__ans, .desk .radio__wait, .desk .radio__note {
  animation: var(--desk-line, none) 0.45s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.desk .radio__ans:nth-child(2) { animation-delay: 0.18s; }
.desk .radio__ans:nth-child(3) { animation-delay: 0.30s; }
.desk .radio__ans:nth-child(4) { animation-delay: 0.42s; }
.desk .radio__wait { animation-delay: 0.54s; }
.desk .radio__note { animation-delay: 0.66s; }
@keyframes desk-in {
  from { opacity: 0; transform: translateY(1.5rem) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
@keyframes desk-line {
  from { opacity: 0; transform: translateX(-0.5rem); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .desk, .desk .radio__ans, .desk .radio__wait, .desk .radio__note { animation: none; }
  .pick__opt, .pick__opt::before { transition: none; }
}

/* --- Vier Schreibtische am Scrollweg --------------------------------------
   Im Hero wählt nicht mehr der Leser, sondern der Weg: der Kasten wird so
   hoch wie gut vier Schritte, die Karte klebt darin fest, und alle 0,7
   Bildschirme rückt es einen weiter. Vier Schreibtische sind der Punkt des
   Abschnitts — wer klickt, sah bisher einen davon.

   Der nullte Schritt ist die Einordnung (.pick__intro) und hat keine
   Karte: der Leser bekommt erst gesagt, was er gleich sieht. Er ist ein
   achtel Schritt, nicht ein ganzer (16.09.2026): der Kasten ist hell und
   der Block steht still, lange bevor die contain-Strecke etwas tut — auf
   1440×900 wird es bei y=420 hell, der Text ist ab da voll lesbar, und der
   Block hängt ab y=560. Die erste Karte kam trotzdem erst bei y=1460, also
   580 Pixel nach dem Stillstand, und Weg, auf dem nichts passiert, liest
   sich als hängengeblieben. Ein achtel Schritt bringt sie auf y=867, rund
   300 Pixel nach dem Stillstand; zum Lesen bleiben die 445 Pixel von 420
   bis dahin.

   Warum nicht ganz auf den Wechsel ins Helle: der Block müsste dafür 124
   Pixel tiefer stehen (seine Ruhelinie liegt auf 1440×900 bei 292 px). Dann
   stünden 416 px leeres Creme über dem Inhalt — genau das, was die Kappe
   unten wegrechnet — und auf 780 px Fensterhöhe wäre der Fuß der Karte um
   53 px abgeschnitten.

   Alles hängt an --desk-run, der View-Timeline des Kastens (deklariert
   oben bei den Nachtabschnitten). Der Bereich contain 0 %–100 % läuft von
   „Oberkante des Kastens am oberen Fensterrand“ bis „Unterkante am
   unteren“ — bei einem Kasten, der höher ist als das Fenster, ist das
   genau seine Höhe minus ein Fenster, hier also 4,125 × --desk-step. Daher
   die Dreiunddreißigstel: die Einordnung bekommt eins, jeder Schreibtisch
   acht.

   Warum Animationen und nicht Schalter: die Radios bleiben als Rückfall in
   der Seite, und ihre :has()-Regeln sind spezifischer als alles, was hier
   stünde. Ein von einer Animation gesetzter Wert schlägt jede normale
   Deklaration, egal wie spezifisch — deshalb tragen Sichtbarkeit, Farbe
   und der Korallenstrich hier je eine eigene Animation.

   Zwei Sonderfälle bei den Keyframes. Die Einordnung steht schon, bevor
   ihr Fenster beginnt (sonst wäre der Kasten beim Ankommen leer), dafür
   sind desk-run-first da. Und der letzte Schreibtisch bleibt stehen, wenn
   seins zu Ende ist (sonst wäre der Kasten leer, während er sich vom
   Fenster löst). Der erste Schreibtisch braucht nichts davon mehr: im
   nullten Schritt soll gerade nichts markiert sein.

   Ohne View-Timeline und bei reduzierter Bewegung bleibt alles, wie es
   war: der Kasten ist so hoch wie sein Inhalt, die Einordnung steht als
   eigene Reihe über der Auswahl, und die vier Radios wählen wie bisher. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero__desks {
      /* 0,7 Bildschirme je Schritt, vier davon plus ein Achtel für den
         nullten, plus das eine Fenster, das der Bereich contain selbst
         kostet. */
      --desk-step: 70vh;
      min-height: calc(100vh + 4.125 * var(--desk-step));
    }
    /* Der Block klebt und steht mittig in seiner Höhe. Mittig ist nötig,
       weil die Leiste ihn sonst anschneidet: die Karte ragt über die
       Oberkante des Blocks hinaus und damit über den Anschlagpunkt.
       Mittig ist das gelöst, ohne den Überstand nachzurechnen.
       Und er ist so hoch wie das Fenster ohne Leiste, sonst stünde er
       oben angeschlagen und darunter läge ein Fenster leerer Grund.
       svh statt vh: auf dem Handy wächst und schrumpft die Browserleiste,
       und der Block soll dabei nicht springen. */
    .hero__desks > .pick {
      position: sticky;
      top: var(--bar-h);
      min-height: calc(100svh - var(--bar-h));
      align-content: center;
    }

    /* Zwei Spalten: die Höhe wird bei 24rem gekappt, und der
       Anschlagpunkt trägt die Differenz.
       Warum: ein ganzes Fenster Höhe heißt auf einem hohen Fenster ein
       halbes Fenster leerer Grund über dem Inhalt, und der schob „Ich
       bin“ unter den Fensterrand. Gemessen am 16.09.2026 auf 1440×900:
       die Zeile lag 306 px darunter, 247 davon allein aus dieser Mitte.
       Gekappt beginnt der Kasten früher und klebt trotzdem mittig im
       Fenster — angeschlagen unter der Leiste sähe der Block beim
       Durchscrollen aus wie auf Anschlag gerutscht.
       Die Kappe ist keine zugesagte Höhe, sie begrenzt nur, wie viel
       leeren Grund die Mitte oben auflegen darf; ist der Inhalt höher,
       wächst der Block darüber hinaus. Gemessen am 16.09.2026 ist der
       Inhalt 314 px bei 1280 breit, 336 bei 1440 und 417 bei 930 — für
       alle vier Schreibtische gleich, weil sie in einer Rasterzelle
       übereinanderliegen. 24rem (384 px) liegt zwischen diesen Werten,
       und genau das ist gewollt: über dem Inhalt bleibt fast keine Mitte
       mehr übrig, und „Ich bin“ steht ohne jede Bewegung dort, wo die
       Spalte vorher erst nach dem Schalter ankam.
       Dass der Fuß dabei aus dem Fenster ragen könnte, ist nachgerechnet:
       das passiert erst, wenn der Inhalt höher wird als (Fenster − Leiste
       + Kappe) / 2. Das flachste Fenster, das hier überhaupt klebt, ist
       34rem hoch (darunter greift der Rückfall weiter unten), also liegt
       die Grenze bei 430 px — über den 417 px des schmalsten Falls.
       Nur zwei Spalten, weil der gestapelte Block das nicht verträgt: auf
       einer Spalte ist der Inhalt 568 px hoch (768 breit) bis 764 px
       (Handy), weit über der Grenze. Zu holen ist dort ohnehin nichts:
       auf einer Spalte steht „Ich bin“ schon 25 px unter der Oberkante
       des Kastens. */
    @media (width > 58rem) {
      .hero__desks > .pick {
        --desk-panel: 24rem;
        top: calc(var(--bar-h) + (100svh - var(--bar-h) - var(--desk-panel)) / 2);
        min-height: var(--desk-panel);
      }
    }

    /* Die Einordnung liegt auf der Bühne statt über ihr: dieselbe
       Rasterzelle wie die Karten, nur aus dem Fluss genommen. Aus dem
       Fluss, weil sie sonst die Höhe des klebenden Blocks bestimmte —
       gemessen am 16.09.2026 ist sie in der Spalte der Bühne 540 px hoch
       gegen 428 px der höchsten Karte, und die Rechnung zur Kappe oben
       hängt daran, dass die Reihe so hoch ist wie die Auswahl selbst.
       Ein absolut gesetztes Rasterkind mit fester Zelle nimmt die Zelle
       als Bezug (der Block klebt, ist also ohnehin der Bezugsrahmen), und
       damit steht die Einordnung dort, wo gleich die erste Karte steht.
       Nicht in der Mitte der Zelle, sondern genau auf dem Textfeld der
       Karte: gemessen am 16.09.2026 stand die Einordnung sonst 68 px
       links und 74 px unter der ersten Karte (1440×900), und der Leser
       sah beim ersten Wechsel einen Sprung nach rechts oben. Deshalb das
       Polster der Karte als Einzug — sie vergleicht Wörter mit Wörtern,
       nicht Rahmen mit Rahmen. */
    /* Beide Spaltenkanten, nicht nur die linke: eine offene Kante geht bei
       einem absolut gesetzten Rasterkind bis an den Rand des Rasters, und
       die Einordnung lief damit über die Sätze (gemessen am 16.09.2026 auf
       1440 breit bis x 1205 statt bis x 699). Vor dem Spaltentausch fiel
       das nicht auf, weil die Karte in der letzten Spalte stand. */
    .hero__desks .pick__intro {
      grid-area: 1 / 1 / auto / 2;
      position: absolute;
      inset: var(--desk-card-pad) var(--desk-card-pad) auto;
      animation: desk-run-first linear both;
      animation-timeline: --desk-run;
    }
    /* Auf einer Spalte stehen die Sätze über der Bühne, die Zelle der
       Karten ist also die zweite Reihe der ersten Spalte. */
    @media (max-width: 58rem) {
      .hero__desks .pick__intro { grid-area: 2 / 1; }
    }
    /* Und nur hier ragt die Karte über die Oberkante des Kastens (siehe
       „Vier Schreibtische“): sie ist der Kopf des klebenden Blocks, die
       Einordnung liegt daneben und nicht darüber. Was die Bühne an Rand
       verschiebt, verschiebt die Einordnung mit — sonst wäre der Sprung
       oben nur halb weg. Auf flachen Fenstern liegt ihr Rahmen dabei an
       der Oberkante des Kastens (gemessen 4 px darunter auf 1440×900,
       5 px darüber auf 1024×768) und die Schrift eine halbe Zeilenhöhe
       tiefer, steht also auf Creme und nicht auf dem Nachtgrund; über
       40 rem Höhe steht das Polster des Kastens darüber (siehe unten). */
    @media (width > 58rem) {
      .hero__desks .pick__stage {
        margin-top: calc(-1 * (var(--desks-pad) + var(--desk-lift)));
      }
      .hero__desks .pick__intro {
        top: calc(var(--desk-card-pad) - var(--desks-pad) - var(--desk-lift));
        /* Die Karte ragt links um ihr Polster aus der Zelle heraus, ihr
           Textfeld beginnt also genau an der Zellkante. Rechts hält sie
           --desk-side Abstand zu den Sätzen, dazu ihr Polster. */
        left: 0;
        right: calc(var(--desk-card-pad) + var(--desk-side));
      }
      /* Auf hohen Fenstern ragt die Karte nur um ihr eigenes Polster
         heraus: ihr Textfeld beginnt dann genau auf der Oberkante der
         Reihe, und die Einordnung mit ihr. Der Grund ist die Ankunft —
         solange der Kasten dunkel ist und der Block noch nicht klebt,
         stand die erste Zeile der Einordnung 4 px unter seiner Oberkante
         (1440×900) und klebte am Rand. Jetzt bleibt dort das Polster des
         Kastens stehen, gemessen 48 px, und am Sprungziel von „Erst mal
         mithören“ 100 statt 56.
         Nur über 40 rem Höhe, weil die Reihe dabei um 68 px wächst und
         der Fuß der Karte auf flachen Fenstern sonst aus dem Bild läuft:
         bei 930×545 sind heute 13 px Luft, gekürzt fehlten 33 px. Der
         engste Fall über der Grenze ist 930×640 mit 11 px Luft, und ab
         1024 breit sind es über 50 (gemessen am 16.09.2026). Darunter
         bleibt --desk-lift, was es war. */
      @media (height >= 40rem) {
        .hero__desks .pick__stage { margin-top: calc(-1 * var(--desk-card-pad)); }
        .hero__desks .pick__intro { top: 0; }
      }
    }

    /* Die Sätze links sind Marken am Weg, keine Schalter mehr — und die
       Radios dahinter sind still: versteckt nimmt sie der Browser aus der
       Tabreihenfolge und aus dem Vorlesebaum. Ein Bedienelement, das nicht
       mehr bedient, soll auch keins mehr sein. #desk-1 bleibt angehakt, es
       trägt den Zustand für den Fallback.
       Ein Klick auf einen Satz fährt aber an seine Stelle: das macht der
       Anker darüber (siehe .pick__jump). Der Zeiger und die Hover-Farbe
       hängen deshalb an ihm — das Label selbst nimmt weiter keine Klicks
       an, und über den Anker greift sein :hover trotzdem. */
    .hero__desks .pick__opt { cursor: default; pointer-events: none; }
    .hero__desks .pick__jump { pointer-events: auto; cursor: pointer; }
    .hero__desks .pick .vh { visibility: hidden; }

    /* Die vier Ziele. Ein Schritt ist acht Dreiunddreißigstel des Wegs, und
       der Weg ist 4,125 × --desk-step lang (die Fensterhöhe fällt heraus,
       siehe oben bei contain). Die Mitte des Fensters von Schritt k liegt
       damit bei (k − 0,375) × --desk-step — dort steht die Karte ruhig, vor
       dem Ausblenden am Fensterende. Ohne das Polster des Kastens: gemessen
       am 16.09.2026 liegt top: 0 hier auf seiner Außenkante, genau dort, wo
       auch der Zeitstrahl beginnt (1440×900: Kasten 788, Marke bei top: 0
       ebenfalls 788, der klebende Block dagegen 836). Käme eine Maschine
       auf die Polsterkante, läge der Klick ein Polster früher — 48 px in
       einem Fenster von 630, die Karte steht dort längst ruhig.
       Kein scroll-margin: die Marke soll genau an den oberen Fensterrand,
       nicht unter die Leiste — sie ist nichts, was man sehen muss. */
    .hero__desks .pick__mark {
      display: block;
      position: absolute;
      left: 0;
      width: 0;
      height: 0;
    }
    .hero__desks .pick__mark--1 { top: calc(0.625 * var(--desk-step)); }
    .hero__desks .pick__mark--2 { top: calc(1.625 * var(--desk-step)); }
    .hero__desks .pick__mark--3 { top: calc(2.625 * var(--desk-step)); }
    .hero__desks .pick__mark--4 { top: calc(3.625 * var(--desk-step)); }

    .hero__desks .desk {
      animation: desk-run linear both;
      animation-timeline: --desk-run;
    }
    .hero__desks .pick__opt {
      animation: opt-run linear both;
      animation-timeline: --desk-run;
    }
    .hero__desks .pick__opt::before {
      animation: opt-dash linear both;
      animation-timeline: --desk-run;
    }
    /* „Ich bin“ kommt erst mit der ersten Karte. Im nullten Schritt steht
       die Erklärung und daneben nur die vier Sätze: die Zeile gehört zur
       Karte — „Ich bin … die Geschäftsführung“, und links dazu die Frage
       dieses Schreibtischs — und ohne Karte hängt sie in der Luft. Sie
       blendet im Fenster des ersten Schreibtischs ein, zusammen mit ihr,
       und bleibt dann stehen. Deckkraft und nicht Sichtbarkeit: die Zeile
       behält ihren Platz, damit die vier Sätze beim Erscheinen nicht
       springen. */
    .hero__desks .pick__lead {
      animation: lead-run linear both;
      animation-timeline: --desk-run;
      animation-range: contain 3.03% contain 27.27%;
    }
    /* Die Fenster der fünf Schritte. Pseudo-Elemente dürfen nicht in
       :is() stehen, darum die Striche in eigenen Zeilen. */
    .hero__desks .pick__intro                 { animation-range: contain 0% contain 3.03%; }
    .hero__desks :is(.desk--1, .pick__opt--1) { animation-range: contain 3.03% contain 27.27%; }
    .hero__desks :is(.desk--2, .pick__opt--2) { animation-range: contain 27.27% contain 51.52%; }
    .hero__desks :is(.desk--3, .pick__opt--3) { animation-range: contain 51.52% contain 75.76%; }
    .hero__desks :is(.desk--4, .pick__opt--4) { animation-range: contain 75.76% contain 100%; }
    .hero__desks .pick__opt--1::before { animation-range: contain 3.03% contain 27.27%; }
    .hero__desks .pick__opt--2::before { animation-range: contain 27.27% contain 51.52%; }
    .hero__desks .pick__opt--3::before { animation-range: contain 51.52% contain 75.76%; }
    .hero__desks .pick__opt--4::before { animation-range: contain 75.76% contain 100%; }
    .hero__desks .desk--4 { animation-name: desk-run-last; }
    .hero__desks .pick__opt--4 { animation-name: opt-run-last; }
    .hero__desks .pick__opt--4::before { animation-name: opt-dash-last; }

    /* 10 % und 90 %: der Wechsel liegt in den ersten und letzten sieben
       Bildschirmhundertsteln eines Fensters, dazwischen steht die Karte
       ruhig. visibility springt dabei (sie kennt keine Zwischenwerte), die
       Deckkraft blendet. */
    @keyframes desk-run {
      0%        { opacity: 0; visibility: hidden;  translate: 0 1.25rem; }
      10%, 90%  { opacity: 1; visibility: visible; translate: 0 0; }
      100%      { opacity: 0; visibility: hidden;  translate: 0 -0.75rem; }
    }
    @keyframes desk-run-first {
      0%, 90%   { opacity: 1; visibility: visible; translate: 0 0; }
      100%      { opacity: 0; visibility: hidden;  translate: 0 -0.75rem; }
    }
    @keyframes desk-run-last {
      0%        { opacity: 0; visibility: hidden;  translate: 0 1.25rem; }
      10%, 100% { opacity: 1; visibility: visible; translate: 0 0; }
    }
    /* transform: none steht in jedem Bild, und zwar gegen die Klickfassung:
       dort rückt der gewählte Satz um 0,15em nach rechts, und weil #desk-1
       für den Fallback angehakt bleibt, stand dieser Ruck hier fest auf dem
       ersten Satz — gemessen 4,7 px auf 1440 breit, in jeder Scrollposition.
       Der erste Satz sah damit dauerhaft weiter eingerückt aus als die
       anderen drei. Hier markieren Tinte und Korallenstrich, ein Ruck wäre
       nur Unruhe. Es steht in den Bildern und nicht in einer Regel, weil
       die :has()-Regel dahinter einen Id-Wert zählt: ein Animationswert
       schlägt sie, eine normale Deklaration nicht. In jedem Bild derselbe
       Wert, damit nichts dazwischen wandert. */
    @keyframes opt-run {
      0%        { color: rgb(var(--ink-rgb) /0.28); transform: none; }
      10%, 90%  { color: var(--ink); transform: none; }
      100%      { color: rgb(var(--ink-rgb) /0.28); transform: none; }
    }
    @keyframes opt-run-last {
      0%        { color: rgb(var(--ink-rgb) /0.28); transform: none; }
      10%, 100% { color: var(--ink); transform: none; }
    }
    @keyframes opt-dash {
      0%        { transform: scaleX(0); }
      10%, 90%  { transform: scaleX(1); }
      100%      { transform: scaleX(0); }
    }
    @keyframes opt-dash-last {
      0%        { transform: scaleX(0); }
      10%, 100% { transform: scaleX(1); }
    }
    /* 10 %: dieselben sieben Bildschirmhundertstel, in denen die erste
       Karte hereinkommt (siehe desk-run). */
    @keyframes lead-run {
      0%        { opacity: 0; }
      10%, 100% { opacity: 1; }
    }

    /* Flache Fenster: ein Handy im Querformat, ein kurzes Browserfenster.
       Dort passt der klebende Block nicht zwischen Leiste und unteren
       Rand, und der Leser sähe von jeder Karte nur die obere Hälfte. Da
       ist der Picker von heute die bessere Fassung — er steht ja noch. Die
       34rem sind gegriffen, nicht gemessen: ein Schreibtisch braucht mit
       Sätzen und Karte rund 540 px, und das ist die Grenze, ab der eine
       ganze Karte sicher ins Fenster geht. Wer hier misst, misst am
       flachsten Gerät, das zählt. */
    @media (height < 34rem) {
      .hero__desks { min-height: 0; }
      .hero__desks > .pick { position: static; min-height: 0; align-content: start; }
      /* Die Einordnung steht wieder über der Auswahl, im Fluss — und die
         Karte dann wieder in ihrer Zelle, ohne Überstand nach oben. */
      .hero__desks .pick__intro { grid-area: auto / 1 / auto / -1; position: static; animation: none; }
      .hero__desks .pick__stage { margin-top: 0; }
      .hero__desks :is(.desk, .pick__opt, .pick__lead), .hero__desks .pick__opt::before { animation: none; }
      .hero__desks .pick__opt { cursor: pointer; pointer-events: auto; }
      /* Hier wählt der Klick wieder selbst, also muss der Anker den Klick
         wieder durchlassen und seine Marke verschwindet mit dem Scrollweg. */
      .hero__desks .pick__jump { pointer-events: none; }
      .hero__desks .pick__mark { display: none; }
      .hero__desks .pick .vh { visibility: visible; }
    }
  }
}

.radio--desk {
  margin: 0;
  max-width: none;
  display: flex;
  flex-direction: column;
  padding: var(--desk-card-pad);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) /0.06), 0 10px 30px rgb(var(--ink-rgb) /0.05);
}
.radio--desk .radio__cap {
  margin-bottom: 0.5rem;
  text-transform: none;
  letter-spacing: 0.02em;
  font-weight: 400;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8125rem;
  color: var(--ink-muted);
}
.radio--desk .radio__body {
  flex: 1;
  background: none;
  border: 0;
  padding: 0;
}
.radio--desk .radio__ask {
  font-size: clamp(1rem, 0.95rem + 0.4vw, 1.1875rem);
  line-height: 1.4;
  color: var(--ink);
  margin-bottom: 0.75rem;
}
.radio--desk .radio__ans, .radio--desk .radio__wait { line-height: 1.45; margin-bottom: 0.375rem; }
.radio--desk .radio__wait { margin-bottom: 0; }
.radio--desk .radio__ans { color: var(--ink-2); }
.radio--desk .radio__ok { color: var(--violet); }
.radio__q { color: var(--coral); font-weight: 700; flex: none; }
.radio--desk .radio__hold,
.radio--desk .radio__wait { color: var(--coral); }
.radio--desk .radio__note {
  margin-top: 0.75rem;
  padding-top: 0.625rem;
  border-top: 1px dashed rgb(var(--ink-rgb) /0.18);
  color: var(--ink-muted);
}

/* --- Inseln -----------------------------------------------------------------
   Drei Karten für die Lage heute (jeder für sich); darunter das Visier
   (nächster Block): dieselbe KI wie oben, als Anschluss an das, was
   schon läuft. */

.silos {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 0.5rem + 1.5vw, 1.5rem);
  margin-top: clamp(2.5rem, 1rem + 4vw, 4rem);
}
@media (max-width: 58rem) { .silos { grid-template-columns: 1fr; } }

.silo {
  padding: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  border-radius: var(--r-lg);
  background: var(--cream);
  border: 1px solid rgb(var(--ink-rgb) /0.08);
}
/* Die Zeile über jeder Karte ist ein Stück Funkspur, das ihr Wort zeichnet:
   zwei Inseln für „Getrennt“, eine Linie, die in Punkte zerfällt, für
   „Verloren“, eine Linie, die vor ihrer Buchse endet, für „Ohne Anschluss“.
   Inline-SVG in der Signalfarbe, Strich in currentColor; dieselbe
   Bauweise wie das Zeichen im Hero-Tag. */
.silo__tag {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  margin: 0 0 0.75rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--coral);
}
.silo__trace {
  width: 3rem; height: 0.75rem; flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}
.silo h3 { font-size: var(--fs-h3); margin-bottom: 0.625rem; text-wrap: balance; }
.silo p:last-child { margin: 0; color: var(--ink-2); font-size: 0.9375rem; }

/* --- Das Visier -----------------------------------------------------------
   Nach den Inseln der Anschluss. Erst steht nur die Zeile: groß, mittig,
   auf dem Nachtgrund in der Spalte, mit Sternen. Beim Scrollen bleibt der
   Kasten im Fenster stehen und wächst auf seine ganze Fläche; dann legt
   sich das Visier darüber — aus der Unschärfe, wie ein Helm, der sich
   schließt — und in seinem Glas erscheinen die Zusagen, eine nach der
   anderen, als Anzeigen im Visier. Alles an die Scrollposition gebunden,
   ohne Skript, wie der Kasten der vier Schreibtische. Schmale Fenster,
   Browser ohne View-Timeline und reduzierte Bewegung bekommen dasselbe
   untereinander: die Zeile, darunter das Visier mit den Karten darin.

   Die Anzeigen sind ein Instrument, kein Kartenraster: Die Armatur liegt
   auf dem Glas, nicht auf den Karten — Fadenkreuz-Ecken, Lineale mit
   Ticks an den Kanten, über dem Bild Scanlines und ein grobes Raster, alles
   statisch (Firefox und reduzierte Bewegung sehen dasselbe). Nur im Kino
   kommt das Retikel über die Erde dazu und ein Kalibrierlauf über das
   Anzeigefeld, bevor die Zusagen erscheinen. Die Karten selbst sind
   Ablese-Streifen: Meßlinie oben mit Zeigtick, Schluß unten, Nummer als
   Fähnchen an der Schiene, der Punkt als Rautik — auf einem fast soliden
   Nachtgrund (0,95 statt 0,8: über Weiß trug 0,8 die Body-Schrift mit
   4,37:1 und verfehlte die 4,5 knapp). Die ganze Armatur ist Deko ohne Schrift;
   der Kontrast steht und fällt mit dem Grund unter dem Text, der hier
   dunkler ist als vorher.

   visor.webp ist mit 72 KB das große Bild der Seite (lazy; dazu nur die
   zwei Porträts der Besatzung) und liegt neben dem Stylesheet — ui/ ist die Quelle, public/ die Kopie, wie bei dieser
   Datei. */

.visor { margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem); }
.visor__box {
  position: relative;
  isolation: isolate;
  /* clip, nicht hidden: hidden machte den Kasten zum Scroll-Container, und
     die View-Timelines der Karten (schmal) maßen sich an ihm statt am
     Fenster. Die Rundung schneidet clip genauso. */
  overflow: clip;
  border-radius: var(--r-lg);
  background:
    radial-gradient(ellipse 70% 60% at 85% 0%, rgb(var(--violet-rgb) /0.4), transparent 70%),
    var(--space);
  color: var(--on-space);
}
/* Die Zeile: mittig, so groß wie der Kasten sie trägt, das eine Wort in
   Bernstein mit dem Unterstrich aus dem Hero (.big__hi). Die Sterne sind
   die des Hero. */
.visor__head {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  text-align: center;
  padding: clamp(3.5rem, 2rem + 6vw, 8rem) var(--gut);
}
.visor__head .eyebrow { margin-bottom: 1.5rem; }
.visor__h {
  max-width: 21ch;
  font-size: clamp(2rem, 0.75rem + 4.5vw, 4.5rem);
  line-height: 1;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

/* Das Glas: das Bild als Grund, die Karten darauf. Untereinander (ohne die
   Animation) ist es der untere Teil des Kastens, das Bild so hoch wie die
   Karten. */
.visor__glass {
  position: relative;
  z-index: 1;
  padding: clamp(1.5rem, 1rem + 2vw, 3rem) clamp(1.25rem, 1rem + 2vw, 3rem);
}
.visor__view {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 40%;
}
/* Die Armatur des Instruments liegt auf dem Glas, nicht auf den Karten:
   Fadenkreuz-Ecken wie vorher auf der Karte, nur größer (28-Pixel-Schenkel,
   2 px Strich, gedimmt — in Rahmengröße muss das flüstern), Lineale mit
   1-Pixel-Ticks an vier Kanten, über dem Bild Raster und Scanlines. Alles
   statisch, damit Firefox und reduzierte Bewegung dasselbe Instrument sehen;
   nur die Kalibrierung (visor-sweep) und das Retikel sind an die Zeitlinie
   gebunden. Gemessen mit Body-Schrift über dem Bild: jede Schicht hier liegt
   unter den Karten und dem Vorspann (die sind position:relative bzw. der
   eigene Block) und kommt nie zwischen Text und Grund. */
.visor__glass::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* die vier Ecken, je zwei Schenkel */
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) top 14px left 14px / 28px 2px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) top 14px left 14px / 2px 28px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) top 14px right 14px / 28px 2px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) top 14px right 14px / 2px 28px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) bottom 14px left 14px / 28px 2px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) bottom 14px left 14px / 2px 28px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) bottom 14px right 14px / 28px 2px,
    linear-gradient(rgb(var(--mint-rgb) /0.55), rgb(var(--mint-rgb) /0.55)) bottom 14px right 14px / 2px 28px,
    /* oben und unten: Haarlinie plus Ticks darauf */
    linear-gradient(rgb(var(--mint-rgb) /0.25), rgb(var(--mint-rgb) /0.25)) top left / 100% 1px,
    linear-gradient(rgb(var(--mint-rgb) /0.25), rgb(var(--mint-rgb) /0.25)) bottom left / 100% 1px,
    repeating-linear-gradient(90deg, rgb(var(--mint-rgb) /0.3) 0 1px, transparent 1px 12px) top left / 100% 6px,
    repeating-linear-gradient(90deg, rgb(var(--mint-rgb) /0.3) 0 1px, transparent 1px 12px) bottom left / 100% 6px,
    /* links und rechts dieselben Ticks, gedreht */
    repeating-linear-gradient(0deg, rgb(var(--mint-rgb) /0.3) 0 1px, transparent 1px 12px) top left / 6px 100%,
    repeating-linear-gradient(0deg, rgb(var(--mint-rgb) /0.3) 0 1px, transparent 1px 12px) top right / 6px 100%,
    /* feine Zeilen und ein grobes Raster über dem Bild */
    repeating-linear-gradient(to bottom, rgb(var(--mint-rgb) /0.035) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(to right, rgb(var(--veil-rgb) /0.045) 0 1px, transparent 1px 5rem),
    repeating-linear-gradient(to bottom, rgb(var(--veil-rgb) /0.045) 0 1px, transparent 1px 5rem);
  background-repeat: no-repeat;
}
.visor__hud {
  counter-reset: hud;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  /* Das Glas ist gewölbt, also hat es eine Fluchtachse, und zwar eine für
     alle Anzeigen: perspective steht am Feld, nicht an der Ablesung, sonst
     kippt jede um ihre eigene Mitte und die Wölbung zerfällt in
     Einzelkippungen. Der Ursprung ist die Mitte des Felds — das Auge.
     60rem ist die flachste Wölbung, die man noch sieht: die äußeren
     Ablesungen stehen 2rem tiefer und schrumpfen dabei um 3 %, nicht um
     15 %, so dass die Schrift ihre Größe behält. */
  perspective: 60rem;
}
.visor__hud .hud--lede { grid-column: 1 / -1; }
@media (max-width: 40rem) { .visor__hud { grid-template-columns: 1fr; } }
/* Die Liste löst sich in das Raster der Anzeige auf; role="list" im Markup
   hält sie für Vorleser eine Liste. */
.hud__list { display: contents; list-style: none; margin: 0; padding: 0; }

/* Die Ableseung: ein Streifen, kein Kasten. Außen die Schiene, die die drei
   Ablesungen einer Seite zu einem Gerät verbindet, darauf oben die Meßlinie
   mit Zeigtick und die Nummer als Fähnchen, das außen an der Schiene hängt;
   innen sitzt der Rautik auf der Kante. Unten schließt nur das äußere Drittel.
   Das Fadenkreuz liegt auf dem Glas (siehe dort); die Karte trägt keine
   Ecken mehr.

   Sechs Ablesungen, die alle gleich aussehen, sind ein Kartenraster mit
   Mint-Linien. Die Seite ist darum spiegelbar: --hud-out ist die Außenkante
   (links in der linken Spalte, rechts in der rechten), und Schiene, Tick,
   Fähnchen und Schluß hängen daran. Die Schrift spiegelt nicht mit —
   rechtsbündiger Fließtext mit gezacktem Anfang liest sich messbar
   langsamer, und das ist der Preis, den diese Seite nicht zahlt. Was
   spiegelt, ist Armatur; was bleibt, ist Text.

   Kein backdrop-filter: die Karte ist selbst animiert (Unschärfe, Skalierung,
   Deckkraft an der Scrollposition) und läge auf der klebenden Bühne über dem
   ebenfalls animierten Bild — ein Element, das seinen Hintergrund jeden Frame
   neu abtastet und dabei selbst gefiltert wird, flackert beim Scrollen in
   Chrome wie in Safari. Das Glas kommt darum aus der Deckkraft des Grundes.

   Warum 0,95 und nicht die alten 0,8: hinter der Karte steht das Bild, und
   der schlimmste Fall, den ein Bild treiben kann, ist reines Weiß. Darüber
   trug 0,8 die Body-Schrift mit 4,37:1 — knapp unter der Schwelle von 4,5.
   0,95 trägt 7,18:1, die Überschrift 12,8:1. Die Zahl ist der Kontrast-Fix,
   nicht der Look.

   Gemessen wird kanalweise: Deckkraft mischt in sRGB, also erst den Grund
   über Weiß mischen, dann die Luminanz des Ergebnisses nehmen. Wer die
   Luminanzen mischt statt der Kanäle, bekommt für dieselben 0,8 eine 2,1
   heraus und tauscht einen knappen Fehlschlag gegen einen dramatischen ein.
   Der Weg ist in scripts/ nicht abgelegt, weil er drei Zeilen hat; diese
   hier sind sie. */
.hud {
  /* die Außenkante und was daran hängt; die geraden Nummern spiegeln das */
  --hud-out: left; /* @kind other */
  --hud-tab-l: -1px; /* @kind other */
  --hud-tab-r: auto; /* @kind other */
  --hud-dot-l: auto; /* @kind other */
  --hud-dot-r: -4px; /* @kind other */
  /* die Lage in der Wölbung: Drehung zur Mitte, Kippung zur Augenhöhe,
     Tiefe. Alles 0, solange nur eine Spalte steht (siehe unten). */
  --hud-ry: 0deg; /* @kind other */
  --hud-rx: 0deg; /* @kind other */
  --hud-tz: 0px; /* @kind other */
  --hud-ty: 0px; /* @kind other */
  --hud-line: rgb(var(--mint-rgb) /0.85);
  position: relative;
  margin: 0;
  width: var(--hud-w, 100%);
  padding: 1rem 1.375rem 1.125rem;
  border-radius: 2px;
  background:
    /* Meßlinie oben, Zeigtick am äußeren Ende */
    linear-gradient(var(--hud-line), var(--hud-line)) top left / 100% 1px,
    linear-gradient(var(--hud-line), var(--hud-line)) top var(--hud-out) / 2px 9px,
    /* die Schiene: außen, über die ganze Höhe, oben satt und nach unten
       auslaufend — so liest die Spalte als ein Gerät mit drei Abgriffen */
    linear-gradient(rgb(var(--mint-rgb) /0.5), rgb(var(--mint-rgb) /0.08)) top var(--hud-out) / 1px 100%,
    /* der Schluß unten schließt nur außen an, nicht über die ganze Breite */
    linear-gradient(rgb(var(--mint-rgb) /0.3), rgb(var(--mint-rgb) /0.3)) bottom var(--hud-out) / 30% 1px,
    /* die Scanlines der Ableseung — dieselbe Textur wie das Glas */
    repeating-linear-gradient(to bottom, rgb(var(--mint-rgb) /0.05) 0 1px, transparent 1px 4px),
    rgb(var(--space-rgb) /0.95);
  background-repeat: no-repeat;
  box-shadow: 0 10px 28px rgb(var(--ink-rgb) /0.4);
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--on-space-muted);
  transform:
    translateY(var(--hud-ty))
    translateZ(var(--hud-tz))
    rotateY(var(--hud-ry))
    rotateX(var(--hud-rx));
}
/* Die Nummer hängt als Fähnchen außen an der Schiene, halb über der Kante,
   nicht mehr als erste Zeile im Text. Sie steht damit teils über dem Bild
   und bekommt darum ihren eigenen Nachtgrund — dieselben 0,95 wie die
   Ableseung, gemessen: Mint darauf trägt 8,1:1 über Weiß. */
.hud__list .hud::before {
  counter-increment: hud;
  content: "[" counter(hud, decimal-leading-zero) "]";
  position: absolute;
  top: -0.7rem;
  left: var(--hud-tab-l);
  right: var(--hud-tab-r);
  padding: 0.25rem 0.4rem;
  background: rgb(var(--space-rgb) /0.95);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  line-height: 1;
  color: var(--mint);
}
/* Der Rautik sitzt auf der Innenkante, halb außerhalb: das Ende der
   Meßlinie, das ins Feld zeigt. Leuchten nur hier, nie unter Schrift; der
   Ring kommt aus Schichten, die mit der Raute kippen. */
.hud__list .hud::after {
  content: "";
  position: absolute;
  top: -4px;
  left: var(--hud-dot-l);
  right: var(--hud-dot-r);
  width: 7px;
  height: 7px;
  border-radius: 1px;
  rotate: 45deg;
  background: var(--mint);
  box-shadow:
    0 0 0 3px rgb(var(--space-rgb) /0.9),
    0 0 0 4px rgb(var(--mint-rgb) /0.55),
    0 0 6px rgb(var(--mint-rgb) /0.7);
}
/* Die Anordnung. Sobald zwei Spalten stehen, ist das Feld eine Wölbung um
   das Auge: die linke Spalte dreht ihre Außenkante zum Betrachter, die
   rechte spiegelverkehrt. Die Zahl der Ablesungen ist frei — gerade und
   ungerade Position entscheiden über die Seite, die ersten zwei und die
   letzten zwei kippen zur Augenhöhe und stehen 2rem tiefer im Raum, welche
   Zahl es auch sind. Die Breiten sind ungleich (90–100 %), damit die
   Ablesungen als Instrument lesen und nicht als Raster; alles jenseits der
   vierten steht auf der vollen Spur (--hud-w fällt auf 100 % zurück).
   Neun Grad ist die Grenze: darüber wird die Schrift der äußeren Kante
   sichtbar weich, weil 3D-Text ohne Subpixel-Glättung gerastert wird.
   Untereinander (eine Spalte) bleibt alles flach und linksbündig — dort
   gibt es kein Außen. */
@media (width > 40rem) {
  .hud__list .hud:nth-child(odd) {
    --hud-ry: 9deg; /* @kind other */
    --hud-ty: -0.75rem; /* @kind other */
    justify-self: start;
  }
  .hud__list .hud:nth-child(even) {
    --hud-out: right; /* @kind other */
    --hud-tab-l: auto; /* @kind other */
    --hud-tab-r: -1px; /* @kind other */
    --hud-dot-l: -4px; /* @kind other */
    --hud-dot-r: auto; /* @kind other */
    --hud-ry: -9deg; /* @kind other */
    --hud-ty: 0.75rem; /* @kind other */
    justify-self: end;
  }
  /* obere Reihe kippt mit der Oberkante zum Auge, untere mit der Unterkante;
     die mittleren Reihen bleiben auf Höhe, welche Zahl es auch sind */
  .hud__list .hud:nth-child(-n+2)      { --hud-rx: 4deg;  --hud-tz: -2rem; }
  .hud__list .hud:nth-last-child(-n+2) { --hud-rx: -4deg; --hud-tz: -2rem; }
  .hud__list .hud:nth-child(1) { --hud-w: 94%; }
  .hud__list .hud:nth-child(2) { --hud-w: 100%; }
  .hud__list .hud:nth-child(3) { --hud-w: 90%; }
  .hud__list .hud:nth-child(4) { --hud-w: 100%; }
}
/* Die Überschrift trägt die Karte; der Satz darunter ist kurz. */
.hud b {
  display: block;
  margin-bottom: 0.4rem;
  font-size: 1.3em;
  line-height: 1.2;
  letter-spacing: -0.015em;
  color: var(--on-space);
  font-weight: 700;
}
/* Der Vorspann: kein Glas, keine Nummer, kein Punkt — nur der Satz, groß
   und mittig, mit einem Dunst darunter statt einem Kasten: der Radial geht
   bis 70 % satt und läuft erst danach aus, so dass jede Ecke des Satzes
   (schlimmster Fall die letzte Zeile außen) noch auf >= 0,88 Deckkraft
   steht: 10,2:1 über Weiß, verlangt sind 3:1 ab 24px. Vorher war es nur ein
   Schatten, und ein Schatten hat keinen Grund, den man messen kann — über
   dem beleuchteten Rand des Bildes (95. Perzentil 0,67) blieb die große
   Schrift damit unter 3:1.

   Er steht auch als einziger gerade: keine Drehung, keine Tiefe. Er sitzt
   auf der Achse des Auges, ist der erste Satz, den man liest, und bleibt
   darum das schärfste Stück im Feld — die Wölbung ist etwas, das um ihn
   herum passiert. Nummer und Rautik hat er nicht; beide hängen an
   .hud__list und der Vorspann steht nicht darin. */
.hud--lede {
  max-width: 30ch;
  margin-inline: auto;
  padding: 0.5rem 0;
  background: none;
  box-shadow: none;
  font-size: clamp(1.375rem, 1rem + 1.2vw, 1.875rem);
  line-height: 1.2;
  letter-spacing: -0.02em;
  text-align: center;
  text-wrap: balance;
  text-shadow: 0 2px 24px rgb(var(--space-rgb) /0.85);
  color: var(--on-space);
}

/* Die Animation. Der Kasten misst 350 Fensterhöhen, seine Bühne klebt
   oben und ist eine davon: zweieinhalb Fensterhöhen Scrollweg, die die
   View-Timeline --visor als „contain 0–100 %“ zählt. Darauf, in dieser
   Reihenfolge: der Kasten wächst von der Spalte aufs Fenster (0–20 %),
   die Zeile kommt näher und verschwimmt (0–52 %), das Visier legt sich
   aus der Unschärfe darüber (20–52 %), der Vorspann erscheint (56–70 %),
   die Zusagen alle zugleich (80–96 %) — und sobald sie stehen, gibt
   die Bühne den Scroll frei. Die Bühne endet bündig mit dem Abschnitt danach. Der Kasten beginnt in der Spalte:
   --visor-in ist der Abstand der Spalte zum Fensterrand. Unter 58rem
   (wo sonst die Kartenraster brechen) blendet stattdessen jede Karte ein,
   sobald sie ins Fenster kommt. Neu die Kalibrierung: zwischen Vorspann und
   Zusagen (70–80 %) fährt einmal ein Mint-Streifen über das Anzeigefeld. */
@supports (animation-timeline: view()) {
  @keyframes hud-in {
    from { opacity: 0; translate: 0 1.25rem; scale: 0.96; filter: blur(8px); }
    to   { opacity: 1; translate: 0 0;       scale: 1;    filter: blur(0); }
  }
  @media (prefers-reduced-motion: no-preference) {
    @media (width <= 58rem) {
      .hud { animation: hud-in ease-out both; animation-timeline: view(); animation-range: entry 0% entry 60%; }
    }
    @media (width > 58rem) {
      .visor {
        --visor-in: max(var(--gut), calc((100vw - var(--wrap)) / 2 + var(--gut)));
        --visor-gap: calc(var(--bar-h) + 1.25rem);
        height: 350vh;
        margin-inline: calc(50% - 50vw);
        margin-bottom: calc(-1 * var(--sec-y));
        /* --night-2 ist derselbe Weg für die Kopfleiste (siehe dort). */
        view-timeline-name: --visor, --night-2;
      }
      /* clip, nicht hidden: hidden machte den Abschnitt zum Scroll-Container
         und die Bühne klebte an ihm statt am Fenster (siehe Hero). */
      .sec:has(.visor) { overflow-x: clip; }
      /* will-change: Bild und Zeile liegen wegen ihrer Animationen auf
         eigenen Ebenen; klebt die Bühne selbst nicht auf einer, wird ihr
         Versatz bei Bruchteil-Scrollpositionen anders gerundet als der der
         Ebenen, und das Bild zittert um ein Pixel. Die Bühne ragt oben und
         unten je ein Pixel über das Fenster hinaus: Safari rundet die
         klebende Bühne auf ganze Pixel, scrollt die Seite aber in
         Bruchteilen — bündig mit dem Fenster blitzte darum an der Unterkante
         eine Zeile der Seite dahinter auf. */
      .visor__stage { position: sticky; top: -1px; height: calc(100vh + 2px); will-change: transform; }
      .visor__box {
        position: absolute;
        inset: var(--visor-gap) var(--visor-in);
        animation: visor-open ease-in-out both;
        animation-timeline: --visor;
        animation-range: contain 0% contain 20%;
      }
      @keyframes visor-open {
        from { inset: var(--visor-gap) var(--visor-in); border-radius: var(--r-lg); }
        to   { inset: 0;                                border-radius: 0; }
      }
      .visor__head {
        position: absolute;
        inset: 0;
        align-content: center;
        animation: visor-head ease-in both;
        animation-timeline: --visor;
        animation-range: contain 0% contain 52%;
      }
      @keyframes visor-head {
        0%   { opacity: 1; scale: 1;    filter: blur(0); }
        45%  { opacity: 1; scale: 1.05; filter: blur(0); }
        100% { opacity: 0; scale: 1.14; filter: blur(14px); }
      }
      .visor__glass { position: absolute; inset: 0; padding: 0; }
      .visor__view {
        animation: visor-helm ease-out both;
        animation-timeline: --visor;
        animation-range: contain 20% contain 52%;
      }
      @keyframes visor-helm {
        from { opacity: 0; scale: 1.12; filter: blur(28px); }
        to   { opacity: 1; scale: 1;    filter: blur(0); }
      }
      /* Die Armatur des Glases legt sich mit dem Helm — dieselben
         Keyframes, dieselbe Strecke, keine eigenen. */
      .visor__glass::before {
        animation: visor-helm ease-out both;
        animation-timeline: --visor;
        animation-range: contain 20% contain 52%;
      }
      /* Das Retikel steht nur im Kino: unten mittig, über der Erde (die
         dunkelste Zone des Bilds, gemessen Median 0,05). Untereinander ist
         der Zuschnitt ein anderer — dort würde die Marke über nichts stehen
         und las sich als Fehler, nicht als Stil. */
      .visor__glass::after {
        content: "";
        position: absolute;
        left: 50%;
        top: 66%;
        width: 9rem;
        height: 9rem;
        translate: -50% -50%;
        border: 1px solid rgb(var(--mint-rgb) /0.5);
        border-radius: 50%;
        background:
          linear-gradient(rgb(var(--mint-rgb) /0.5), rgb(var(--mint-rgb) /0.5)) 50% 0 / 1px 12px,
          linear-gradient(rgb(var(--mint-rgb) /0.5), rgb(var(--mint-rgb) /0.5)) 50% 100% / 1px 12px,
          linear-gradient(rgb(var(--mint-rgb) /0.5), rgb(var(--mint-rgb) /0.5)) 0 50% / 12px 1px,
          linear-gradient(rgb(var(--mint-rgb) /0.5), rgb(var(--mint-rgb) /0.5)) 100% 50% / 12px 1px;
        background-repeat: no-repeat;
        animation: visor-helm ease-out both;
        animation-timeline: --visor;
        animation-range: contain 20% contain 52%;
      }
      /* Im Glas: links und rechts je eine Spalte Ablesungen, in der Mitte
         oben der Vorspann als bloße Schrift, die Mitte darunter bleibt frei
         für die Erde und ihr Retikel. Das Raster steht mittig zwischen
         Leiste und Armaturen (die unteren 12 % des Bildes); die Schrift
         wächst mit der Fensterhöhe, damit so viele Reihen, wie die Copy
         bringt, in jedes Fenster passen. */
      .visor__hud {
        position: absolute;
        inset: calc(var(--bar-h) + 2vh) 6% 12%;
        grid-template-columns: minmax(0, 3fr) minmax(0, 4fr) minmax(0, 3fr);
        gap: 1.25rem;
        align-content: center;
        align-items: start;
      }
      .visor__hud .hud--lede { grid-column: 2; grid-row: 1; font-size: clamp(1.125rem, 0.5rem + 2.4vh, 2rem); }
      .hud__list .hud:nth-child(odd)  { grid-column: 1; }
      .hud__list .hud:nth-child(even) { grid-column: 3; }
      /* Im Kino ist mehr Platz, also greift die Staffelung weiter: die
         Spalten stehen um 1,25rem gegeneinander versetzt, so dass links und
         rechts nie eine Zeile bilden. Und die mittlere Ablesung jeder Seite
         greift in den Rand hinein — das Glas ist auf Augenhöhe am breitesten,
         oben und unten zieht es sich zusammen. Der Einzug von 6 % trägt die
         4 %, ohne dass etwas aus dem Bild läuft. */
      .hud__list .hud:nth-child(odd)  { --hud-ty: -1.25rem; }
      .hud__list .hud:nth-child(even) { --hud-ty:  1.25rem; }
      .hud__list .hud:nth-child(3) { margin-left: -4%; }
      .hud__list .hud:nth-child(4) { margin-right: -4%; }
      /* Der Kalibrierlauf: ein Mint-Streifen fährt einmal von oben nach
         unten über das Anzeigefeld, bevor die Zusagen erscheinen (56–70 %
         Vorspann, 70–80 % Lauf, 80–96 % Zusagen — die feste Choreographie
         bleibt). Er liegt auf .visor__hud und läuft, bevor die Karten da
         sind, kreuzt also keine Schrift. Ohne Zeitlinie hat er kein content
         und steht nie — das Instrument wird ohne ihn nicht halb. */
      .visor__hud::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 16%;
        background: linear-gradient(to bottom,
          transparent,
          rgb(var(--mint-rgb) /0.05) 40%,
          rgb(var(--mint-rgb) /0.11) 55%,
          transparent);
        animation: visor-sweep linear both;
        animation-timeline: --visor;
        animation-range: contain 70% contain 80%;
      }
      @keyframes visor-sweep {
        from { opacity: 0; translate: 0 -16%; }
        12%  { opacity: 1; }
        88%  { opacity: 1; }
        to   { opacity: 0; translate: 0 460%; }
      }
      .hud {
        font-size: clamp(0.75rem, 0.35rem + 0.9vh, 0.9375rem);
        animation: hud-in ease-out both;
        animation-timeline: --visor;
      }
      .visor__hud .hud--lede { animation-range: contain 56% contain 70%; }
      .hud__list .hud        { animation-range: contain 80% contain 96%; }
    }
  }
}

/* --- Vertrauen ------------------------------------------------------------
   Vier Karten (Kontrolle, Daten, Verstehen, Rückweg), der Werte-Block in
   voller Breite auf Weiß, die Nie-Liste klein, dann der Abschluss. Keine
   Linien zwischen den Blöcken — der Abstand trennt, die drei Balken der
   Liste und der fette Schlusssatz tragen die Gliederung. */

.eyebrow__blip {
  display: inline-block;
  width: 0.5rem; height: 0.5rem;
  margin-right: 0.5rem;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 3px rgb(var(--violet-rgb) /0.2);
  vertical-align: 0.05em;
}

.trust {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.25rem, 0.5rem + 2vw, 1.75rem);
  margin-top: clamp(2.5rem, 1rem + 4vw, 4rem);
}
@media (max-width: 58rem) { .trust { grid-template-columns: 1fr; } }

.trust__card {
  background: var(--white);
  border-radius: var(--r-lg);
  padding: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) /0.06), 0 10px 30px rgb(var(--ink-rgb) /0.05);
}
.trust__label {
  display: inline-block;
  margin: 0 0 0.875rem;
  padding: 0.3125rem 0.75rem;
  border-radius: var(--r-pill);
  background: var(--violet);
  color: var(--on-accent, #fff);
  font-size: 0.8125rem;
  font-weight: 800;
  letter-spacing: 0.02em;
}
.trust__q {
  margin: 0 0 0.75rem;
  font-size: clamp(1.125rem, 1rem + 0.7vw, 1.4375rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--ink);
  text-wrap: balance;
}
.trust__card p:last-child { margin: 0; color: var(--ink-2); font-size: 0.9375rem; }

.creed { margin-top: clamp(3rem, 1.5rem + 5vw, 5.5rem); }
.creed__q {
  margin-bottom: 0.875rem;
  font-size: clamp(1.375rem, 1rem + 1.25vw, 1.875rem);
  max-width: 24ch;
}
.creed__lede { margin: 0; color: var(--ink-2); max-width: 56ch; text-wrap: balance; }
.creed__list {
  list-style: none;
  counter-reset: creed;
  margin: clamp(1.25rem, 1rem + 1vw, 2rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.25rem, 0.5rem + 2vw, 2rem);
}
@media (max-width: 58rem) { .creed__list { grid-template-columns: 1fr; } }
.creed__list li {
  counter-increment: creed;
  padding-top: 1rem;
  border-top: 2px solid var(--violet);
  font-size: 0.9375rem;
  color: var(--ink-2);
}
.creed__list li::before {
  content: counter(creed, decimal-leading-zero);
  display: block;
  margin-bottom: 0.5rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--violet);
}
.creed__list b {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--ink);
  font-weight: 800;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.trust__end { margin-top: clamp(3rem, 1.5rem + 5vw, 5.5rem); }
.trust__act { margin-top: 1.5rem; }

/* ==========================================================================
   Abschnitte
   ========================================================================== */

.sec { padding-block: var(--sec-y); }
.sec--cream { background: var(--cream); }
.sec--dark {
  background:
    radial-gradient(ellipse 70% 60% at 85% 10%, rgb(var(--violet-rgb) /0.4), transparent 70%),
    var(--space);
  color: var(--on-space);
}

/* --- Die drei Ängste ----------------------------------------------------- */

.fears {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.25rem, 0.5rem + 2vw, 2rem);
  margin-top: clamp(2.5rem, 1rem + 4vw, 4rem);
}
@media (max-width: 58rem) { .fears { grid-template-columns: 1fr; } }

.fear {
  background: var(--white);
  border-radius: var(--r-lg);
  padding: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) /0.06), 0 10px 30px rgb(var(--ink-rgb) /0.05);
}
.fear:nth-child(1) { transform: rotate(-0.5deg); }
.fear:nth-child(3) { transform: rotate(0.5deg); }
@media (max-width: 58rem) { .fear { transform: none !important; } }

.fear__says {
  font-size: clamp(1.125rem, 1rem + 0.7vw, 1.4375rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.25;
  color: var(--ink-muted);
  margin-bottom: 1.125rem;
}
.fear__label {
  display: inline-block;
  margin-bottom: 0.875rem;
  padding: 0.3125rem 0.75rem;
  border-radius: var(--r-pill);
  background: var(--mint);
  color: var(--on-mint, #06341f);
  font-size: 0.8125rem;
  font-weight: 800;
  letter-spacing: 0.02em;
}
.fear p:last-child { font-size: 0.9375rem; color: var(--ink-muted); line-height: 1.65; }

/* --- Zahlen -------------------------------------------------------------- */

.nums {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.5rem, 0.5rem + 2.5vw, 2.5rem);
  margin-top: clamp(2.5rem, 1rem + 4vw, 4rem);
}
@media (max-width: 62rem) { .nums { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 30rem) { .nums { grid-template-columns: 1fr; } }

.num__v {
  margin: 0 0 0.5rem;
  font-size: clamp(3rem, 1.5rem + 5vw, 5rem);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.05em;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
}
.num__p { color: var(--coral); }
.num__c { margin: 0; font-size: 0.875rem; line-height: 1.45; color: var(--on-space-muted); max-width: 24ch; }

/* --- Die Reise ----------------------------------------------------------- */

/* Die vier Etappen auf einer Zeitleiste statt in vier Karten. Die Leiste
   ist eine 2-px-Linie am Fuß des Blocks, die von Fensterrand zu Fensterrand
   läuft; die vier Etappen stehen darauf in der Spalte der Seite (--trip-in
   ist der Abstand der Spalte zum Fensterrand, wie --visor-in). Alles
   passiert über der Linie, unten bündig: Nummer, Überschrift, Absatz, dann
   — als Markierung des Abschnitts — die Dauer in Signalfarbe, und darunter
   der Punkt auf der Linie, an dem die Etappe beginnt. Das ist die
   Reihenfolge im Markup, nichts wird umsortiert. Nach der letzten Etappe
   läuft die Linie aus dem Bild — die Betreuung hat kein Ende.

   Ab 64rem liegt die Leiste links und die Etappen stehen untereinander.
   In der Vier-Spalten-Ansicht hängt alles an der View-Timeline --trip der
   Liste: erst der Vorlauf am linken Rand, dann je Etappe die Linie bis zur
   nächsten, der Punkt, und aus der Unschärfe von links kommend die
   Schrift — vier Mal nacheinander, gestaffelt über --t. In der Spalte
   hat jede Etappe ihre eigene Timeline (--stage) und kommt an, wenn sie
   unten ins Fenster tritt. Ohne View-Timelines oder mit reduzierter
   Bewegung steht die Leiste fertig gezeichnet da. */
.trip {
  --trip-in: max(var(--gut), calc((100vw - var(--wrap)) / 2 + var(--gut)));
  --tick: 0.875rem;                      /* der Punkt */
  --rail-b: calc(var(--tick) / 2 - 1px); /* die Linie, gemessen vom Fuß: Mitte des Punkts */
  --rail: rgb(var(--violet-rgb) /0.9);
  position: relative;
  list-style: none;
  margin: clamp(2.5rem, 1rem + 4vw, 4rem) calc(50% - 50vw) 0;
  padding: 0 var(--trip-in);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.5rem, 0.5rem + 2vw, 2.5rem);
}
/* clip, nicht hidden — siehe „Das Visier“. */
.sec:has(.trip) { overflow-x: clip; }

/* Der Vorlauf: die Linie vom linken Fensterrand bis zum ersten Punkt. */
.trip::before {
  content: "";
  position: absolute;
  left: 0;
  width: var(--trip-in);
  bottom: var(--rail-b);
  height: 2px;
  background: var(--rail);
  transform-origin: left;
}

.trip__i {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-width: 0;
}
/* .trip__i .trip__n, weil „.trip__i p“ unten sonst gewinnt — gleiches bei
   der Dauer. */
.trip__i .trip__n {
  margin: 0 0 0.75rem;
  font-size: 1rem;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: 0.02em;
  color: var(--violet);
  font-variant-numeric: tabular-nums;
}
/* Der Punkt auf der Linie, als Letztes in der Spalte: Signalfarbe mit
   einem Ring in der Grundfarbe, damit die Linie sauber unter ihm
   durchläuft. */
.trip__i::before {
  content: "";
  order: 1;
  width: var(--tick);
  height: var(--tick);
  margin-top: 1rem;
  border-radius: 50%;
  background: var(--coral);
  box-shadow: 0 0 0 3px var(--cream);
  position: relative;
  z-index: 1;
}
/* Der Abschnitt der Linie: von diesem Punkt bis zum nächsten (über die
   Lücke hinweg); beim letzten bis zum rechten Fensterrand, dort auslaufend. */
.trip__i::after {
  content: "";
  position: absolute;
  left: 0;
  right: calc(-1 * clamp(1.5rem, 0.5rem + 2vw, 2.5rem));
  bottom: var(--rail-b);
  height: 2px;
  background: var(--rail);
  transform-origin: left;
}
.trip__i:last-child::after {
  right: calc(-1 * var(--trip-in));
  mask-image: linear-gradient(to right, #000 55%, transparent);
}
.trip__i h3 { font-size: var(--fs-h3); margin-bottom: 0.625rem; }
.trip__i p { font-size: 0.9375rem; color: var(--ink-muted); line-height: 1.6; }
.trip__i .trip__m {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--coral);
}

/* Die Spalte: Leiste links, Punkt am Zeilenanfang, alles andere rechts
   davon in derselben Reihenfolge, oben bündig. */
@media (width <= 64rem) {
  .trip {
    --rail-x: calc(var(--trip-in) + var(--tick) / 2);
    grid-template-columns: 1fr;
    gap: clamp(2rem, 1rem + 3vw, 3rem);
    padding-right: var(--gut);
  }
  .trip::before {
    left: calc(var(--rail-x) - 1px);
    top: calc(-1 * clamp(2.5rem, 1rem + 4vw, 4rem));
    width: 2px;
    height: clamp(2.5rem, 1rem + 4vw, 4rem);
    transform-origin: top;
  }
  .trip__i { padding-left: calc(var(--tick) + 1.25rem); max-width: 40rem; justify-content: flex-start; }
  .trip__i::before {
    position: absolute;
    left: 0;
    top: 0.25rem;
    margin: 0;
  }
  .trip__i::after {
    left: calc(var(--tick) / 2 - 1px);
    right: auto;
    top: 0.25rem;
    width: 2px;
    height: calc(100% + clamp(2rem, 1rem + 3vw, 3rem));
    transform-origin: top;
    mask-image: none;
  }
  .trip__i:last-child::after {
    height: calc(100% + var(--sec-y));
    mask-image: linear-gradient(to bottom, #000 40%, transparent);
  }
  .trip__i .trip__n { margin-bottom: 0.25rem; }
}

/* Die Animation. Vier Spalten: Vorlauf, dann je Etappe Linie (10vh),
   Punkt (5vh, um den Moment, in dem die Linie ihn erreicht) und Schrift
   (14vh, kurz danach) — alles auf --trip, gestaffelt über --t, fertig nach
   58vh Scrollweg, wenn die Liste im unteren Fensterdrittel steht. In der
   Spalte dasselbe je Etappe auf ihrer eigenen Timeline. */
@supports (animation-timeline: view()) {
  @keyframes trip-draw-x { from { scale: 0 1; } to { scale: 1 1; } }
  @keyframes trip-draw-y { from { scale: 1 0; } to { scale: 1 1; } }
  @keyframes trip-tick   { from { scale: 0; opacity: 0; } to { scale: 1; opacity: 1; } }
  @keyframes trip-in {
    from { opacity: 0; translate: -2rem 0; filter: blur(8px); }
    to   { opacity: 1; translate: 0 0;     filter: blur(0); }
  }
  @media (prefers-reduced-motion: no-preference) {
    @media (width > 64rem) {
      .trip { view-timeline-name: --trip; }
      .trip::before {
        animation: trip-draw-x linear both;
        animation-timeline: --trip;
        animation-range: cover 0 cover 6vh;
      }
      .trip__i:nth-child(1) { --t: 6vh; }
      .trip__i:nth-child(2) { --t: 18vh; }
      .trip__i:nth-child(3) { --t: 30vh; }
      .trip__i:nth-child(4) { --t: 42vh; }
      .trip__i::after {
        animation: trip-draw-x linear both;
        animation-timeline: --trip;
        animation-range: cover var(--t) cover calc(var(--t) + 10vh);
      }
      .trip__i::before {
        animation: trip-tick ease-out both;
        animation-timeline: --trip;
        animation-range: cover calc(var(--t) - 1vh) cover calc(var(--t) + 4vh);
      }
      .trip__i > * {
        animation: trip-in ease-out both;
        animation-timeline: --trip;
        animation-range: cover calc(var(--t) + 2vh) cover calc(var(--t) + 16vh);
      }
    }
    @media (width <= 64rem) {
      .trip::before {
        animation: trip-draw-y linear both;
        animation-timeline: view();
        animation-range: cover 0 cover 12vh;
      }
      .trip__i { view-timeline-name: --stage; }
      .trip__i::after {
        animation: trip-draw-y linear both;
        animation-timeline: --stage;
        animation-range: cover 0 cover 30vh;
      }
      .trip__i::before {
        animation: trip-tick ease-out both;
        animation-timeline: --stage;
        animation-range: cover 0 cover 6vh;
      }
      .trip__i > * {
        animation: trip-in ease-out both;
        animation-timeline: --stage;
        animation-range: cover 2vh cover 20vh;
      }
    }
  }
}

/* --- Besatzung -----------------------------------------------------------
   Die zwei Gründer als das Kassiopeia-Zeichen aus dem Logo, in die Breite
   gezogen: fünf Sterne, vier Haarlinien dazwischen. Die beiden oberen
   Sterne sind die Porträts, jeweils mit dem Text daneben; die drei unteren
   sind die Grundlinie — drei Punkte, an jedem ein Können.

   Die Geometrie kommt aus dem Raster, nicht aus einem Skript: vier Spalten
   14/26/20/40 legen die Sterne auf 0, 14, 40, 60 und 100 % (das Zeichen
   selbst steht bei 0, 25, 43, 71, 100 — die rechte Hälfte ist gestreckt,
   damit Davids Text Platz hat). Die Linien sind zwei SVGs im Band zwischen
   den Zeilen, ohne viewBox — die <line>-Enden stehen in Prozent der
   Fläche (35 % ist 14/40, 33,3 % ist 20/60), so bleibt der Strich eine
   Haarlinie statt einer gestreckten. Die SVGs ragen oben und unten genau
   so weit über das Band, dass die Linienenden auf den Sternmitten liegen —
   Porträtradius, Hub, halbe Zeile. Die Zeilen darüber und darunter dürfen
   so hoch werden, wie der Text will; das Band kennt nur Abstände in rem. */

.crew {
  --pic: clamp(5.5rem, 4.5rem + 2.5vw, 8rem); /* Durchmesser der Porträts */
  --lift: 1.5rem;                             /* Davids Stern steht höher, wie im Zeichen (4 zu 6) */
  --dot: 0.625rem;                            /* die drei Punkte der Grundlinie */
  --lh1: 1.25rem;                             /* Zeilenhöhe des Kennworts; der Punkt sitzt auf seiner Mitte */
  --sky: clamp(6rem, 3rem + 7vw, 11rem); /* @kind spacing */ /* das Band, in dem die Linien laufen */
  display: grid;
  grid-template-columns: 14fr 26fr 20fr 40fr;
  grid-template-rows: auto var(--sky) auto;
  margin-top: clamp(3rem, 1.5rem + 4vw, 5rem);
}

/* Die oberen Sterne: Porträt links, Text rechts, unten bündig — die Linien
   verlassen den Stern nach unten, also darf unter seiner Mitte kein Text
   stehen. Der negative Rand schiebt das Porträt so, dass seine Mitte auf
   der Spaltenlinie liegt. */
.mate {
  position: relative;
  z-index: 1;
  grid-row: 1;
  align-self: end;
  display: flex;
  align-items: flex-end;
  gap: 1.375rem;
  margin: 0 0 0 calc(var(--pic) / -2);
}
.mate--1 { grid-column: 2 / 4; padding-right: calc(var(--pic) / 2 + 1.5rem); }
.mate--2 { grid-column: 4 / 5; margin-bottom: var(--lift); }
/* Das Porträt: rund, quadratisch beschnitten (malte.webp, david.webp, je
   480 px, ~11 KB, lazy). Ein Ring in der Sektionsfarbe hebt es vom Grau
   des Fotos ab und deckt den Linienanfang. */
.mate__pic {
  flex: none;
  display: block;
  width: var(--pic);
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
  box-shadow: 0 0 0 3px var(--cream), 0 0 0 4px rgb(var(--ink-rgb) / 0.12);
}
.mate__txt { min-width: 0; padding-bottom: 0.25rem; }
/* Die Rollenzeile über dem Namen ist weg (15.09.2026): die Rolle steht schon
   im Absatz darunter, und die drei Sterne der Grundlinie sagen sie ein
   zweites Mal. Der Name fängt die Karte jetzt selbst an. */
.mate__name { font-size: clamp(1.5rem, 1rem + 1.4vw, 2rem); margin-bottom: 0.75rem; }
.mate__txt p { font-size: 0.9375rem; color: var(--ink-muted); line-height: 1.6; }
.mate__txt p:last-child { margin-bottom: 0; }

/* Das Band. Zwei SVGs, links 0–40 % (Punkt, Malte, Punkt), rechts 40–100 %
   (Punkt, David, Punkt); der mittlere Punkt gehört beiden. Oben ragen sie
   bis zur Porträtmitte, unten bis zur Mitte der ersten Zeile. */
.crew__sky { grid-row: 2; grid-column: 1 / -1; position: relative; }
.crew__ray {
  position: absolute;
  display: block;
  overflow: visible;
}
.crew__ray--1 { left: 0;   width: 40%; top: calc(var(--pic) / -2);               height: calc(var(--sky) + var(--pic) / 2 + var(--lh1) / 2); }
.crew__ray--2 { left: 40%; width: 60%; top: calc(var(--pic) / -2 - var(--lift)); height: calc(var(--sky) + var(--pic) / 2 + var(--lift) + var(--lh1) / 2); }
.crew__ray line { stroke: rgb(var(--ink-rgb) / 0.38); stroke-width: 1; }

/* Die Grundlinie: drei Punkte auf einer Höhe, an jedem ein Kennwort und ein
   Satz. Links und in der Mitte steht der Text rechts vom Punkt, rechts
   außen links davon, damit der Punkt auf 100 % liegen kann. */
.crew__base {
  position: relative;
  z-index: 1;
  grid-row: 3;
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  margin: 0;
  padding: 0;
  list-style: none;
}
.skill { display: flex; align-items: flex-start; gap: 0.875rem; margin: 0; }
.skill--1 { grid-column: 1 / 3; margin-left: calc(var(--dot) / -2); padding-right: 3rem; }
.skill--2 { grid-column: 3 / 4; margin-left: calc(var(--dot) / -2); padding-right: 1.5rem; }
.skill--3 { grid-column: 4 / 5; flex-direction: row-reverse; text-align: right; margin-right: calc(var(--dot) / -2); padding-left: 1.5rem; }
.skill__dot {
  flex: none;
  width: var(--dot);
  height: var(--dot);
  margin-top: calc((var(--lh1) - var(--dot)) / 2);
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 3px var(--cream);
}
.skill__k {
  margin: 0 0 0.25rem;
  font-size: 0.8125rem;
  line-height: var(--lh1);
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
}
.skill p { margin: 0; font-size: 0.9375rem; color: var(--ink-muted); line-height: 1.55; }

/* Schmal: das Zeichen fällt weg, die fünf Sterne werden eine Liste — erst
   die zwei Gründer, dann die drei Punkte hinter einer Haarlinie. */
@media (max-width: 64rem) {
  .crew { display: block; }
  .crew__sky { display: none; }
  .mate { align-items: flex-start; margin: 0 0 2rem; padding: 0; }
  .mate__txt { padding-bottom: 0; }
  .crew__base {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.25rem;
    margin-top: 2.5rem;
    padding-top: 2rem;
    border-top: 1px solid rgb(var(--ink-rgb) / 0.14);
  }
  .skill--1, .skill--2, .skill--3 { grid-column: auto; flex-direction: row; text-align: left; margin: 0; padding: 0; }
}
@media (max-width: 30rem) {
  .crew { --pic: 4.5rem; }
}

/* --- Absage ---------------------------------------------------------------
   Fünf Zeilen, kein Absatz. Der Abschnitt wirkt nur, solange er nichts
   zurücknimmt — deshalb hier auch kein freundlicher Schlusssatz. Und er
   soll wie eine Notiz aussehen, nicht wie ein Feature: keine Karten, kein
   Signal in Koralle (die gehört dem Funkspruch-Knopf), nur Zeilen mit
   einer Haarlinie dazwischen. */

.nope {
  margin: clamp(2rem, 1rem + 3vw, 3.25rem) 0 0;
  padding: 0;
  list-style: none;
}
.nope li {
  padding: 1rem 0;
  border-top: 1px solid rgb(var(--ink-rgb) / 0.14);
  font-size: 1.0625rem;
  line-height: 1.5;
  color: var(--ink-2);
}
.nope li:last-child {
  border-bottom: 1px solid rgb(var(--ink-rgb) / 0.14);
}

/* --- Fragen -------------------------------------------------------------- */

.qs { margin-top: clamp(2.25rem, 1rem + 3vw, 3.5rem); }

.qq {
  background: var(--white);
  border-radius: var(--r);
  margin-bottom: 0.75rem;
  padding: 0 clamp(1rem, 0.75rem + 1vw, 1.5rem);
}
.qq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-block: 1.125rem;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.35;
  transition: color 0.2s ease;
}
.qq summary::-webkit-details-marker { display: none; }
/* The badge: two bars painted as gradients so the + can shrink into a –
   while the disc turns half a turn and warms up. */
.qq summary::after {
  content: "";
  margin-left: auto;
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background-color: var(--violet);
  background-image:
    linear-gradient(var(--on-accent, #fff), var(--on-accent, #fff)),
    linear-gradient(var(--on-accent, #fff), var(--on-accent, #fff));
  background-repeat: no-repeat;
  background-position: center;
  background-size: 0.75rem 2px, 2px 0.75rem;
  transition:
    background-color 0.3s ease,
    background-size 0.3s ease,
    transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.qq[open] summary::after {
  background-color: var(--coral);
  background-size: 0.75rem 2px, 2px 0;
  transform: rotate(180deg);
}
.qq summary:hover { color: var(--violet); }
/* The answer slides open: the content box is a grid whose single row
   grows from 0fr to 1fr. Browsers without ::details-content just toggle. */
.qq::details-content {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition:
    grid-template-rows 0.35s cubic-bezier(0.2, 0.8, 0.2, 1),
    content-visibility 0.35s allow-discrete;
}
.qq[open]::details-content { grid-template-rows: 1fr; }
.qq p {
  min-height: 0;
  margin: 0;
  padding: 0 3rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--ink-muted);
  opacity: 0;
  translate: 0 -0.25rem;
  transition: opacity 0.3s ease, translate 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* The gap under the answer is a block inside the paragraph, not padding:
   min-height: 0 only covers the content box, so padding would hold the
   0fr row open by 1.375rem until the transition ends and the row snaps. */
.qq p::after { content: ""; display: block; height: 1.375rem; }
.qq[open] p { opacity: 1; translate: 0 0; }
/* Der rechte Rand der Antwort hält sie auf breiten Fenstern kürzer als die
   Frage; auf dem Handy nähme er ein Fünftel der Spalte. */
@media (max-width: 40rem) { .qq p { padding-right: 0; } }
@media (prefers-reduced-motion: reduce) {
  .qq summary::after,
  .qq::details-content,
  .qq p { transition: none; }
  .qq[open] summary::after { transform: none; }
}

/* ==========================================================================
   Funkspruch
   ========================================================================== */

.call {
  position: relative;
  /* clip, nicht hidden: hidden machte den Abschnitt zum Scroll-Container,
     und die View-Timelines seiner Überschrift und seines Absatzes (siehe
     rise-in bei den wiederkehrenden Teilen) mäßen dann an ihm statt am
     Fenster — sie stünden immer am Ende. */
  overflow: clip;
  background:
    radial-gradient(ellipse 70% 70% at 20% 0%, rgb(var(--coral-rgb) /0.35), transparent 65%),
    radial-gradient(ellipse 60% 60% at 90% 100%, rgb(var(--violet-rgb) /0.45), transparent 65%),
    var(--space);
  color: var(--on-space);
  padding-block: clamp(4rem, 2rem + 8vw, 8.5rem);
}
.call__h {
  font-size: clamp(1.875rem, 1rem + 3.2vw, 3.75rem);
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1.06;
  text-wrap: balance;
}
.call__p {
  margin: 1.75rem 0 0;
  max-width: 54ch;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--on-space-muted);
}
/* Der Aufruf steht als Überschrift über den Knöpfen, nicht mehr auf einem
   von ihnen. Klein gehalten: die große Zeile darüber trägt den Abschnitt,
   das hier sagt nur noch, was die Knöpfe darunter tun. */
.call__cta {
  margin: clamp(2.25rem, 1rem + 3vw, 3.25rem) 0 0;
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--on-space);
}
.call__act {
  display: flex;
  align-items: center;
  /* Enger als vorher: aus zwei Elementen sind fünf geworden, und mit dem
     alten Abstand von bis zu 2,25rem bricht die Zeile bei 1440 px um. */
  gap: 0.75rem 0.875rem;
  flex-wrap: wrap;
  margin: 1.125rem 0 0;
}
/* Die Adresse noch einmal ausgeschrieben, für alle, deren mailto: ins Leere
   läuft. */
.call__mail { font-weight: 700; color: var(--on-space); }

/* ==========================================================================
   Fuß
   ========================================================================== */

/* Der letzte Streifen Nachtgrund: die Ground Control meldet sich ab, der
   Kanal bleibt offen. Ein paar Sterne aus dem Hero (siehe .stars, hier
   kleiner), das Logo mit der Funkmarke des Heros (siehe .tag — der Ring
   pulst weiter) und der eine Satz; daneben die Abschnitte (dieselben acht
   wie in der Kopfleiste, die sie unter 75rem versteckt) und der Kontakt.
   Darunter, unter einer Haarlinie, Firma, Sprache und der Weg nach
   oben. Drei Spalten ab 64rem, zwei ab 40rem,
   darunter eine. */
.foot {
  position: relative;
  overflow: clip;
  background:
    radial-gradient(ellipse 55% 90% at 100% 100%, rgb(var(--violet-rgb) / 0.28), transparent 70%),
    var(--space-2);
  color: var(--on-space-muted);
  padding-block: clamp(3rem, 2rem + 3vw, 4.5rem) 2rem;
}
.foot .stars span { width: 2px; height: 2px; }
.foot__in, .foot__end { position: relative; z-index: 1; }
.foot__in { display: grid; gap: 2.5rem var(--gut); align-items: start; }
@media (min-width: 40rem) {
  .foot__in { grid-template-columns: 1fr 1fr; }
  .foot__id { grid-column: 1 / -1; }
}
@media (min-width: 64rem) {
  .foot__in { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr); }
  .foot__id { grid-column: auto; }
}

/* Das Logo (siehe „Logo“) in voller Helligkeit, die Funkmarke darunter
   eine Stufe kleiner als im Hero, der Satz gedämpft. */
.foot__brand { display: flex; width: max-content; color: var(--on-space); }
.foot__tag { margin: 1.5rem 0 0; font-size: 0.75rem; color: var(--on-space); }
.foot__note { margin: 1rem 0 0; font-size: 0.9375rem; line-height: 1.55; max-width: 30ch; }

.foot__k {
  margin: 0 0 0.875rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mint);
}
.foot__list { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.5rem 2rem; }
/* Die acht Abschnitte in zwei Spalten zu vier, spaltenweise gelesen. */
.foot__list--2 { grid-auto-flow: column; grid-template-rows: repeat(4, auto); grid-template-columns: repeat(2, max-content); }
.foot__list a {
  color: var(--on-space);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.foot__list a:hover { color: var(--amber); border-bottom-color: rgb(var(--veil-rgb) / 0.35); }
.foot__dim { font-weight: 400; color: var(--on-space-muted); }

.foot__end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.625rem 1.75rem;
  margin-top: clamp(2.5rem, 1.5rem + 3vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid rgb(var(--veil-rgb) / 0.12);
  font-size: 0.8125rem;
}
.foot__end > * { margin: 0; }
/* In einer Spalte steht die Firma allein in der ersten Zeile, Sprache und
   Weg nach oben zusammen in der zweiten. */
@media (max-width: 39.99rem) { .foot__legal { flex-basis: 100%; } .foot__langs { margin-left: 0; } }
.foot__legal { font-weight: 600; color: var(--on-space); }
.foot__langs { display: inline-flex; gap: 0.5rem; margin-left: auto; }
.foot__langs b { font-weight: 600; color: var(--on-space); }
.foot__end a { color: var(--on-space); text-decoration: none; border-bottom: 1px solid rgb(var(--veil-rgb) / 0.28); }
.foot__end a:hover { color: var(--amber); }
/* Der Pfeil hebt sich beim Überfahren ein Stück, wie die Knöpfe. */
.foot__up { display: inline-flex; gap: 0.375rem; align-items: baseline; font-weight: 700; }
.foot__up span { display: inline-block; transition: translate 0.2s ease; }
.foot__up:hover span { translate: 0 -2px; }
@media (prefers-reduced-motion: reduce) {
  .foot__list a, .foot__up span { transition: none; }
}

/* ==========================================================================
   Versteckt, aber erreichbar
   ========================================================================== */

/* Die Radioknöpfe der vier Schreibtische: display:none nähme ihnen die
   Tastatur, darum aus dem Bild geschoben statt entfernt. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   Ground Control — interne Seiten unter /ground-control/
   ========================================================================== */

/* Gebaut aus dem Vault (web/ground-control/, Format: die Notiz
   projects/ground-control/seitenformat.md), von ui/components/gc/. Die
   Regeln kommen von der Abstimmungsseite vom 05.10.2026, die sie bis dahin
   inline trug; aus ab- wurde gc-. Neu gegenüber ihr: Reiter für beliebige
   Fassungen (ohne Regeln je Seite), Marken für alle fünf Belegstärken. */

body > .bar.gc-bar { animation: none; }
body > .bar.gc-bar::before, body > .bar.gc-bar .bar__in { --night-t: 1; transition: none; }
/* Auf der Übersicht hat die Leiste keinen eigenen Grund: sie liegt auf dem
   Creme der Seite, in dunkler Schrift, und scrollt mit (ohne Grund würde
   sie klebend über den Karten schweben). */
body > .bar.gc-bar.gc-bar--plain { position: relative; }
/* Die Übersicht hat keinen Fuß; unter den Karten bleibt bis zum Rand Creme. */
body.gc-home { background: var(--cream); }
/* Auf dem Telefon hat die Leiste der Übersicht Platz (sie trägt keinen
   Knopf): Wort und „Vertraulich · intern“ bleiben stehen, statt dass nur
   das Zeichen einsam oben links steht. Darunter weniger Luft. */
@media (max-width: 40rem) {
  body > .bar.gc-bar.gc-bar--plain .hush { display: block; }
  body > .bar.gc-bar.gc-bar--plain .logo__word { display: inline; }
  .gc-home .gc-mag { padding-top: 0.5rem; }
}
/* Auf einer Seite liegt die Leiste ohne Grund auf dem Hero und scrollt mit
   ihm weg; der Hero hält ihr oben Platz frei. */
body > .bar.gc-bar.gc-bar--over { position: absolute; inset: 0 0 auto; }
body > .bar.gc-bar.gc-bar--over::before { background: none; backdrop-filter: none; }
.gc-bar--over ~ main .gc-hero { padding-top: calc(var(--bar-h) + clamp(2rem, 1rem + 3vw, 4rem)); }
body > .bar.gc-bar.gc-bar--plain::before { background: var(--cream); backdrop-filter: none; }
body > .bar.gc-bar.gc-bar--plain .bar__in { --night-t: 0; --bar-fg: var(--ink); --bar-fg-muted: var(--ink-muted); --bar-accent: var(--violet); }
.hush {
  margin: 0 0 0 auto;
  font-size: 0.8125rem;
  color: var(--bar-fg-muted);
  white-space: nowrap;
}
@media (max-width: 40rem) {
  .bar .hush { display: none; }
  .bar.gc-bar .btn { margin-left: auto; }
}

.gc-h1 {
  font-size: clamp(2.25rem, 1rem + 4vw, 4.25rem);
  color: var(--on-space);
  text-wrap: balance;
}
/* Die Zeile unter der Überschrift: die Leser mit Porträt, darunter Thema,
   Stand und Lesezeit. Ein Hinweis ist Text mit Punkt, keine Marke. */
.gc-byline { margin-top: 1.5rem; display: flex; align-items: center; gap: 0.875rem; }
.gc-byline .gc-avatar { width: 2.5rem; height: 2.5rem; font-size: 0.9375rem; box-shadow: 0 0 0 2px var(--space); }
.gc-byline .gc-avatar + .gc-avatar { margin-left: -0.625rem; }
.gc-byline p { margin: 0; }
.gc-byline__who { font-size: 0.9375rem; font-weight: 600; color: var(--on-space); }
/* Der Punkt zwischen zwei Angaben steht in der Lücke links von jeder; wer
   eine Zeile beginnt, dessen Punkt fällt links aus dem Kasten und wird
   abgeschnitten. Der Hinweis trägt seinen roten Punkt statt des Trenners. */
.gc-byline__meta { display: flex; flex-wrap: wrap; gap: 0 1rem; overflow: hidden; font-size: 0.875rem; color: var(--on-space-muted); }
.gc-byline__meta > span { position: relative; }
.gc-byline__meta > span::before { content: "·"; position: absolute; left: -0.625rem; }
.gc-byline__meta > .gc-byline__note::before { content: ""; position: static; display: inline-block; width: 0.4375rem; height: 0.4375rem; margin: 0 0.4375rem 0.0625rem 0; border-radius: 50%; background: var(--coral); }
.gc-act { display: flex; flex-wrap: wrap; gap: 0.875rem; margin-top: 2.25rem; }
.gc-small { font-size: 0.875rem; color: var(--ink-muted); }
.sec--dark .gc-small { color: var(--on-space-muted); }
.gc-body { max-width: 66ch; margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem); }
.gc-body p, .gc-body li { color: var(--ink-2); line-height: 1.65; }
.gc-body ul, .gc-body ol { padding-left: 1.25rem; display: grid; gap: 0.5rem; }
/* Ein Verweis in den Vault (GcVault): eine Pille mit dem Tresor-Zeichen,
   dem Wort „Vault“ und dem Pfad. Die Ordner leise, die Notiz fett. Passt
   der Pfad nicht neben das Wort, bekommt er eine eigene Zeile über die
   ganze Breite der Pille und bricht an jedem Zeichen. */
.gc-vault {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.5rem;
  width: fit-content; max-width: 100%;
  margin: 1.5rem 0 0; padding: 0.5rem 0.875rem 0.5rem 0.75rem;
  border-radius: var(--r-sm);
  background: linear-gradient(135deg, var(--gold-hi), var(--gold-lo));
  box-shadow: inset 0 0 0 1px var(--gold-line), inset 0 1px 0 1px rgb(255 255 255 / 0.6), 0 1px 2px rgb(127 91 14 / 0.12);
  font-size: 0.8125rem; line-height: 1.4; color: var(--gold);
}
/* Zeichen und Wort bleiben zusammen und stehen mittig zueinander. */
.gc-vault__head { flex: none; display: inline-flex; align-items: center; gap: 0.375rem; }
.gc-vault__icon {
  flex: none; width: 1rem; height: 1rem;
  fill: none; stroke: var(--gold); stroke-width: 1.4; stroke-linecap: round;
}
.gc-vault__lead { font-weight: 700; color: var(--gold-ink); }
/* Die Basis ist die volle Länge des Pfads: passt sie nicht neben das Wort,
   rückt der Pfad in die nächste Zeile, füllt sie (grow) und bricht dort an
   jedem Zeichen (min-width 0, break-all). */
.gc-vault__path { flex: 1 1 auto; min-width: 0; font-size: 0.8125rem; color: var(--gold); word-break: break-all; }
.gc-vault__path b { font-weight: 700; color: var(--gold-ink); }
.gc-vault__sep { margin: 0 0.125em; opacity: 0.55; }
/* Auf Nachtgrund leuchtet das Gold selbst: Bernstein auf einem Hauch Gold. */
.sec--dark .gc-vault {
  background: linear-gradient(135deg, rgb(255 201 92 / 0.16), rgb(255 201 92 / 0.06));
  box-shadow: inset 0 0 0 1px rgb(255 201 92 / 0.45);
  color: var(--amber);
}
.sec--dark .gc-vault__icon { stroke: var(--amber); }
.sec--dark .gc-vault__lead, .sec--dark .gc-vault__path b { color: var(--gold-hi); }
.sec--dark .gc-vault__path { color: var(--amber); }

.gc-hero {
  padding-block: clamp(3rem, 1.5rem + 5vw, 6rem) var(--sec-y);
}
.gc-hero__in {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 1rem + 4vw, 5rem);
  align-items: start;
}
@media (max-width: 62rem) { .gc-hero__in { grid-template-columns: 1fr; } }

/* Die Lesehilfe: was zuerst, wie lange. */
.gc-steps { list-style: none; margin: 1.75rem 0 0; padding: 0; display: grid; gap: 0.5rem; counter-reset: s; }
.gc-steps li {
  counter-increment: s;
  display: grid; grid-template-columns: 1.75rem minmax(0, 1fr); gap: 0.5rem;
  color: var(--on-space); line-height: 1.5;
}
.gc-steps li::before { content: counter(s) "."; font-weight: 800; color: var(--amber); }
.gc-steps a { color: var(--on-space); }

/* Die Fakten mit Belegstärke: eine Fläche, keine Kästen darin. Jede Zeile
   ist durch eine Linie abgesetzt; Marke, Satz und Quelle stehen in festem
   Abstand (0.75rem, dann 0.5rem), Zeilen 1.25rem auseinander. */
.gc-log {
  margin: 0;
  border-radius: var(--r-lg);
  background: rgb(var(--veil-rgb) / 0.06);
  box-shadow: inset 0 0 0 1px rgb(var(--veil-rgb) / 0.14);
  padding: clamp(1.25rem, 0.75rem + 1.5vw, 2rem);
}
.gc-log__head {
  margin: 0 0 0.25rem;
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--on-space-muted);
}
.gc-facts { list-style: none; margin: 0; padding: 0; }
/* Die Marke steht in einer Zeile für sich, der Text darunter über die
   ganze Breite. */
.gc-fact {
  display: grid;
  gap: 0.5rem;
  padding: 1.25rem 0;
  border-top: 1px solid rgb(var(--veil-rgb) / 0.1);
}
.gc-fact:first-child { border-top: 0; }
.gc-fact:last-child { padding-bottom: 0; }
.gc-fact .gc-grade:not(.gc-grade--inline) { margin-bottom: 0.25rem; }
.gc-fact__t { margin: 0; font-weight: 600; color: var(--on-space); line-height: 1.45; text-wrap: pretty; }
.gc-fact__t a { color: inherit; }
.gc-fact__s { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--on-space-muted); }
/* Die Belegstärke (GcGrade): jede Stufe sieht anders aus. Fünf Balken wie
   eine Signalanzeige, so viele hell wie die Stufe, sagen die Stärke ohne
   Farbe; die Farbe sagt, was die Regel des Vaults daraus macht: Minze ein
   Fakt (5 voll, 4 tief), Bernstein und Koralle eine Annahme (3, 2), eine
   gestrichelte Linie das Offene (1). Alles in em, damit dieselbe Marke als
   Block und mitten im Satz passt. */
.gc-grade {
  display: inline-flex; align-items: center; gap: 0.5em;
  justify-self: start;
  padding: 0.3em 0.8em 0.3em 0.65em;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: 0.75rem; font-weight: 800; line-height: 1.2; letter-spacing: 0.02em;
  white-space: nowrap;
}
.gc-grade__bars { display: inline-flex; align-items: flex-end; gap: 0.15em; height: 0.95em; }
.gc-grade__bars i { width: 0.24em; border-radius: 1px; background: currentColor; opacity: 0.28; }
.gc-grade__bars i:nth-child(1) { height: 28%; }
.gc-grade__bars i:nth-child(2) { height: 46%; }
.gc-grade__bars i:nth-child(3) { height: 64%; }
.gc-grade__bars i:nth-child(4) { height: 82%; }
.gc-grade__bars i:nth-child(5) { height: 100%; }
.gc-grade--5 i, .gc-grade--4 i:nth-child(-n + 4), .gc-grade--3 i:nth-child(-n + 3),
.gc-grade--2 i:nth-child(-n + 2), .gc-grade--1 i:nth-child(1) { opacity: 1; }
.gc-grade--5 { background: var(--mint); color: var(--on-mint); }
.gc-grade--4 { background: var(--violet); color: var(--on-accent); border-color: rgb(var(--mint-rgb) / 0.55); }
.gc-grade--3 { background: var(--amber); color: var(--on-amber); }
.gc-grade--2 { background: var(--coral); color: var(--on-accent); }
.gc-grade--1 { background: transparent; color: inherit; border: 1px dashed currentColor; }
/* Im Satz: so groß wie der Text drumherum, ohne die Zeile zu weiten. */
.gc-grade--inline {
  font-size: 0.8em; line-height: 1; vertical-align: 0.05em;
  margin: 0 0.1em; padding: 0.15em 0.6em 0.15em 0.5em;
}

/* Auf einen Blick: bis zu vier Spalten. */
.gc-glance {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: clamp(1rem, 0.5rem + 1.5vw, 1.5rem);
  margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem);
}
.gc-col {
  padding: 1.25rem 1.5rem;
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: 0 1px 0 rgb(0 0 0 / 0.04);
}
.gc-col h3 { margin: 0 0 0.75rem; font-size: 1.0625rem; }
.gc-col ul { margin: 0; padding-left: 1.125rem; display: grid; gap: 0.5rem; }
.gc-col li { color: var(--ink-2); line-height: 1.5; font-size: 0.9375rem; }
.gc-col a { color: var(--ink); }
.gc-tag {
  display: inline-block; margin-bottom: 0.625rem;
  padding: 0.125rem 0.625rem; border-radius: var(--r-pill);
  font-size: 0.75rem; font-weight: 800;
}
.gc-tag--same { background: var(--cream); color: var(--ink); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12); }
.gc-tag--done { background: var(--mint); color: var(--on-mint); }
.gc-tag--prop { background: var(--amber); color: var(--ink); }
.gc-tag--open { background: var(--ink-muted); color: var(--white); }

/* Begriffe: die Karten von .fears, drei nebeneinander. */
.fears.gc-three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 58rem) { .fears.gc-three { grid-template-columns: 1fr; } }
.fear .gc-vault { margin-top: 0.75rem; }

/* Fassungen eines Textes als Reiter, ohne Skript. Jede Fassung trägt ihre
   eigene Reiterleiste mit ihrem eigenen Reiter markiert; sichtbar ist die
   Fassung, auf die der Teil der Adresse nach dem # zeigt, ohne ihn die erste.
   So braucht keine Seite eigene Regeln, und ein Link zeigt genau auf eine. */
.gc-tabs { margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem); max-width: 40rem; }
.gc-variant { scroll-margin-top: calc(var(--bar-h, 4.5rem) + 1.5rem); }
.gc-tabs:not(:has(.gc-variant:target)) .gc-variant ~ .gc-variant,
.gc-tabs:has(.gc-variant:target) .gc-variant:not(:target) { display: none; }
.gc-tabs__bar { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0; padding: 0; list-style: none; }
.gc-tabs__bar a {
  display: block; padding: 0.5rem 1rem; border-radius: 999px;
  font-size: 0.875rem; font-weight: 700; text-decoration: none;
  background: var(--white); color: var(--ink);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12);
}
.gc-tabs__bar a:focus-visible { outline: 2px solid var(--coral); outline-offset: 2px; }
.gc-tabs__bar a[aria-current] { background: var(--ink); color: var(--white); box-shadow: none; }
@media (max-width: 26rem) { .gc-tabs__bar a { padding: 0.5rem 0.75rem; font-size: 0.8125rem; } }
.gc-msg {
  max-width: 40rem;
  margin-top: 1rem;
  padding: clamp(1.25rem, 0.75rem + 1.5vw, 2rem);
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) 6px;
  background: var(--white);
  box-shadow: 0 1px 0 rgb(0 0 0 / 0.04), 0 18px 40px rgb(0 0 0 / 0.08);
}
.gc-msg p { margin: 0 0 0.875rem; line-height: 1.6; }
.gc-msg p:last-child { margin-bottom: 0; }
.gc-msg__head {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-muted);
}

/* Schritte, je mit Marke. */
.gc-flow { list-style: none; margin: clamp(1.5rem, 1rem + 2vw, 2.5rem) 0 0; padding: 0; display: grid; gap: 0.75rem; max-width: 52rem; counter-reset: f; }
.gc-flow li {
  counter-increment: f;
  display: grid; grid-template-columns: 2.5rem minmax(0, 1fr); gap: 0.25rem 1rem;
  padding: 1rem 1.25rem; border-radius: var(--r-sm); background: var(--white);
}
.gc-flow li::before { content: counter(f); grid-row: span 2; font-size: 1.5rem; font-weight: 800; color: var(--coral); }
.gc-flow h3 { margin: 0; font-size: 1rem; }
.gc-flow p { margin: 0; font-size: 0.9375rem; line-height: 1.55; color: var(--ink-2); }
.gc-flow .gc-tag { margin: 0 0 0 0.5rem; vertical-align: 0.1em; }

/* Gegenüberstellung: bisher, Vorschlag. */
.gc-diff { margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem); display: grid; gap: 0.75rem; max-width: 60rem; }
.gc-diff__row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.25rem 1.5rem;
  padding: 1rem 1.25rem; border-radius: var(--r-sm); background: var(--white);
}
@media (max-width: 46rem) { .gc-diff__row { grid-template-columns: 1fr; } }
.gc-diff__row h3 { grid-column: 1 / -1; margin: 0 0 0.25rem; font-size: 1rem; }
.gc-diff__row p { margin: 0; font-size: 0.9375rem; line-height: 1.55; color: var(--ink-2); }
.gc-diff__row b { display: block; font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-muted); }

/* Zahlen mit Herkunft. */
.gc-nums {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: clamp(1rem, 0.5rem + 1.5vw, 1.5rem);
  margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem);
}
.gc-num {
  padding: 1.25rem 1.5rem;
  border-radius: var(--r-lg);
  background: var(--cream);
}
.gc-num__v { display: block; font-size: var(--fs-h2); font-weight: 800; letter-spacing: -0.02em; color: var(--ink); }
.gc-num__l { margin: 0.25rem 0 0; font-weight: 600; color: var(--ink-2); }
.gc-num__s { margin: 0.5rem 0 0; font-size: 0.8125rem; color: var(--ink-muted); }

/* Entscheidungen und Aufgaben. Die Nummer steht im Text, nicht als Zähler:
   Sie ist fest und muss nicht bei 1 anfangen. */
.gc-qs__h { margin: clamp(2rem, 1rem + 2vw, 3rem) 0 0; font-size: 1.125rem; color: var(--on-space); }
.gc-qs { list-style: none; padding: 0; margin: 1rem 0 0; display: grid; gap: 0.75rem; max-width: 52rem; }
.gc-qs li {
  display: grid; grid-template-columns: 2.25rem minmax(0, 1fr); gap: 0.25rem 0.75rem;
  padding: 0.875rem 1rem;
  border-radius: var(--r-sm);
  background: rgb(var(--veil-rgb) / 0.06);
  color: var(--on-space);
  line-height: 1.5;
}
.gc-qs__n { grid-row: span 2; font-weight: 800; color: var(--amber); }
.gc-qs__q { margin: 0; font-weight: 600; }
.gc-qs__p { margin: 0; font-size: 0.875rem; color: var(--on-space-muted); }
.gc-qs__p a { color: var(--on-space); }

/* Die Übersicht /ground-control/, als Titelseite eines Magazins: eine
   Kopfzeile statt Hero, dann die Seiten über die ganze Breite — die neueste
   als Aufmacher, die übrigen zu zweit —, rechts die Spalte mit den letzten
   Deployments. Unter 62rem steht die Spalte unter den Seiten. */
.gc-mag { background: var(--cream); padding-block: clamp(1.5rem, 1rem + 2vw, 2.5rem) clamp(3rem, 2rem + 4vw, 5rem); }
.gc-mast {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 2rem;
  padding-bottom: 0.875rem; margin-bottom: clamp(1.25rem, 1rem + 1vw, 2rem);
  border-bottom: 2px solid var(--ink);
}
.gc-mast__h { margin: 0; font-size: clamp(1.75rem, 1.25rem + 1.5vw, 2.5rem); letter-spacing: -0.03em; line-height: 1; }
/* Die Zahl der Seiten in der Schrift des Titels, kleiner und heller. */
.gc-mast__count { margin-left: 0.35em; font-size: 0.6em; color: var(--ink-muted); white-space: nowrap; }
.gc-mast__meta { margin: 0; font-size: 0.9375rem; color: var(--ink-2); }

/* Ein übersprungener Lauf: über den Seiten, korallenrot gerandet. */
.gc-run {
  margin-bottom: clamp(1.25rem, 1rem + 1vw, 2rem);
  padding: 1rem 1.25rem; border-radius: var(--r-sm);
  background: var(--white); box-shadow: inset 4px 0 0 var(--coral);
  color: var(--ink-2); font-size: 0.9375rem;
}
.gc-run p { margin: 0; }
.gc-run__head { font-weight: 800; color: var(--ink); margin-bottom: 0.25rem !important; }
.gc-run ul { margin: 0.5rem 0 0; padding-left: 1.25rem; }

.gc-mag__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem); gap: clamp(1.25rem, 1rem + 1.5vw, 2.5rem); align-items: start; }
@media (max-width: 62rem) { .gc-mag__grid { grid-template-columns: minmax(0, 1fr); } }
.gc-mag__main { display: grid; gap: clamp(0.75rem, 0.5rem + 0.75vw, 1.25rem); }

/* Eine Seite als Meldung. Der Link der Überschrift deckt die ganze Karte. */
.gc-stories { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(0.75rem, 0.5rem + 0.75vw, 1.25rem); }
@media (max-width: 46rem) { .gc-stories { grid-template-columns: minmax(0, 1fr); } }
.gc-story {
  --pad: clamp(1.125rem, 1rem + 0.5vw, 1.5rem);
  position: relative; display: flex; flex-direction: column; gap: 0.75rem;
  padding: var(--pad); border-radius: var(--r-sm);
  background: var(--white); box-shadow: 0 1px 2px rgb(var(--ink-rgb) / 0.06);
  transition: box-shadow 0.14s ease, transform 0.14s ease;
}
.gc-story:hover { transform: translateY(-2px); box-shadow: 0 1px 2px rgb(var(--ink-rgb) / 0.06), 0 12px 28px rgb(var(--ink-rgb) / 0.1); }
.gc-story:has(a:focus-visible) { outline: 3px solid var(--violet); outline-offset: 2px; }
.gc-story--lead { grid-column: 1 / -1; --pad: clamp(1.5rem, 1rem + 2vw, 2.5rem); background: var(--space); color: var(--on-space); }
/* Oben in jeder Karte, auf einer Zeile: links der Bereich als Badge, rechts
   „neu“ und das Datum. Die übrigen Themen stehen ganz über der Überschrift
   und dürfen umbrechen; gekürzt wird nichts. */
.gc-story__top, .gc-deploy__top { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; min-width: 0; }
.gc-story__kicker { margin: 0; display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.gc-story__kicker .gc-chip { flex: none; }
.gc-story__head { display: grid; gap: 0.25rem; }
.gc-story__topic { margin: 0; font-size: 0.875rem; font-weight: 600; line-height: 1.35; color: var(--violet); }
.gc-story--lead .gc-story__topic { color: var(--amber); }
.gc-story__when { flex: none; margin: 0; display: flex; align-items: center; gap: 0.5rem; font-size: 0.8125rem; color: var(--ink-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.gc-story__when .gc-tag { margin: 0; }
.gc-story--lead .gc-story__when { color: var(--on-space-muted); }

/* Die Badges der Übersicht. Gefüllt: der Bereich einer Seite, eine je
   Karte; grau umrandet: zurückgezogen. Die Arten einer Auslieferung haben
   je eine Farbe, die sonst nichts bedeutet. */
.gc-chip {
  display: inline-flex; align-items: center;
  padding: 0.1875rem 0.625rem; border-radius: var(--r-pill);
  font-size: 0.75rem; font-weight: 600; line-height: 1.3;
  color: var(--ink-2); box-shadow: inset 0 0 0 1px rgb(var(--ink-rgb) / 0.16);
}
.gc-chip--area { background: var(--ink); color: var(--white); box-shadow: none; }
.gc-story--lead .gc-chip { color: var(--on-space); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.25); }
.gc-story--lead .gc-chip--area { background: var(--amber); color: var(--ink); box-shadow: none; }
.gc-chip--texts { background: rgb(var(--mint-rgb) / 0.35); color: var(--on-mint); box-shadow: none; }
.gc-chip--code { background: rgb(var(--ink-rgb) / 0.08); color: var(--ink); box-shadow: none; }
.gc-chip--hand { background: rgb(var(--coral-rgb) / 0.12); color: var(--coral); box-shadow: none; }
.gc-chip--back { background: var(--coral); color: var(--on-accent); box-shadow: none; }
.gc-story__h { margin: 0; font-size: var(--fs-h3); line-height: 1.2; letter-spacing: -0.01em; text-wrap: balance; }
.gc-story--lead .gc-story__h { font-size: clamp(1.75rem, 1rem + 2.5vw, 3rem); line-height: 1.05; letter-spacing: -0.03em; max-width: 24ch; }
.gc-story__h a { color: inherit; text-decoration: none; outline: none; }
.gc-story__h a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.gc-story:hover .gc-story__h { color: var(--violet); }
.gc-story--lead:hover .gc-story__h { color: var(--amber); }
/* Der Anreißer ist Lesetext: groß genug, ruhig gesetzt, vier Zeilen. Der
   Aufmacher zeigt sein Intro ganz. */
.gc-story__teaser {
  margin: 0; max-width: 62ch; font-size: 1.0625rem; line-height: 1.6; color: var(--ink-2); text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4; overflow: hidden;
}
.gc-story--lead .gc-story__teaser { display: block; font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem); color: var(--on-space-muted); }
/* Der Fuß der Karte, durch eine Linie abgesetzt: links die Leser mit
   Porträt, rechts ein Hinweis, wenn die Quelle sich seither geändert hat. */
/* Die Linie geht über die ganze Breite der Karte: der Fuß greift über ihren
   Innenabstand (--pad) hinaus und holt ihn innen zurück. */
.gc-story__foot {
  margin: auto calc(-1 * var(--pad)) 0; padding: 0.875rem var(--pad) 0; border-top: 1px solid rgb(var(--ink-rgb) / 0.08);
  display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: center; justify-content: space-between;
  font-size: 0.875rem; color: var(--ink-2);
}
.gc-story--lead .gc-story__foot { border-top-color: rgb(255 255 255 / 0.12); color: var(--on-space-muted); }
.gc-people { display: inline-flex; align-items: center; gap: 0.625rem; min-width: 0; }
.gc-avatars { display: inline-flex; flex: none; }
.gc-avatar {
  display: inline-grid; place-items: center; flex: none;
  width: 1.75rem; height: 1.75rem; border-radius: 50%; object-fit: cover;
  background: var(--cream); box-shadow: 0 0 0 2px var(--white);
  font-size: 0.75rem; font-weight: 700; color: var(--ink-2);
}
.gc-avatar + .gc-avatar { margin-left: -0.5rem; }
.gc-story--lead .gc-avatar { box-shadow: 0 0 0 2px var(--space); }
.gc-story__note { display: inline-flex; align-items: center; gap: 0.4375rem; font-size: 0.8125rem; color: var(--ink-muted); }
.gc-story__note::before { content: ""; width: 0.4375rem; height: 0.4375rem; border-radius: 50%; background: var(--coral); }
.gc-story--lead .gc-story__note { color: var(--on-space-muted); }
.gc-story__meta .gc-tag { margin: 0; }

/* "Was ist neu": die Seite neuigkeiten, über allen anderen. */
.gc-news { padding: clamp(1.125rem, 1rem + 0.5vw, 1.5rem); border-radius: var(--r-sm); background: var(--white); box-shadow: inset 4px 0 0 var(--amber); display: grid; gap: 0.625rem; }
.gc-news .gc-story__h a { color: var(--ink); }
.gc-news .gc-story__h a:hover { color: var(--violet); }
.gc-news__intro { margin: 0; max-width: 62ch; font-size: 1.0625rem; line-height: 1.6; color: var(--ink-2); }

/* Die Spalte: kompakte Zeilen, drei Deployments offen, der Rest gefaltet. */
.gc-mag__side { display: grid; gap: 1rem; }
/* Jede Linie im Kasten — unter der Überschrift, zwischen den Zeilen, über
   der Falte — geht über seine ganze Breite, wie im Fuß der Karten: sie
   greift über den Innenabstand (--pad) hinaus und holt ihn innen zurück. */
.gc-box { --pad: 1.125rem; padding: 1rem var(--pad) 0.25rem; border-radius: var(--r-sm); background: var(--white); }
.gc-box__h {
  margin: 0 calc(-1 * var(--pad)); padding: 0 var(--pad) 1rem; border-bottom: 1px solid rgb(var(--ink-rgb) / 0.08);
  font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; color: var(--ink);
}
.gc-deploys { list-style: none; margin: 0; padding: 0; }
.gc-deploy { display: grid; gap: 0.375rem; margin-inline: calc(-1 * var(--pad)); padding: 1.125rem var(--pad); border-top: 1px solid rgb(var(--ink-rgb) / 0.08); font-size: 0.9375rem; }
.gc-deploys > .gc-deploy:first-child { border-top: 0; }
.gc-more .gc-deploys > .gc-deploy:first-child { border-top: 1px solid rgb(var(--ink-rgb) / 0.08); }
.gc-more .gc-deploy { margin-inline: 0; }
.gc-deploy__t { font-weight: 600; line-height: 1.35; color: var(--ink); text-decoration: none; overflow-wrap: anywhere; }
/* Die ganze Zeile ist der Link, nicht nur die Überschrift: auf dem Telefon
   ein großes Ziel statt einer Textzeile. */
.gc-deploy { position: relative; transition: background-color 0.14s ease; }
.gc-deploy__t { outline: none; }
.gc-deploy__t::after { content: ""; position: absolute; inset: 0; }
.gc-deploy:hover { background: rgb(var(--ink-rgb) / 0.03); }
.gc-deploy:hover .gc-deploy__t { color: var(--violet); text-decoration: underline; }
.gc-deploy:has(.gc-deploy__t:focus-visible) { outline: 2px solid var(--violet); outline-offset: -2px; }
.gc-deploy__s { font-size: 0.8125rem; color: var(--ink-muted); overflow-wrap: anywhere; }
.gc-deploy__parts { list-style: none; margin: -0.125rem 0 0; padding: 0; display: grid; gap: 0.125rem; font-size: 0.8125rem; color: var(--ink-2); }
.gc-deploy__parts li { position: relative; padding-left: 0.875rem; }
.gc-deploy__parts li::before { content: ""; position: absolute; left: 0.125rem; top: 0.55em; width: 0.3125rem; height: 0.3125rem; border-radius: 50%; background: rgb(var(--ink-rgb) / 0.3); }
.gc-more { margin-inline: calc(-1 * var(--pad)); border-top: 1px solid rgb(var(--ink-rgb) / 0.08); }
.gc-more summary {
  display: flex; align-items: center; gap: 0.5rem; padding: 1rem var(--pad) 0.875rem;
  list-style: none; cursor: pointer; font-size: 0.8125rem; font-weight: 600; color: var(--ink-2);
}
.gc-more summary::-webkit-details-marker { display: none; }
.gc-more summary::before {
  content: ""; width: 0.375rem; height: 0.375rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); transition: transform 0.14s ease;
}
.gc-more[open] summary::before { transform: rotate(45deg); }
.gc-more summary:hover { color: var(--violet); }
.gc-more summary:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; border-radius: 2px; }
.gc-more[open] summary { padding-bottom: 1rem; }
