/* =========================================================================
   AURORA 51°N — „Unter dem Nordlicht"  ·  Klickdummy / Design-Mockup
   Grundlage: PLAN-rebrand-polaris-2.md (v1.3)
     Kap. 4  visuelles Gesetz + Verbotsliste
     Kap. 5  Farben, Typografie, Licht/Material
     Kap. 6  Dramaturgie + Bewegungs-Budget
     Kap. 7  Shot-List (Textzonen)
     Kap. 9  Textsatz über 3D
     Kap. 11 Fallback-First
   Kein Produktionscode. Vanilla CSS, kein Build-Step.

   WICHTIG: Der CSS-Fallback ist der INITIALE Zustand (Kap. 11).
   `html.mode-journey` wird erst gesetzt, wenn three.js + GSAP + WebGL +
   der erste gültig gerenderte Frame stehen.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1 — TOKENS (Kap. 5.1, Evolution der V1-Tokens)
   ------------------------------------------------------------------------- */
:root {
  /* Runde 7 — global aufgehellt. Die Ausgangswerte (L 0.09 / 0.125 / 0.30)
     ergaben einen fast schwarzen Himmel; der Kunde las das als „Weltall".
     Die Hex-Fallbacks unten sind aus genau diesen OKLCH-Werten gerechnet,
     damit beide Zweige denselben Himmel zeigen. */
  /* Runde 13 (CI-Abgleich Farbkarte): der Himmel startet nicht mehr im
     Fast-Schwarz, sondern im CI-Navy #162347 und laeuft ueber die
     CI-Petroltoene #146e75 / #136b7f aus. Damit liest die Seite als
     blaue Stunde, nicht als tiefe Nacht. */
  /* Runde 15: zurueck ins Dunkle (edler), aber mit mehr CI-Farbspiel:
     Navy-Violett im Zenit, Tiefblau in der Polarnacht, Petrol am Horizont,
     Teal in der Daemmerung. */
  --zenit: oklch(0.2 0.05 272); /* ~#0e142c */
  --polarnacht: oklch(0.26 0.062 258); /* ~#0f2441 */
  --horizont: oklch(0.4 0.082 205); /* ~#00545d */
  /* Neutral blaugrüne Dämmerung am Fuß des Himmels — bewusst KEIN Amber,
     das bleibt markenseitig exklusiv Day One. */
  --daemmerung: oklch(0.48 0.072 196); /* ~#1d6a6b */

  /* Polaris. ACHTUNG: der Hex im @supports-Zweig unten ist NICHT dieselbe
     Farbe — Chromium rendert die OKLCH-Deklaration und die kommt als #dff81d
     heraus, nicht als #d8f300. Alle Kontrastzahlen im README sind gegen die
     GERENDERTE Farbe gerechnet.
     Verwendungsregel (Runde 9 präzisiert — „Punkt/Fill, nie Fläche" war schon
     vorher ungenau: `.skiplink` seit v1, `.cta--primary` seit Runde 7):
       erlaubt  — Logo-Dot, aktiver Marker, CTA-Rahmen und -Schrift,
                  gefüllter Button-Body, Fokusring
       verboten — Sektions-Hintergrund, Textfläche, Verlaufsfüllung,
                  Aurora-Band */
  --polaris: oklch(0.93 0.21 117);
  --aurora-557: oklch(0.85 0.16 163);
  --aurora-violett: oklch(0.48 0.14 305); /* nur oberster Aurora-Rand */
  /* Runde 12 (CI-Abgleich): Der Nordlichtvorhang selbst laeuft nicht mehr im
     Neongruen der Emissionslinie, sondern in einem entsaettigten Petrol-Teal
     aus der CI-Familie (--horizont / --daemmerung). --aurora-557 bleibt
     ausschliesslich Punkt-/Fill-Farbe fuer Bedienelemente. */
  --aurora-dezent: oklch(0.72 0.055 192);
  /* 630-nm-Sauerstoffrot (AP 3, Runde 9). h = 18 ist ab jetzt reserviert:
     ausschließlich die Aurora-Rotschicht — nie Fläche, nie Text, nie
     Bedienelement. Dieselbe Art Reservierung wie h ≈ 75 für Day One. */
  --aurora-rot: oklch(0.62 0.2 18);
  --sternenlicht: oklch(0.975 0.015 90);
  --mondgrau: oklch(0.78 0.025 255);
  /* Day-One-Warmton. Runde 9 (AP 5b): von oklch(0.80 0.12 75) auf
     oklch(0.86 0.045 96) — vom Amber zum Champagner. Der Kunde zu Day One
     als Event: „da passt für mich dieses Orange dann auch nicht." Die
     Reservierung bleibt: h ≈ 75…96 gehört ausschließlich Day One.
     Day One trägt ab jetzt Northlight-Gelb; dieser Ton ist nur noch das
     leise Licht dahinter, nicht mehr die Leitfarbe. */
  --erstes-licht: oklch(0.86 0.045 96); /* exklusiv Day One */
  /* Warnrot/-orange für Messwerte, die reißen. Bis Runde 8 lieh sich das
     `--erstes-licht` — damit war die Day-One-Reservierung faktisch gebrochen,
     und mit dem neuen Champagner wäre eine Warnung auch nicht mehr als
     Warnung lesbar. */
  --warnung: #e0a750;
  --lichtlinie: oklch(0.975 0.015 90 / 0.1);

  /* Tinte = dunkle Schrift auf LIME. Runde 9 hat die helle Kontaktsektion und
     den on-light-Header entfernt; danach bleiben genau vier Verwender, und
     alle vier meinen dasselbe: `::selection`, `.skiplink`, `.cta:hover` und
     `.cta--primary` — immer Polaris als Fläche, Tinte als Schrift darauf.
     Der Token bleibt trotzdem eigenständig und wird NICHT wieder mit
     `--zenit` verschmolzen: `--zenit` ist die dunkelste Himmelsfarbe und
     wandert mit dem Licht-Regler. Läge die Tinte darauf, würde die Schrift
     auf einer Lime-Fläche mit heller werden, obwohl ihre Trägerfläche gleich
     bleibt — Kontrastverlust an einer Stelle, die der Regler gar nicht meint.
     `--tinte` ist deshalb auf dem Runde-7-Zenit eingefroren. */
  --tinte: oklch(0.14 0.025 265);

  /* Der EINE Farbverlauf — gemeinsamer Anker von Fallback und WebGL (Kap. 11).
     Vier Stopps: der letzte trägt die Dämmerung über der Stadt. */
  --sky-gradient: linear-gradient(
    180deg,
    var(--zenit) 0%,
    color-mix(in oklab, var(--zenit) 62%, var(--polarnacht)) 22%,
    color-mix(in oklab, var(--polarnacht) 88%, var(--horizont)) 46%,
    color-mix(in oklab, var(--polarnacht) 52%, var(--horizont)) 72%,
    color-mix(in oklab, var(--horizont) 55%, var(--daemmerung)) 88%,
    var(--daemmerung) 100%
  );

  /* Runde 16: derselbe fliessende CI-Verlauf wie auf der publizierten Seite
     (FirstVersionLanding) — Teal oben links, Tiefblau in der Mitte, Petrol
     rechts unten, ein Hauch Lime am Fuss. Er liegt UEBER dem linearen
     Himmel und ersetzt die Kachel-Scrims hinter den Textbloecken. */
  --sky-flow:
    radial-gradient(
      at 10% 4%,
      color-mix(in oklab, var(--aurora-557) 24%, transparent) 0px,
      transparent 36%
    ),
    radial-gradient(
      at 18% 10%,
      color-mix(in oklab, var(--horizont) 68%, transparent) 0px,
      transparent 40%
    ),
    radial-gradient(
      at 62% 8%,
      color-mix(in oklab, var(--aurora-557) 18%, transparent) 0px,
      transparent 42%
    ),
    radial-gradient(
      at 85% 20%,
      color-mix(in oklab, var(--polarnacht) 64%, transparent) 0px,
      transparent 50%
    ),
    radial-gradient(
      at 92% 38%,
      color-mix(in oklab, var(--daemmerung) 42%, transparent) 0px,
      transparent 44%
    ),
    radial-gradient(
      at 48% 50%,
      color-mix(in oklab, var(--horizont) 22%, transparent) 0px,
      transparent 52%
    ),
    radial-gradient(
      at 22% 52%,
      color-mix(in oklab, var(--zenit) 78%, transparent) 0px,
      transparent 55%
    ),
    radial-gradient(
      at 68% 60%,
      color-mix(in oklab, var(--aurora-557) 16%, transparent) 0px,
      transparent 40%
    ),
    radial-gradient(
      at 82% 74%,
      color-mix(in oklab, var(--daemmerung) 48%, transparent) 0px,
      transparent 46%
    ),
    radial-gradient(
      at 34% 86%,
      color-mix(in oklab, var(--polaris) 16%, transparent) 0px,
      transparent 42%
    ),
    radial-gradient(
      at 52% 96%,
      color-mix(in oklab, var(--polaris) 22%, transparent) 0px,
      transparent 48%
    );

  /* Typografie — Runde 7: identisches Paar wie die Live-Seite
     (src/routes/__root.tsx). Kein Serif, keine Kursiven, kein Mono-Face.
     Die Serif-Fallbacks sind bewusst gepurgt: bei einem Ladefehler soll
     eine System-Sans einspringen, nicht Georgia. */
  --font-display:
    "Space Grotesk", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-sans: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /* `.mono` ist ab Runde 7 nur noch eine Optik (11 px / uppercase / tracking),
     kein Monospace-Schnitt mehr. Der Klassenname bleibt (~40 Verwendungen). */
  --font-mono:
    "Space Grotesk", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Motion-Grammatik (Kap. 5.2 — unverändert aus V1) */
  --t-instrument: 200ms;
  --t-reveal: 800ms;
  --t-zeremoniell: 1400ms;
  --e-house: cubic-bezier(0.22, 1, 0.36, 1);
  --e-expo: cubic-bezier(0.83, 0, 0.17, 1);
  --e-back: cubic-bezier(0.175, 0.885, 0.32, 1.275);

  /* Der Scrim aus Kap. 9 — hinter JEDEM Textblock. Die Deckkraft ist
     herausgezogen, weil sie mit der Himmelshelligkeit steigen muss: ein
     hellerer Himmel senkt den Textkontrast unmittelbar, und der Puffer über
     dem AA-Minimum beträgt nur 0.26 (gemessen 4.76:1 bei 4.5:1 Anforderung). */
  --scrim-a: 0.74;
  --scrim: radial-gradient(ellipse at center, rgba(7, 10, 20, var(--scrim-a)), transparent 72%);

  /* Horizontlage — identisch in Fallback und 3D-Kamera (Kap. 5.3) */
  --horizon: 58%;

  /* Vignette — vom Licht-Regler bewegt (siehe `.vignette` unten) */
  --vignette-a: 0.38;
  --vignette-r: 46%;

  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
}

/* Exakt aus den OKLCH-Werten oben gerechnet — nicht handgesetzt. Vor Runde 7
   lagen die Fallbacks rund fünf L-Punkte über den OKLCH-Deklarationen; in
   oklch-fähigen Browsern rendete deshalb ein anderer (dunklerer) Himmel als
   der, den `COL` in main.js spiegelte. */
@supports not (color: oklch(0.5 0.1 200)) {
  :root {
    --zenit: #0e142c;
    --polarnacht: #0f2441;
    --horizont: #00545d;
    --daemmerung: #1d6a6b;
    --polaris: #d8f300;
    --aurora-557: #6ee7b7;
    --aurora-violett: #6a4a9e;
    --aurora-dezent: #86b3bb;
    --aurora-rot: #e54156;
    --sternenlicht: #f7fffd;
    --mondgrau: #adb9c8;
    --erstes-licht: #e6dcc0;
    --warnung: #e0a750;
    --lichtlinie: rgba(247, 255, 253, 0.1);
    --tinte: #050913;
    --sky-gradient: linear-gradient(180deg, #162347 0%, #21335a 38%, #1a5169 66%, #3c8f97 100%);
  }
}

/* -------------------------------------------------------------------------
   2 — RESET & BASIS
   ------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
html.mode-journey {
  scroll-behavior: auto;
} /* Nav-Flüge steuern selbst */

body {
  margin: 0;
  background: var(--zenit);
  color: var(--sternenlicht);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.62;
  /* Space Grotesk hat kein Italic-Face — ohne diese Zeile würde der Browser
     jede verbliebene Kursive schräg stellen und genau den Look zurückholen,
     den Runde 7 entfernt. */
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Auf leistungsfähigen Desktop-Geräten bleibt der erste Paint unsichtbar,
   bis die finale WebGL-Welt texturiert und über zwei Frames stabil ist.
   So erscheint nie die abweichende CSS-Komposition vor der Logoformation. */
html.hero-world-pending body {
  opacity: 0;
}

img,
svg,
canvas {
  display: block;
  max-width: 100%;
}
a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--polaris);
  outline-offset: 3px;
  border-radius: 2px;
}
:focus:not(:focus-visible) {
  outline: none;
}
::selection {
  background: var(--polaris);
  color: var(--tinte);
}

.mono {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 500;
  /* Ersatz für den entfallenen Monospace-Schnitt: Koordinate, Countdown und
     Datumszeile bleiben in der Ziffernbreite ruhig. */
  font-variant-numeric: tabular-nums;
}
/* Der Klassenname `.serif` bleibt aus Diff-Gründen stehen; ab Runde 7 meint
   er „Display-Schnitt" (Space Grotesk), nicht mehr Serif. */
.serif {
  font-family: var(--font-display);
  font-weight: 700;
}
/* Die 13 <em> im HTML bleiben unangetastet — nur die Regel wird neutralisiert. */
.serif em {
  font-style: normal;
}

.skiplink {
  position: absolute;
  left: 16px;
  top: -100px;
  z-index: 1000;
  padding: 10px 18px;
  background: var(--polaris);
  color: var(--tinte);
  font: 500 12px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 2px;
}
.skiplink:focus {
  top: 16px;
}
/* Lime auf Lime — wie bei `.cta`. Der Skiplink ist eine Polaris-FLÄCHE, sein
   Fokusring braucht deshalb erst recht eine eigene Farbe. */
.skiplink:focus-visible {
  outline-color: var(--aurora-557);
}

/* -------------------------------------------------------------------------
   3 — HINTERGRUND-STAPEL
   `.skybase` verschwindet nie: derselbe Farbverlauf liegt unter dem
   CSS-Fallback UND unter dem transparenten WebGL-Canvas. Auf Desktop wird
   der Aufbau verborgen und erst die vollständig stabile 3D-Welt gezeigt.
   ------------------------------------------------------------------------- */
.skybase {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: var(--sky-flow), var(--sky-gradient);
  pointer-events: none;
}

.sky {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  will-change: opacity;
}

.stage {
  position: fixed;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
}

/* Hero-only Matte: eine additive Tiefenlage über der echten 3D-Rheinebene.
   Das reine Schwarz verschwindet im Screen-Blend; nur Wasserreflexe,
   Froststaffelung und Fernufer bleiben. main.js blendet sie vor Akt 1 aus. */
.hero-matte {
  position: fixed;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  will-change: opacity;
}
.hero-matte::before {
  content: "";
  position: absolute;
  inset: -10% 0;
  transform: translateY(-8.333%);
  /* Aufraeumer 24.08.2026 (Plan §7.1): Das Bild ist in dieser Kopie nie
     sichtbar. Die 3D-Journey ist dauerhaft aus (main.js `canDo3D()` gibt
     `false` zurueck), `.hero-matte` bleibt damit auf `opacity: 0`, und
     `showShellFallback()` setzt sie beim Laden zusaetzlich auf 0. Geladen
     wurde rhine-matte-v3.png trotzdem bei jedem Seitenaufruf — 990 KB,
     gemessen am 24.08.2026 an der Hauptseite.
     Die Originalzeile stand hier:
       background: #000 url("./assets/rhine-matte-v3.png") center / cover no-repeat;
     Die Datei bleibt im Ordner liegen. Wer die 3D-Ebene zurueckholt, holt
     diese Zeile mit zurueck. */
  background: #000;
  filter: saturate(0.78) contrast(1.12) brightness(0.82);
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0 43%,
    rgba(0, 0, 0, 0.45) 52%,
    #000 64%
  );
  mask-image: linear-gradient(to bottom, transparent 0 43%, rgba(0, 0, 0, 0.45) 52%, #000 64%);
}

.dim {
  position: fixed;
  inset: 0;
  z-index: 3;
  background: var(--zenit);
  opacity: 0;
  pointer-events: none;
}

.amber {
  position: fixed;
  inset: 0;
  z-index: 4;
  opacity: 0;
  pointer-events: none;
  background:
    radial-gradient(
      ellipse 38% 16% at 50% calc(var(--horizon) - 7%),
      color-mix(in oklab, var(--erstes-licht) 78%, transparent) 0%,
      color-mix(in oklab, var(--erstes-licht) 26%, transparent) 42%,
      transparent 100%
    ),
    radial-gradient(
      ellipse 9% 30% at 33% 72%,
      color-mix(in oklab, var(--erstes-licht) 18%, transparent) 0%,
      transparent 100%
    );
}

/* Korn + Vignette liegen über dem Canvas, aber UNTER dem Text (Kap. 8) */
/* Deckkraft und Innenradius sind Variablen, weil der Licht-Regler sie mit der
   Himmelshelligkeit zurücknimmt: eine harte Vignette über einem hellen Himmel
   liest sich als Objektiv-Fehler, nicht als Nacht. */
.vignette {
  position: fixed;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background: radial-gradient(
    120% 90% at 50% 46%,
    transparent var(--vignette-r),
    rgba(4, 6, 12, var(--vignette-a)) 100%
  );
}

.grain {
  position: fixed;
  inset: -50%;
  z-index: 6;
  pointer-events: none;
  background-image: var(--grain);
  opacity: 0.035;
  mix-blend-mode: overlay;
}

/* Aurora-Wipe für Nav-Sprünge ab dem zweiten Klick (Kap. 10) */
.wipe {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    100deg,
    transparent 0%,
    color-mix(in oklab, var(--horizont) 60%, transparent) 26%,
    color-mix(in oklab, var(--aurora-557) 78%, transparent) 47%,
    color-mix(in oklab, var(--aurora-dezent) 30%, transparent) 58%,
    transparent 86%
  );
  transform: translateX(-120%);
  filter: blur(26px);
}

/* ---- CSS-Fallback-Komposition (initialer Zustand) ---- */
/* Runde 7: Alphas × 0.6 — dieselbe Sternenzahl, aber Dämmerung statt Weltall. */
.sky__stars {
  position: absolute;
  inset: 0 0 42% 0;
  background-image:
    radial-gradient(1.1px 1.1px at 12% 18%, rgba(247, 255, 253, 0.37), transparent 60%),
    radial-gradient(1px 1px at 27% 9%, rgba(247, 255, 253, 0.25), transparent 60%),
    radial-gradient(1.2px 1.2px at 41% 26%, rgba(247, 255, 253, 0.3), transparent 60%),
    radial-gradient(1px 1px at 58% 12%, rgba(247, 255, 253, 0.23), transparent 60%),
    radial-gradient(1.3px 1.3px at 71% 22%, rgba(247, 255, 253, 0.33), transparent 60%),
    radial-gradient(1px 1px at 84% 8%, rgba(247, 255, 253, 0.2), transparent 60%),
    radial-gradient(1.1px 1.1px at 92% 30%, rgba(247, 255, 253, 0.26), transparent 60%),
    radial-gradient(1px 1px at 6% 34%, rgba(247, 255, 253, 0.18), transparent 60%),
    radial-gradient(1px 1px at 34% 40%, rgba(247, 255, 253, 0.16), transparent 60%),
    radial-gradient(1px 1px at 64% 37%, rgba(247, 255, 253, 0.17), transparent 60%);
}

.sky__bands {
  position: absolute;
  inset: 0;
  overflow: hidden;
  display: none;
}
.sky__bands::before {
  content: "";
  position: absolute;
  inset: 0 0 33%;
  background:
    linear-gradient(
      180deg,
      rgba(7, 10, 20, 0.02) 0%,
      rgba(7, 10, 20, 0.08) 58%,
      var(--polarnacht) 100%
    ),
    radial-gradient(
      ellipse 34% 48% at 31% 30%,
      color-mix(in oklab, var(--polaris) 17%, transparent) 0%,
      color-mix(in oklab, var(--polaris) 8%, transparent) 34%,
      transparent 72%
    ),
    radial-gradient(
      ellipse 27% 42% at 69% 38%,
      color-mix(in oklab, var(--polaris) 12%, transparent) 0%,
      color-mix(in oklab, var(--polaris) 5%, transparent) 38%,
      transparent 74%
    ),
    linear-gradient(
      180deg,
      color-mix(in oklab, var(--aurora-dezent) 16%, transparent) 0%,
      color-mix(in oklab, var(--horizont) 12%, transparent) 62%,
      transparent 100%
    ),
    url("./assets/aurora-curtain-v3.png") center 38% / cover no-repeat;
  opacity: 0.5;
  /* Runde 12: die PNG bleibt unangetastet, ihr Neongruen wird hier
     zurueckgenommen — entsaettigt, Richtung Petrol gedreht, abgedunkelt.
     Runde 14: zusaetzlich ein winziger Hauch Logo-Gelb, sehr dezent.
     Runde 17: Schleimschimmer etwas intensiver — mehr Farbe, aber noch
     dezent genug, dass der Navy-Grundton dominiert. */
  filter: saturate(0.55) hue-rotate(-14deg) brightness(0.88) contrast(1.08);
  mix-blend-mode: screen;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 70%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 70%, transparent 100%);
}
/* AP 3 (Runde 9): Rot im Nordlicht, CSS-Seite. `::before` trägt bereits die
   Aurora-PNG und ist damit belegt — die Rotschicht liegt deshalb auf
   `::after`, durch dieselbe PNG maskiert, damit sie den Vorhängen folgt und
   nicht als Rechteck über dem Himmel liegt.

   Der Fallback hat nur EINE Rotschicht, obwohl das WebGL zwei Regler kennt.
   Das ist kein Versehen: `uTop` verschiebt dort eine Farbrampe über die Höhe
   der Vorhänge, und eine PNG hat keine Rampe, die sich verschieben ließe.
   Beide Regler speisen deshalb hier denselben Layer — `--rot-top` mit dem
   größeren Anteil, weil das die gewählte Variante ist (B).

   Beide Variablen schreibt main.js VOR `canDo3D()`. In `build()` wären sie
   nie angekommen, wo es gar kein WebGL gibt: Touch, reduced motion,
   unter 1024 px. */
.sky__bands::after {
  content: "";
  position: absolute;
  inset: 0 0 52%;
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--aurora-rot) 38%, transparent) 0%,
    color-mix(in oklab, var(--aurora-rot) 20%, transparent) 46%,
    transparent 100%
  );
  opacity: calc(var(--rot-top, 0) * 0.1 + var(--rot-crown, 0) * 0.15);
  mix-blend-mode: screen;
  pointer-events: none;
  -webkit-mask-image: url("./assets/aurora-curtain-v3.png");
  mask-image: url("./assets/aurora-curtain-v3.png");
  -webkit-mask-size: cover;
  mask-size: cover;
  -webkit-mask-position: center 38%;
  mask-position: center 38%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.sky__bands .band {
  display: none;
}

/* Vorhänge stehen AUF der Horizontlinie und wachsen nach oben — dieselbe
   Anordnung wie die kameragekoppelten Bänder im WebGL (Kap. 5.3). Die
   Streifen entstehen aus einer Maske, nicht aus zusätzlichen Elementen. */
.band {
  position: absolute;
  bottom: calc(100% - var(--horizon));
  transform-origin: 50% 100%;
  mix-blend-mode: screen;
  -webkit-mask-image: var(--striae), var(--curtain-falloff);
  -webkit-mask-composite: source-in;
  mask-image: var(--striae), var(--curtain-falloff);
  mask-composite: intersect;
}

:root {
  /* Streifen (die „Schweife") und weiche Vorhangränder — ohne Zusatz-Elemente */
  --striae: repeating-linear-gradient(
    90deg,
    rgba(0, 0, 0, 0.08) 0px,
    rgba(0, 0, 0, 0.95) 11px,
    rgba(0, 0, 0, 0.14) 23px,
    rgba(0, 0, 0, 0.55) 38px,
    rgba(0, 0, 0, 0.06) 52px,
    rgba(0, 0, 0, 0.85) 66px,
    rgba(0, 0, 0, 0.1) 80px
  );
  --curtain-falloff: linear-gradient(90deg, transparent 0%, #000 20%, #000 80%, transparent 100%);
}

/* Farbe: sehr dezenter Petrol-Horizont mit einem zarten, aber spürbareren
   Hauch Logo-Gelb. --polaris (Gelb) wird nur in kleinen Anteilen eingemischt,
   damit der Himmel die Farbe aufnimmt, ohne dass die Schweife selbst gelb
   leuchten. */
.band--a {
  left: 4%;
  width: 62%;
  height: 36%;
  background: linear-gradient(
    180deg,
    transparent 0%,
    color-mix(in oklab, var(--daemmerung) 18%, transparent) 12%,
    color-mix(in oklab, var(--aurora-dezent) 26%, transparent) 44%,
    color-mix(in oklab, var(--polaris) 8%, transparent) 54%,
    color-mix(in oklab, var(--aurora-dezent) 18%, transparent) 78%,
    transparent 100%
  );
  opacity: 0.4;
  filter: blur(12px);
  animation: drift 24s ease-in-out infinite alternate;
}
.band--b {
  left: 44%;
  width: 52%;
  height: 29%;
  background: linear-gradient(
    180deg,
    transparent 0%,
    color-mix(in oklab, var(--daemmerung) 12%, transparent) 14%,
    color-mix(in oklab, var(--aurora-dezent) 22%, transparent) 50%,
    color-mix(in oklab, var(--polaris) 7%, transparent) 60%,
    color-mix(in oklab, var(--horizont) 16%, transparent) 84%,
    transparent 100%
  );
  opacity: 0.32;
  filter: blur(15px);
  animation: drift 30s ease-in-out infinite alternate-reverse;
}
.band--c {
  left: -6%;
  width: 34%;
  height: 22%;
  background: linear-gradient(
    180deg,
    transparent 0%,
    color-mix(in oklab, var(--aurora-dezent) 18%, transparent) 42%,
    color-mix(in oklab, var(--polaris) 5%, transparent) 52%,
    color-mix(in oklab, var(--horizont) 16%, transparent) 86%,
    transparent 100%
  );
  opacity: 0.24;
  filter: blur(13px);
  animation: drift 26s ease-in-out infinite alternate;
}

/* Der Schweif — vierter, schmaler Streifen, neigt sich zum Boden (Kap. 5.3) */
.sky__tail {
  display: none;
}

@keyframes drift {
  0% {
    transform: translateX(-1.6%) scaleY(1) skewX(-1.2deg);
  }
  100% {
    transform: translateX(1.8%) scaleY(1.07) skewX(1.6deg);
  }
}

/* Der Horizont verschwindet im Nebel, nie als harte Kante (Kap. 5.3) */
.sky__haze {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--horizon) - 15%);
  height: 30%;
  background: linear-gradient(
    180deg,
    transparent 0%,
    color-mix(in oklab, var(--polarnacht) 72%, transparent) 46%,
    color-mix(in oklab, var(--polarnacht) 92%, transparent) 62%,
    color-mix(in oklab, var(--polarnacht) 55%, transparent) 100%
  );
  filter: blur(14px);
}

/* Nocturne-Schwester der WebGL-Skyline. Mobile, Reduced Motion und < 1024 px
   sehen ausschließlich diese statische, aber motivisch deckungsgleiche Welt. */
.sky__skyline {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% - var(--horizon));
  height: 12%;
  opacity: 1;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 200' preserveAspectRatio='none'%3E%3Cg fill='%2316303f'%3E%3Cpath d='M0,200 V178 H46 V162 H92 V184 H132 V148 H164 V172 H198 V132 H232 V174 H262 V152 H292 V180 H336 V160 H386 V126 H428 V162 H470 V142 H506 V176 H552 V152 H598 V178 H648 V156 H692 V180 H744 V150 H792 V176 H846 V136 H880 V172 H928 V158 H974 V180 H1028 V150 H1076 V174 H1132 V162 H1200 V200 Z'/%3E%3Cpath d='M401,182 h15 l-3.4,-104 h-8.2 Z'/%3E%3Cellipse cx='408.5' cy='74' rx='12' ry='6.5'/%3E%3Cpath d='M406.5,68 h4 l-1,-56 h-2 Z'/%3E%3Crect x='700' y='100' width='5.5' height='80'/%3E%3Crect x='820' y='100' width='5.5' height='80'/%3E%3Crect x='648' y='148' width='230' height='4.5'/%3E%3C/g%3E%3Cg stroke='%2316303f' stroke-width='1.4' fill='none'%3E%3Cpath d='M702,102 L748,148 M702,116 L734,148 M702,102 L656,148 M702,116 L670,148'/%3E%3Cpath d='M822,102 L868,148 M822,116 L854,148 M822,102 L776,148 M822,116 L790,148'/%3E%3C/g%3E%3Cg fill='%236ee7b7' opacity='0.62'%3E%3Ccircle cx='408.5' cy='150' r='1.6'/%3E%3Ccircle cx='408.5' cy='138' r='1.6'/%3E%3Ccircle cx='408.5' cy='126' r='1.6'/%3E%3Ccircle cx='408.5' cy='114' r='1.6'/%3E%3Ccircle cx='408.5' cy='102' r='1.6'/%3E%3Ccircle cx='408.5' cy='90' r='1.6'/%3E%3Ccircle cx='408.5' cy='12' r='1.8'/%3E%3C/g%3E%3Cg fill='%23e6f2ec' opacity='0.4'%3E%3Ccircle cx='150' cy='158' r='1.2'/%3E%3Ccircle cx='214' cy='146' r='1.2'/%3E%3Ccircle cx='218' cy='158' r='1.2'/%3E%3Ccircle cx='352' cy='170' r='1.2'/%3E%3Ccircle cx='446' cy='154' r='1.2'/%3E%3Ccircle cx='522' cy='160' r='1.2'/%3E%3Ccircle cx='612' cy='166' r='1.2'/%3E%3Ccircle cx='862' cy='150' r='1.2'/%3E%3Ccircle cx='866' cy='164' r='1.2'/%3E%3Ccircle cx='944' cy='170' r='1.2'/%3E%3Ccircle cx='1046' cy='162' r='1.2'/%3E%3C/g%3E%3C/svg%3E")
    bottom center / 100% 100% no-repeat;
}

/* Runde 8: Die externe Datei ersetzt die ältere Inline-Silhouette oberhalb.
   Die separate Deklaration hält den Fallback-Backport bewusst risikoarm.
   Runde 14: Die Bandhoehe haengt nicht mehr an der Viewport-HOEHE, sondern
   an der BREITE. Nur so bleibt das Groessenverhaeltnis der Skyline (und der
   Gehry-Bauten) auf Tablet und Handy identisch zum Desktop — vorher wurde
   das Motiv seitlich gestaucht, weil die Breite schrumpfte, die Bandhoehe
   aber nicht. */
.sky__skyline {
  /* Kundenwunsch 28.08. (2): Das Band wird UNIFORM verkleinert — breitere
     Seitenraender (15 %) bei nativem SVG-Seitenverhaeltnis 1113:303.
     So sinkt die Gesamthoehe (Rheinturm bleibt unter dem Menue), ohne
     die Proportionen der Gebaeude vertikal zu stauchen. */
  left: 15%;
  right: 15%;
  height: auto;
  aspect-ratio: 1113 / 303;
  background: url("assets/skyline-nocturne.svg") bottom center / 100% 100% no-repeat;
}

/* Runde 18: Die Skyline ist eine 1:1-Nachzeichnung der Referenz. Sie enthaelt
   den Rheinturm bereits; die separate Turm-Ebene entfaellt deshalb. */
.sky__turm {
  display: none;
}

/* Abstrahierte Rheinebene: flacher Horizont, sanfte Geländewellen */
.sky__land {
  position: absolute;
  left: -2%;
  right: -2%;
  top: var(--horizon);
  bottom: 0;
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--polarnacht) 88%, var(--horizont)) 0%,
    var(--zenit) 74%
  );
  clip-path: polygon(
    0% 12%,
    7% 8%,
    14% 11%,
    22% 6%,
    30% 10%,
    38% 5%,
    46% 9%,
    54% 4%,
    62% 8%,
    70% 5%,
    78% 9%,
    86% 6%,
    93% 10%,
    100% 7%,
    100% 100%,
    0% 100%
  );
}

/* Die Aurora spiegelt sich im Rhein (Kap. 5.3, Opacity 0.25) */
.sky__river {
  position: absolute;
  left: 30%;
  right: 34%;
  top: calc(var(--horizon) + 1%);
  bottom: -6%;
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--aurora-dezent) 25%, transparent) 0%,
    color-mix(in oklab, var(--horizont) 22%, transparent) 42%,
    color-mix(in oklab, var(--zenit) 40%, transparent) 100%
  );
  filter: blur(9px);
  transform: perspective(320px) rotateX(58deg) scaleX(2.6);
  transform-origin: 50% 0;
  opacity: 0.6;
  mix-blend-mode: screen;
}

/* -------------------------------------------------------------------------
   4 — HERO-LOGO-FORMATION: kein Einspieler, sondern Teil von Akt 0.
   Der erste sichtbare Desktop-Frame enthält bereits die stabile 3D-Welt und
   den beginnenden Sternenstrom an der finalen Logo-Position.
   ------------------------------------------------------------------------- */
/* Runde 7: 660 → 540 px. NICHT weiter herunter — intro.js:265 schaltet
   unterhalb von 520 px Breite von 1050 auf 560 Partikel und verändert damit
   die Formation, nicht nur die Größe. */
.hero__brand {
  position: relative;
  width: min(540px, 52vw);
  aspect-ratio: 294.38 / 81.76;
  margin: 0 auto clamp(2px, 0.4vw, 6px);
  isolation: isolate;
}
.hero__logo-lockup {
  position: absolute;
  inset: 0;
  z-index: 2;
  filter: drop-shadow(0 0 34px rgba(4, 226, 183, 0.065)); /* Runde 7: halbiert */
  pointer-events: none;
}
.hero__logo {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  object-fit: contain;
}
.hero__particles {
  position: absolute;
  z-index: 1;
  left: -18%;
  top: -35%;
  width: 136%;
  height: 170%;
  max-width: none;
  pointer-events: none;
  overflow: visible;
}
.hero__dot-pop {
  position: absolute;
  left: 83.42%;
  top: 73.2%;
  width: 3.32%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--polaris);
  opacity: 0;
  transform: translate(-50%, -50%) scale(0);
  box-shadow: 0 0 18px 2px color-mix(in oklab, var(--polaris) 55%, transparent);
  pointer-events: none;
  will-change: transform, opacity;
}

/* Erst das laufende Skript verbirgt die Wortmarke. Fällt es schon beim
   Laden aus, bleibt das echte SVG ohne Wartezeit sichtbar (fail-open). */
html.hero-logo-running .hero__logo {
  opacity: 0;
  clip-path: inset(0 14.9% 0 0);
}
html.hero-logo-running .hero__logo,
html.hero-logo-running .hero__dot-pop {
  animation: none !important;
}
html[data-hero-logo="seen"] .hero__logo,
html.motion-off .hero__logo {
  opacity: 1;
  clip-path: none;
}
html.motion-off .hero__logo {
  animation: none;
}
html[data-hero-logo="seen"] .hero__particles,
html.motion-off .hero__particles {
  display: none;
}

/* Deutlicher, aber immer noch eleganter Puls des großen Hero-Logos. */
@keyframes logo-pulse {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.06);
  }
}
.hero__logo {
  animation: logo-pulse 4.5s ease-in-out infinite;
  transform-origin: center;
}

/* -------------------------------------------------------------------------
   5 — HEADER (Kap. 10)
   ------------------------------------------------------------------------- */
.hd {
  position: fixed;
  z-index: 40;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  padding: 20px clamp(18px, 4vw, 48px);
  transition:
    padding var(--t-instrument, 0.3s) var(--e-house, ease),
    transform 0.42s var(--e-house, cubic-bezier(0.22, 1, 0.36, 1));
}
/* Runde 18: Der Header fährt beim Runterscrollen nach oben aus dem Bild und
   beim Hochscrollen wieder ein (Apple-Manier). Zustand kommt aus main.js. */
.hd.is-tucked {
  transform: translateY(-100%);
}
.hd.is-tucked .hd__panel {
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .hd {
    transition: none;
  }
}

/* Runde 17: Der Header lag beim Scrollen transparent auf der Seitenschrift.
   Statt einer harten Kachel rastet er jetzt zu einer schmalen Registerleiste
   ein: leichtes Glas (Blur), CI-Navy-Schleier und eine Haarlinie als Kante.
   Im Seitenkopf (ungescrollt) bleibt er vollstaendig transparent. */
.hd::before {
  content: "";
  position: absolute;
  inset: 0;
  background: none;
  border-bottom: 1px solid transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  pointer-events: none;
  transition:
    background var(--t-instrument, 0.3s) ease,
    border-color var(--t-instrument, 0.3s) ease,
    backdrop-filter var(--t-instrument, 0.3s) ease;
}
.hd.is-scrolled {
  padding-top: 12px;
  padding-bottom: 12px;
}
.hd.is-scrolled::before {
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--polarnacht, #162347) 78%, transparent) 0%,
    color-mix(in oklab, var(--polarnacht, #162347) 62%, transparent) 100%
  );
  border-bottom-color: color-mix(in oklab, var(--aurora-557) 26%, transparent);
  backdrop-filter: blur(14px) saturate(1.12);
  -webkit-backdrop-filter: blur(14px) saturate(1.12);
  box-shadow: 0 10px 30px rgba(7, 10, 20, 0.28);
  -webkit-mask-image: none;
  mask-image: none;
}

.hd > * {
  position: relative;
}
.hd__panel {
  display: contents;
}
.hd__burger {
  display: none;
}

.hd__mark {
  position: relative;
  display: block;
  text-decoration: none;
  flex: 0 0 auto;
  width: clamp(102px, 7.8vw, 124px);
}
.hd__logo {
  width: 100%;
  height: auto;
  transition: opacity var(--t-instrument) var(--e-house);
}
.hd__mark:hover .hd__logo {
  opacity: 0.84;
  filter: drop-shadow(0 0 9px color-mix(in oklab, var(--aurora-557) 35%, transparent));
}

.hd__nav {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.7vw, 26px);
  flex: 1 1 auto;
}
.nav__l {
  position: relative;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mondgrau);
  text-decoration: none;
  padding: 6px 0;
  white-space: nowrap;
}
.nav__l i {
  font-style: normal;
  color: color-mix(in oklab, var(--mondgrau) 84%, transparent);
  margin-right: 4px;
}
.nav__l::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 1px;
  background: var(--aurora-557);
  transition: right var(--t-instrument) var(--e-house);
}
.nav__l:hover,
.nav__l[aria-current="true"] {
  color: var(--sternenlicht);
}
.nav__l:hover::after,
.nav__l[aria-current="true"]::after {
  right: 0;
}
.nav__l[aria-current="true"] i {
  color: var(--polaris);
}

.hd__inst {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: 0 0 auto;
}
.hd__coord {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  color: var(--aurora-557);
}
.hd__tog {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: none;
  border: 1px solid var(--lichtlinie);
  border-radius: 2px;
  padding: 6px 10px;
  cursor: pointer;
  font: 500 9.5px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mondgrau);
}
.hd__tog:hover {
  color: var(--sternenlicht);
  border-color: var(--aurora-557);
}
.hd__togdot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: color-mix(in oklab, var(--mondgrau) 50%, transparent);
  transition: background var(--t-instrument) var(--e-house);
}
.hd__tog[aria-pressed="true"] .hd__togdot {
  background: var(--polaris);
}
.hd__tog[aria-pressed="true"] {
  color: var(--sternenlicht);
}

.prog {
  position: fixed;
  z-index: 41;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  pointer-events: none;
}
.prog i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--aurora-557);
  box-shadow: 0 0 8px color-mix(in oklab, var(--aurora-557) 60%, transparent);
}

/* Der `html.on-light`-Block ist mit Runde 9 (AP 1) ersatzlos entfallen: er
   drehte den Header über der hellen Kontaktfläche auf dunkle Schrift. Es gibt
   keine helle Fläche mehr, der Header bleibt durchgehend dunkel. */

/* -------------------------------------------------------------------------
   6 — JOURNEY: FALLBACK-LAYOUT (Kap. 11 — der initiale Zustand)
   Ohne JS / ohne WebGL / auf Mobile: normale, vollständig lesbare Sektionen.
   ------------------------------------------------------------------------- */
.journey {
  position: relative;
  z-index: 10;
}

.act {
  position: relative;
  padding: clamp(72px, 12vh, 148px) clamp(20px, 6vw, 96px);
}
.act--0 {
  padding-top: clamp(140px, 26vh, 280px);
  padding-bottom: clamp(72px, 14vh, 150px);
  min-height: 100vh;
  display: flex;
  align-items: flex-end;
  overflow-x: clip;
}
.act__inner {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
}

.zone {
  position: relative;
  max-width: 640px;
}
.zone--center,
.zone--statement,
.zone--dayone {
  margin-inline: auto;
  text-align: center;
}
.act--0 .zone--center {
  width: min(760px, 84vw);
  max-width: none;
}
.zone--right {
  margin-left: auto;
}

/* Runde 16: kein Scrim mehr hinter den Textbloecken. Die Aurora-Flaechen sind
   seit Runde 14 aus, der Himmel ist ueberall dunkles CI-Navy/Petrol — die
   getoenten Ellipsen waren nur noch als angedeutete Kacheln sichtbar.
   Der Block bleibt als leeres ::before stehen, damit `--scrim-a` (Licht-
   Regler) und die Journey-Logik weiter greifen koennen, ohne Selektor-Umbau. */
.zone::before {
  content: "";
  position: absolute;
  inset: 0;
  background: none;
  z-index: -1;
  pointer-events: none;
}

.eyebrow {
  margin: 0 0 18px;
  color: var(--aurora-557);
  letter-spacing: 0.28em;
}
/* AP 5b: Der Eyebrow trug --erstes-licht und traf im CSS-Fallback das helle
   Aurora-Grün — gemessen 1,50:1 bei 1023 px, also weit unter AA. Off-White
   trägt dort, und Day One bekommt seine Farbe jetzt ohnehin über den Ring
   und die Grafik, nicht über die Schrift. */
.eyebrow--warm {
  color: var(--sternenlicht);
}

h1.serif {
  margin: 0 0 22px;
  font-size: clamp(48px, 8.4vw, 118px);
  line-height: 0.95;
  letter-spacing: -0.02em;
}
/* Runde 13: Der Subclaim ist Teil des Logo-Lockups, nicht eine eigene,
   zentrierte Zeile. Er sitzt direkt unter der Wortmarke und beginnt auf der
   Achse des "g" von northlight — im Logo-SVG startet dessen Pfad bei x=291
   im viewBox 162…400, also bei 54,2 % der Logobreite. Breite und Zentrierung
   sind identisch zu .hero__brand, damit die Achse bei jeder Viewportbreite
   stimmt. */
.hero__h1-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.act--0 .hero__brand {
  margin-bottom: clamp(24px, 3.2vw, 38px);
}
.act--0 h1.serif em {
  font-style: normal;
}

h2.serif {
  margin: 0 0 20px;
  font-size: clamp(34px, 4.6vw, 62px);
  line-height: 1.06;
  letter-spacing: -0.02em;
}

/* Fließtext max. 34 ch (Kap. 9) — Headlines sind davon ausgenommen */
.lead,
.proof,
.statement__sub,
.light__lead {
  max-width: 34ch;
}
.zone--center .lead,
.zone--center .proof,
.zone--statement .statement__sub {
  margin-inline: auto;
}

.lead {
  margin: 0 0 26px;
  color: var(--mondgrau);
  font-size: clamp(15px, 1.4vw, 18px);
  max-width: 52ch;
}
.lead__topline {
  white-space: nowrap;
}
.proof {
  margin: 0 0 26px;
  color: var(--mondgrau);
  font-size: 15.5px;
}
.proof b {
  color: var(--sternenlicht);
  font-weight: 500;
}
.act--1 .proof {
  max-width: none;
  width: max-content;
}
.proof__line {
  display: block;
  white-space: nowrap;
}
.act--3 .proof {
  max-width: none;
  width: max-content;
}

@media (max-width: 520px) {
  .act--1 .proof,
  .act--3 .proof {
    font-size: 13px;
  }
}

.odo {
  margin: 6px 0 0;
  line-height: 0.9;
  font-size: clamp(58px, 8vw, 120px);
  font-weight: 600;
  letter-spacing: -0.02em;
  /* main.js schreibt den Zähler pro Frame — ohne tabellarische Ziffern
     zittert die Zahl bei jedem Schritt in der Breite. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  color: var(--sternenlicht);
}
.odo__label {
  margin: 8px 0 10px;
  color: var(--aurora-557);
  letter-spacing: 0.24em;
}
.odo__second {
  margin: 0 0 26px;
  color: color-mix(in oklab, var(--mondgrau) 88%, transparent);
  letter-spacing: 0.2em;
}
.odo__second b {
  color: var(--sternenlicht);
  font-weight: 600;
}

.statement {
  font-size: clamp(32px, 4.4vw, 66px);
  line-height: 1.08;
  max-width: 20ch;
  margin-inline: auto;
}
.statement__sub {
  margin: 22px auto 0;
  color: var(--mondgrau);
}

/* AP 9: die Marker-Signatur der Stationen — Day One liest damit als Station
   der Reise, ohne eine Nummer zu bekommen.
   Runde 9 (AP 5b): der Ring stand in Amber. Day One trägt jetzt
   Northlight-Gelb, weil der Kunde das Orange ausdrücklich verworfen hat. */
.dayone__marker {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.dayone__ring {
  position: relative;
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 1px solid color-mix(in oklab, var(--polaris) 62%, transparent);
}
.dayone__ring::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  border-radius: 50%;
  background: var(--polaris);
  box-shadow: 0 0 9px 1px color-mix(in oklab, var(--polaris) 55%, transparent);
}

/* AP 5b: Day One ist mit 4,99:1 der engste Messpunkt der ganzen Seite, und
   die additiven Akzente der Bühne hellen den Grund dort zusätzlich auf.
   --mondgrau ist der sicherere Träger als der Warmton. */
.dayone__meta {
  margin: 0 0 12px;
  color: var(--mondgrau);
  letter-spacing: 0.2em;
}
.dayone__date {
  color: var(--aurora-557);
  white-space: nowrap;
}
@media (max-width: 520px) {
  .dayone__date {
    white-space: normal;
  }
}

.dayone__countdown {
  display: block;
  margin-top: 6px;
  color: var(--mondgrau);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
}

@media (min-width: 768px) {
  .dayone__countdown {
    font-size: 12px;
    letter-spacing: 0.22em;
  }
}

.dayone__block {
  margin-top: 26px;
}
.dayone__subhead {
  margin: 28px 0 12px;
  color: var(--polaris);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.ov__box > .dayone__subhead:first-of-type {
  margin-top: 0;
}

.dayone__speakers {
  list-style: none;
  margin: 0;
  padding: 0;
}
.dayone__speakers li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 0;
  border-bottom: 1px solid color-mix(in oklab, var(--lichtlinie) 35%, transparent);
}
.dayone__speakers li:first-child {
  padding-top: 0;
}
.dayone__speakers li:last-child {
  border-bottom: none;
}
.dayone__speakers strong {
  color: var(--sternenlicht);
  font-weight: 600;
  font-size: 15px;
}
.dayone__speakers span {
  color: var(--mondgrau);
  font-size: 13px;
  line-height: 1.45;
}

/* Kompakte Namens-Liste ohne Rollen */
.dayone__speakers--names {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px 18px;
}
.dayone__speakers--names li {
  display: block;
  padding: 0;
  border-bottom: none;
  color: var(--sternenlicht);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.4;
}

.dayone__ticket-note {
  margin: 0 0 16px;
  color: var(--mondgrau);
  font-size: 13px;
  line-height: 1.5;
}

.dayone__tickets {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.zone--dayone .proof {
  margin-bottom: 22px;
}

/* ---- AP 5a: Day One als Event, CSS-Fallback ------------------------------
   Der Kunde bat um eine Grafik: „Bühne mit einer Person darauf, Publikum
   davor". Im Fallback ist das die flache Linienzeichnung; im Journey-Modus
   übernimmt die 3D-Bühne, deshalb ist die Regel ausdrücklich auf
   NICHT-Journey beschränkt.
   `.zone::before` trägt den Text-Scrim, `::after` ist frei. */
html:not(.mode-journey) .zone--dayone::after {
  content: "";
  display: block;
  width: min(100%, 520px);
  margin: clamp(26px, 4vh, 44px) auto 0;
  aspect-ratio: 1200 / 520;
  background: url("./assets/dayone-venue.svg") center / contain no-repeat;
}

/* Runde 9 (AP 2): „Mehr Details" war zu versteckt. Rahmen UND Schrift stehen
   jetzt in Polaris, gefüllt wird weiterhin erst beim Hover — der Button
   verspricht damit dieselbe Farbe, die er beim Anfassen einlöst.
   Der alte Rand stand auf --lichtlinie (10 % Deckkraft): auf dem Nachthimmel
   rund 1,3:1, während WCAG 1.4.11 für Bedienelement-Begrenzungen 3:1 fordert.
   Die 62 % sind der benannte Regler (62 % ↔ 100 %); gemessen an den vier
   realen CTA-Positionen liegt der Rand damit bei 5,45…6,28:1 — siehe README. */
.cta {
  display: inline-block;
  padding: 12px 22px;
  background: none;
  color: var(--polaris);
  border: 1px solid color-mix(in oklab, var(--polaris) 62%, transparent);
  border-radius: 2px;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    color var(--t-instrument) var(--e-house),
    background var(--t-instrument) var(--e-house),
    border-color var(--t-instrument) var(--e-house);
}
.cta:hover {
  background: var(--polaris);
  color: var(--tinte);
  border-color: var(--polaris);
}
/* Der globale Fokusring ist selbst Polaris — auf einem lime umrandeten Button
   ein Doppelrahmen, der als Rückmeldung nicht mehr taugt. Mint ist hier die
   einzige Farbe, die weder mit dem Rand noch mit der Füllung verschmilzt. */
.cta:focus-visible,
.cta--primary:focus-visible {
  outline-color: var(--aurora-557);
}

/* Runde 7 (AP 6): der Primär-CTA in den Overlays. Voll deckend, große
   Hitarea — der 0.5-Opacity-Ghost von `.cta--dummy` taugte nicht für
   „präsent", und deaktiviert war er ohnehin die falsche Antwort. */
.cta--primary {
  padding: 15px 34px;
  background: var(--polaris);
  color: var(--tinte);
  border-color: var(--polaris);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
}
.cta--primary:hover {
  background: color-mix(in oklab, var(--polaris) 86%, var(--sternenlicht));
  border-color: color-mix(in oklab, var(--polaris) 86%, var(--sternenlicht));
}

/* Beteiligungs-Labels (Kap. 6, Akt 2) */
.holdings {
  position: relative;
  width: 100vw;
  left: 50%;
  transform: translateX(-50%);
  padding: 0 clamp(14px, 2vw, 40px);
  margin-top: 44px;
}
.holdings__label {
  margin: 0 0 14px;
  color: var(--aurora-557);
  letter-spacing: 0.24em;
}
/* Runde 20: Beteiligungen als eine echte, volle Registerzeile vom linken
   bis zum rechten Rand. Die Typo darf grösser werden, weil die volle
   Viewport-Breite genutzt wird. */
.holdings__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-between;
  gap: clamp(6px, 0.65vw, 11px);
  align-items: center;
  width: 100%;
  max-width: none;
}
.holdings__list li {
  color: var(--mondgrau);
  letter-spacing: 0.04em;
  font-size: clamp(8px, 0.8vw, 13px);
  white-space: nowrap;
}

.holdings__list--dup {
  display: none;
}

@media (max-width: 640px) {
  /* Mobile: automatisches Laufband statt Wischen */
  .holdings {
    overflow: hidden;
  }
  .holdings__track {
    display: flex;
    width: max-content;
    animation: holdings-marquee 38s linear infinite;
    will-change: transform;
  }
  .holdings__list,
  .holdings__list--dup {
    display: flex;
    width: auto;
    justify-content: flex-start;
    gap: clamp(14px, 4.5vw, 22px);
    padding-right: clamp(14px, 4.5vw, 22px);
  }
  .holdings__list li {
    font-size: clamp(9px, 3vw, 12px);
  }
}

@keyframes holdings-marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .holdings__track {
    animation: none;
  }
}

/* Stations-Marker (nur Journey-Modus) */
.marker {
  display: none;
}

/* Kontaktsektion (Kap. 6, Akt 6). Runde 9: kein Lichtbruch mehr, auch nicht
   im CSS-Fallback — dort sah der Kunde denselben „Abschuss". Keine Fläche,
   keine Tinte; die Sektion läuft im normalen dunklen Design weiter.
   Der Scrim ist hier PFLICHT, nicht Kosmetik: --mondgrau auf --daemmerung
   sind 3,816:1 und damit unter AA. `contrast.mjs` misst den Fallback nicht,
   fängt das also nicht — der Wert ist von Hand gerechnet. */
.light {
  position: relative;
  z-index: 6;
  background: none;
  color: var(--sternenlicht);
  padding: clamp(72px, 14vh, 168px) clamp(20px, 6vw, 96px);
  border-top: 0;
}
/* NICHT `var(--scrim)`: das ist eine mittige Ellipse, die bei 72 % Radius
   auslaufen soll. Sie sitzt richtig hinter einer 640-px-Zone, aber `.light`
   ist im Fallback ein Vollbreiten-Band mit linksbündigem Text — dort ist die
   Ellipse an der Textkante längst durchsichtig. Gemessen: 3,87:1 bei 1023 px
   und 3,14:1 bei 640 px, also unter AA. Ein Verlauf über die Bandhöhe ist
   breitenunabhängig und braucht keine Nachjustage je Viewport. Er liest als
   „die Nacht wird zum Seitenfuß hin tiefer", nicht als Panel — die weiße
   Fläche war genau das, was der Kunde nicht mehr wollte. */
/* Runde 16: auch hier keine getoente Flaeche mehr — der Farbverlauf traegt. */
.light::before {
  content: "";
  position: absolute;
  inset: 0;
  background: none;
  z-index: -1;
  pointer-events: none;
}

.light__inner {
  max-width: 1280px;
  margin: 0 auto;
}
.light .eyebrow {
  color: var(--aurora-557);
}
.light__lead {
  margin: 0 0 34px;
  color: var(--mondgrau);
  font-size: 18px;
}
.light__addr {
  margin: 0 0 10px;
  font-style: normal;
  color: var(--mondgrau);
  letter-spacing: 0.13em;
  font-size: 10.5px;
}
.light__mail {
  margin: 0 0 30px;
  letter-spacing: 0.13em;
  font-size: 10.5px;
}
.light__mail a {
  color: var(--sternenlicht);
  text-decoration: none;
  border-bottom: 1px solid var(--lichtlinie);
  padding-bottom: 2px;
  transition: border-color var(--t-instrument) var(--e-house);
}
/* Auf der alten Off-White-Fläche war dieser Hover 1,049:1 — praktisch
   unsichtbar. Auf dunklem Grund trägt dieselbe Regel 7,5:1. */
.light__mail a:hover {
  border-color: var(--polaris);
}
.light__social {
  margin: 0 0 24px;
  letter-spacing: 0.13em;
  font-size: 10.5px;
  color: var(--mondgrau);
}
.light__social a {
  color: var(--polaris);
  text-decoration: none;
  border-bottom: 1px solid var(--lichtlinie);
  padding-bottom: 2px;
  transition: border-color var(--t-instrument) var(--e-house);
}

.light__social a:hover {
  border-color: var(--polaris);
}
.light__sep {
  margin: 0 10px;
  color: var(--mondgrau);
}
.light__foot {
  margin: 0;
  padding-top: 22px;
  border-top: 1px solid var(--lichtlinie);
  color: color-mix(in oklab, var(--mondgrau) 76%, transparent);
  letter-spacing: 0.13em;
  font-size: 10px;
}
/* Weißer Punkt hinter der Kontakt-Headline */
.light h2.serif::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--sternenlicht);
  margin-left: 8px;
  vertical-align: baseline;
}

/* -------------------------------------------------------------------------
   7 — JOURNEY-MODUS (three.js läuft): Scroll-Track + fixierte Textzonen
   ------------------------------------------------------------------------- */
html.mode-journey .act {
  padding: 0;
  min-height: 0;
  display: block;
}
/* Runde 10 (S4): war 120vh. Akt 0 hatte damit die längste Anfahrt der Seite,
   ohne in ihr etwas zu zeigen — die früheste sichtbare Kante lag bei 678 px.
   70vh drückt die Gesamthöhe auf 750 vh. */
html.mode-journey .act--0 {
  height: 70vh;
}
html.mode-journey .act--1,
html.mode-journey .act--2,
html.mode-journey .act--3,
html.mode-journey .act--4 {
  height: 96vh;
}
html.mode-journey .act--5 {
  height: 152vh;
}
html.mode-journey .act--6 {
  height: 144vh;
}
/* Summe = 750 vh (Kap. 7, Runde 10 · vorher 800 vh).

   Kein p-Fenster hängt an diesen Höhen: `html.mode-journey .act__inner` ist
   `position: fixed`, alle Aktinhalte hängen an `p`, die Sektionen sind reine
   Abstandshalter. Die Aktfenster bleiben 0 / 15 / 27 / 39 / 51 / 63 / 82 /
   100 %; nur die physische Strecke wird um 7,14 % dichter (50/700).

   ACHTUNG: Hier stand bis Runde 10 die Gleichung „Sektionsgrenze =
   Aktgrenze". Sie war nie wörtlich wahr, aber bis Runde 10 wenigstens
   PROPORTIONAL: `p` normalisiert über die Scrollstrecke (Summe − 100 vh),
   die Sektionen liegen auf der vollen Summe, das Verhältnis war für JEDEN
   Akt exakt 800/700 = 1,143 — jede Sektionsgrenze lag um denselben Faktor
   HINTER ihrer Aktgrenze.

   S4 hat genau diese Proportionalität gebrochen, weil es nur Akt 0 kürzt.
   Gemessen in vh (Sektionsgrenze / Aktgrenze / Faktor):

     Akt 0:  70,0 / 97,5 / 0,718   ← Sektion endet VOR dem Akt
     Akt 1: 166,0 / 175,5 / 0,946  ← ebenfalls davor
     Akt 2: 262,0 / 253,5 / 1,034
     Akt 3: 358,0 / 331,5 / 1,080
     Akt 4: 454,0 / 409,5 / 1,109
     Akt 5: 606,0 / 533,0 / 1,137
     Akt 6: 750,0 / 650,0 / 1,154

   Für die Darstellung ist das folgenlos (alles ist fixed), für jede Rechnung
   auf diesen Höhen nicht: Wer aus Sektionshöhen auf p schließt, liegt jetzt
   je Akt unterschiedlich daneben, und bei Akt 0 in der anderen Richtung als
   bei Akt 6. Wer die Proportionalität zurückwill, muss alle sieben Höhen
   gemeinsam skalieren, nicht eine. */

html.mode-journey .act__inner {
  position: fixed;
  inset: 0;
  z-index: 5;
  max-width: none;
  margin: 0;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  will-change: opacity;
}
html.mode-journey .act__inner.is-live {
  visibility: visible;
}
/* Nur echte Bedienelemente fangen Klicks — der Scrim nie (Kap. 9). */
html.mode-journey .act__inner.is-live .zone button,
html.mode-journey .act__inner.is-live .zone a,
html.mode-journey .act__inner.is-live .marker {
  pointer-events: auto;
}

html.mode-journey .zone {
  position: absolute;
  max-width: none;
  width: min(520px, 42vw);
}
/* Space Grotesk Bold läuft breiter als der frühere Serif-Schnitt. Im
   Journey-Layout sitzen die Zonen in min(520px, 42vw) — dort trägt 600
   die Headline, ohne dass sie in eine dritte Zeile umbricht. */
html.mode-journey h2.serif {
  font-size: clamp(29px, 2.9vw, 43px);
  font-weight: 600;
}
html.mode-journey .zone--statement h2.serif {
  font-size: clamp(31px, 3.9vw, 58px);
  font-weight: 600;
}
html.mode-journey .zone--center {
  left: 50%;
  transform: translateX(-50%);
  bottom: clamp(72px, 14vh, 150px);
  width: min(760px, 84vw);
  text-align: center;
}
html.mode-journey .zone--right {
  right: clamp(24px, 6vw, 92px);
  top: 50%;
  transform: translateY(-50%);
  text-align: left;
  margin: 0;
}
html.mode-journey .zone--left {
  left: clamp(24px, 6vw, 92px);
  top: 50%;
  transform: translateY(-50%);
  text-align: left;
  margin: 0;
}
html.mode-journey .zone--statement {
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(820px, 86vw);
  text-align: center;
}
html.mode-journey .zone--dayone {
  left: 50%;
  transform: translateX(-50%);
  bottom: clamp(80px, 16vh, 170px);
  width: min(640px, 84vw);
  text-align: center;
}
/* AP 5c (Runde 9): Die Day-One-Bühne steht im rechten Bilddrittel. Bei
   schmaleren Seitenverhältnissen wächst ihre Projektion nach links und
   erreicht die zentrierte Typo. Diese Regel ist deshalb VORAUSSETZUNG,
   nicht Option (R3): sie schiebt den Textblock nach links, damit Bühne und
   Typo klar getrennt bleiben. Bei 1512×982 (Seitenverhältnis 1,540) greift
   sie nicht — die kanonische Komposition ist unangetastet. */
@media (max-aspect-ratio: 29/20) {
  html.mode-journey .zone--dayone {
    left: clamp(24px, 6vw, 92px);
    transform: none;
    width: min(460px, 46vw);
    text-align: left;
  }
  html.mode-journey .zone--dayone .proof {
    margin-inline: 0;
  }
  html.mode-journey .zone--dayone .dayone__marker {
    justify-content: flex-start;
  }
}
html.mode-journey .zone--center .lead,
html.mode-journey .zone--center .proof,
html.mode-journey .zone--dayone .proof,
html.mode-journey .zone--statement .statement__sub {
  margin-inline: auto;
}
/* Hero: Die Instrumenten-Zeile löst sich knapp von der Horizontkante,
   ohne die abgenommene Typo-Komposition zu verschieben. */
html.mode-journey .act--0 .eyebrow {
  position: relative;
  top: 12px;
}

/* Beteiligungs-Namen frei im Raum an den Lichtpunkten (Kap. 6, Akt 2) */
html.mode-journey .holdings {
  position: fixed;
  inset: 0;
  margin: 0;
  pointer-events: none !important;
}
html.mode-journey .holdings__label {
  position: absolute;
  left: clamp(24px, 6vw, 92px);
  bottom: clamp(56px, 8vh, 82px);
  margin: 0;
}
html.mode-journey .holdings__list {
  position: absolute;
  left: clamp(24px, 6vw, 92px);
  right: clamp(24px, 6vw, 92px);
  bottom: clamp(26px, 5vh, 52px);
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-between;
  gap: clamp(7px, 0.75vw, 12px);
  align-items: center;
  width: auto;
  max-width: none;
}
html.mode-journey .holdings__list li {
  position: static;
  transform: none !important;
  white-space: nowrap;
  color: var(--sternenlicht);
  font-size: clamp(8px, 0.72vw, 11px);
  letter-spacing: 0.06em;
  text-shadow:
    0 0 14px rgba(7, 10, 20, 0.9),
    0 0 4px rgba(7, 10, 20, 0.9);
  opacity: 0;
  will-change: transform, opacity;
}
html.mode-journey .holdings__list li::before {
  content: "";
  position: absolute;
  left: -8px;
  top: 50%;
  width: 3px;
  height: 3px;
  margin-top: -1.5px;
  border-radius: 50%;
  background: var(--aurora-557);
  box-shadow: 0 0 8px 1px color-mix(in oklab, var(--aurora-557) 70%, transparent);
}

/* Stationen klickbar — echte Buttons, pro Frame aus 3D-Ankern projiziert */
html.mode-journey .marker {
  display: block;
  position: fixed;
  left: 0;
  top: 0;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  opacity: 0;
  will-change: transform, opacity;
}
.marker__ring {
  display: block;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid color-mix(in oklab, var(--aurora-557) 60%, transparent);
  position: relative;
  transition:
    transform var(--t-instrument) var(--e-house),
    border-color var(--t-instrument) var(--e-house);
}
.marker__ring::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--aurora-557);
  box-shadow: 0 0 12px 2px color-mix(in oklab, var(--aurora-557) 60%, transparent);
  transition: background var(--t-instrument) var(--e-house);
}
.marker__label {
  position: absolute;
  left: 46px;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  color: var(--sternenlicht);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-shadow: 0 0 16px rgba(7, 10, 20, 0.95);
}
.marker:hover .marker__ring,
.marker:focus-visible .marker__ring {
  transform: scale(1.18);
  border-color: var(--polaris);
}
.marker:hover .marker__ring::after,
.marker:focus-visible .marker__ring::after {
  background: var(--polaris);
}

/* Runde 9 (AP 1): Der Kontakt im Journey-Modus ist keine Fläche mehr.
   Bis Runde 8 wischte hier ein weißes Panel über die ganze Szene nach oben —
   der Kunde las das als Abschluss („da kommt ja wie so'n Abschuss noch mal.
   Und dann scrollt man vielleicht gar nicht mehr weiter"). Die Szene läuft
   jetzt weiter; der Kontakt ist ein normaler Textblock in der Geometrie von
   `.zone--right`, mit demselben Scrim wie jede andere Zone.

   Er bleibt trotzdem `position: fixed` und Geschwister von `.act__inner` —
   NICHT als achte `.zone`: die teilte sich die Opazität mit Day One
   (`textOpacity(p, 6)` ist bei p = 0.888 schon auf 0), und ein achtes
   `.act__inner` bräche die Index↔Akt-Kopplung in main.js. */
html.mode-journey .light {
  position: fixed;
  inset: auto;
  right: clamp(24px, 6vw, 92px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 20;
  width: min(520px, 42vw);
  padding: 0;
  background: none;
  color: var(--sternenlicht);
  border-top: 0;
  box-shadow: none;
  opacity: 0;
  /* Die Fläche darf keine Klicks mehr schlucken. Als opakes Panel war
     `auto` auf der ganzen Fläche richtig; als transparente Ebene über der
     laufenden Szene wäre es ein unsichtbarer Deckel über Nav und Marker.
     `auto` steht deshalb weiter unten NUR auf den echten Bedienelementen —
     und nur im geöffneten Zustand, sonst wäre der unsichtbare Mail-Link
     schon vor der Einblendung anklickbar. */
  pointer-events: none;
}
/* Derselbe Scrim wie `.zone::before` — ohne ihn steht heller Text direkt auf
   der Szene. Bei `.zone` ist er ein z-index-negatives ::before; `.light` hat
   sein ::before frei. */
html.mode-journey .light::before {
  content: "";
  position: absolute;
  inset: -14% -12%;
  background: var(--scrim);
  z-index: -1;
  pointer-events: none;
}
html.mode-journey .light.is-open a,
html.mode-journey .light.is-open button {
  pointer-events: auto;
}

/* Einspaltig — das zweispaltige Editorial-Raster aus Runde 7 gehörte zur
   Vollfläche und hat in 42 vw keinen Platz. */
html.mode-journey .light__inner {
  width: 100%;
  max-width: none;
  display: block;
  padding-block: 0;
  border-top: 0;
  border-bottom: 0;
}
/* Farben kommen jetzt vollständig aus dem Basisblock oben — hier steht nur
   noch, was sich in 42 vw wirklich unterscheidet: der Typoschnitt der
   Zonen (`html.mode-journey h2.serif`) und die Zeilenlänge. */
html.mode-journey .light h2.serif {
  margin-bottom: 20px;
}
html.mode-journey .light__lead {
  font-size: clamp(15px, 1.4vw, 18px);
  max-width: 34ch;
  margin-bottom: 26px;
}
html.mode-journey .light__mail {
  margin-bottom: 26px;
}
html.mode-journey .light__foot {
  padding-top: 20px;
}

/* -------------------------------------------------------------------------
   8 — OVERLAYS (Kap. 10)
   ------------------------------------------------------------------------- */
.ov {
  border: 0;
  padding: 0;
  margin: auto; /* zentriert wie im UA-Default */
  width: min(720px, 92vw);
  max-width: none;
  max-height: 86vh;
  background: color-mix(in oklab, var(--polarnacht) 92%, var(--zenit));
  color: var(--sternenlicht);
  border-radius: 3px;
  box-shadow:
    0 40px 120px rgba(0, 0, 0, 0.6),
    0 0 0 1px var(--lichtlinie);
  overflow: hidden;
}
.ov::backdrop {
  background: rgba(4, 6, 12, 0.74);
  backdrop-filter: blur(6px);
}
.ov[open] {
  animation: ovIn 520ms var(--e-house) both;
}
@keyframes ovIn {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.ov__box {
  padding: clamp(26px, 4vw, 52px);
  max-height: 86vh;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior-x: none;
  overflow-anchor: none;
  scrollbar-gutter: stable;
}
.ov__box > p {
  text-align: justify;
  text-align-last: left;
  hyphens: auto;
  -webkit-hyphens: auto;
  word-spacing: -0.02em;
  color: var(--mondgrau);
  font-size: 15.5px;
}
.ov__box > p.eyebrow {
  color: var(--aurora-557);
  text-align: left;
}
.ov__box > p.dayone__meta {
  text-align: left;
}
.ov__box > p b {
  color: var(--sternenlicht);
  font-weight: 500;
}
.ov h2.serif {
  font-size: clamp(27px, 3.2vw, 41px);
  font-weight: 600;
  margin-bottom: 24px;
}

.ov__x {
  float: right;
  margin: -6px -6px 0 16px;
  background: none;
  border: 1px solid var(--lichtlinie);
  border-radius: 2px;
  padding: 7px 12px;
  cursor: pointer;
  color: var(--mondgrau);
  font: 500 9.5px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition:
    color var(--t-instrument) var(--e-house),
    border-color var(--t-instrument) var(--e-house);
}
.ov__x:hover {
  color: var(--sternenlicht);
  border-color: var(--aurora-557);
}

/* --- Runde 7 (AP 6): Aktionsblock direkt unter der Headline ------------- */
.ov__action {
  margin: 0 0 30px;
  padding: 24px 0 26px;
  border-top: 1px solid var(--lichtlinie);
  border-bottom: 1px solid var(--lichtlinie);
  text-align: center;
}
.ov__actionhint {
  margin: 14px 0 0;
  color: color-mix(in oklab, var(--mondgrau) 72%, transparent);
  letter-spacing: 0.14em;
  text-transform: none;
}
.ov__mock {
  margin: 22px auto 0;
  max-width: 460px;
  text-align: left;
  display: grid;
  gap: 12px;
}
.ov__mock[hidden] {
  display: none;
}
.ov__field {
  display: grid;
  gap: 6px;
}
.ov__fieldlabel {
  color: var(--aurora-557);
  letter-spacing: 0.2em;
  font-size: 9.5px;
}
.ov__input {
  display: block;
  height: 38px;
  width: 100%;
  border: 1px solid var(--lichtlinie);
  border-radius: 999px;
  background: color-mix(in oklab, var(--sternenlicht) 4%, transparent);
  padding: 0 18px;
  color: var(--sternenlicht);
  font: inherit;
  font-size: 14px;
  outline: none;
  transition: border-color 0.2s ease;
}
.ov__input:focus-visible {
  border-color: var(--polarlicht, #d8f300);
}
.ov__drop {
  display: flex;
  align-items: center;
  min-height: 62px;
  width: 100%;
  padding: 0 20px;
  border-radius: 14px;
  text-align: left;
  border: 1px dashed color-mix(in oklab, var(--sternenlicht) 16%, transparent);
  background: color-mix(in oklab, var(--sternenlicht) 4%, transparent);
  color: color-mix(in oklab, var(--mondgrau) 80%, transparent);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.ov__drop:hover {
  border-color: color-mix(in oklab, var(--sternenlicht) 32%, transparent);
}
.ov__mockfoot {
  margin: 4px 0 0;
  text-align: center;
  color: color-mix(in oklab, var(--mondgrau) 58%, transparent);
  letter-spacing: 0.12em;
  text-transform: none;
}

.ov__stat {
  display: flex;
  align-items: baseline;
  gap: 34px;
  margin: 18px 0 26px;
  flex-wrap: wrap;
}
.ov__stat > span {
  display: flex;
  align-items: baseline;
  gap: 12px;
}
.ov__stat .serif {
  font-size: 52px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--sternenlicht);
}
.ov__stat .mono {
  color: var(--aurora-557);
  letter-spacing: 0.22em;
}

.ov__pillars {
  list-style: none;
  margin: 30px 0;
  padding: 0;
  display: grid;
  gap: 22px 34px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.ov__pillars h3 {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.ov__pillars p {
  margin: 0;
  color: var(--mondgrau);
  font-size: 14px;
  line-height: 1.55;
}
.ov__pillars li {
  border-top: 1px solid var(--lichtlinie);
  padding-top: 14px;
}

.ov__pathlabel {
  margin: 28px 0 10px;
  color: var(--aurora-557);
  letter-spacing: 0.24em;
}
.ov__path {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  color: var(--mondgrau);
}
.ov__path li {
  position: relative;
  padding-left: 14px;
  letter-spacing: 0.14em;
}
.ov__path li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--aurora-557);
}
.ov__holdings {
  margin: 0 0 8px;
  color: var(--mondgrau);
  letter-spacing: 0.16em;
  line-height: 2;
}
.ov__hint {
  margin: 22px 0 6px;
  color: var(--aurora-557);
  letter-spacing: 0.22em;
}
.ov__details {
  margin: 0 0 26px;
  color: var(--mondgrau);
  font-size: 14px;
}
.ov__dummy {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin: 0;
}
.ov__dummy .mono {
  color: color-mix(in oklab, var(--mondgrau) 60%, transparent);
  letter-spacing: 0.12em;
  text-transform: none;
}

/* -------------------------------------------------------------------------
   9 — CURSOR + STATS
   ------------------------------------------------------------------------- */
/* Runde 10 (S5): Der Kunde sah ZWEI Zeiger — einen leeren 26-px-Ring, dessen
   `<i>` erst über Bedienelementen zum 6-px-Kern wuchs, UND den nativen
   Systemzeiger, weil `cursor: none` im ganzen Klickdummy nirgends stand.
   Aufgelöst wie auf der Live-Site (src/components/effects/CustomCursor.tsx):
   ein gefüllter 10-px-Polaris-Punkt mit Glow, über Bedienelementen 20 px.
   Der Ring ist ersatzlos weg, `<i>` wird nicht mehr gebraucht.

   ABWEICHUNG VOM PLAN, bewusst: der Plan schrieb `html.js`, hier steht
   `html.js.mode-journey`. Grund ist gemessen, nicht gemutmaßt — der Punkt
   wird ausschließlich in der Journey-Renderschleife bewegt
   (`el.cursor.style.transform`, main.js, direkt vor `renderer.render`). Im
   CSS-Fallback läuft diese Schleife nicht. Mit `html.js` bliebe dort ein
   eingefrorener Punkt stehen, WÄHREND der Systemzeiger versteckt ist — das
   wäre schlimmer als der Zustand, den S5 repariert. Im Fallback bleibt
   deshalb der Systemzeiger, und der Punkt ist unsichtbar. */
.cursor {
  display: none;
}
@media (pointer: fine) {
  html.js.mode-journey .cursor {
    display: block;
    position: fixed;
    left: 0;
    top: 0;
    z-index: 60;
    width: 10px;
    height: 10px;
    margin: -5px 0 0 -5px;
    border: 0;
    border-radius: 50%;
    background: var(--polaris);
    box-shadow: 0 0 12px 2px color-mix(in oklab, var(--polaris) 55%, transparent);
    pointer-events: none;
    transition:
      width var(--t-instrument) var(--e-house),
      height var(--t-instrument) var(--e-house),
      margin var(--t-instrument) var(--e-house),
      box-shadow var(--t-instrument) var(--e-house);
  }
  /* Der frühere Kern IST jetzt der Punkt. */
  html.js.mode-journey .cursor i {
    display: none;
  }
  html.js.mode-journey .cursor.is-hot {
    width: 20px;
    height: 20px;
    margin: -10px 0 0 -10px;
    box-shadow: 0 0 28px 8px color-mix(in oklab, var(--polaris) 65%, transparent);
  }

  /* R6 — der Licht-Regler wird im Termin bedient; ohne Zeiger ist
     Feinjustierung am Slider unangenehm.
     Zwei Teile, beide nötig. `:not(.licht, .licht *)` nimmt den Teilbaum von
     der Regel aus, statt ihn nachträglich zurückzusetzen — so bleiben die
     bestehenden Deklarationen dort gültig (`.licht__regler` `pointer`,
     `:disabled` `not-allowed`), ohne hier dupliziert und beim nächsten
     Panel-Umbau vergessen zu werden. Das allein genügt aber NICHT: `cursor`
     ist eine vererbte Eigenschaft, das Panel erbt `none` vom Body, auch wenn
     keine Regel es trifft (gemessen: `getComputedStyle(.licht).cursor` war
     `none`). Deshalb setzt die zweite Zeile den Teilbaumanfang aktiv auf
     `auto`; alles darin erbt von dort. */
  /* Der Ersatzpunkt wird vor showModal() in den aktiven Dialog verschoben,
     damit er zusammen mit diesem im Top Layer liegt und auch im Overlay
     sichtbar ist. Der native Zeiger bleibt überall ausgeschaltet. */
  html.js.mode-journey,
  html.js.mode-journey *:not(.licht, .licht *) {
    cursor: none;
  }
  html.js.mode-journey .licht {
    cursor: auto;
  }

  /* Nicht animierte Fassung: dort läuft keine Journey-Renderschleife, der
     Punkt wird von zeiger.js bewegt (setzt `html.hat-zeiger`). Gleiche Optik,
     gleiche Ausnahmen wie oben — Licht-Panel und modale Dialoge behalten den
     Systemzeiger. */
  html.js.hat-zeiger:not(.mode-journey) .cursor {
    display: block;
    position: fixed;
    left: 0;
    top: 0;
    z-index: 60;
    width: 10px;
    height: 10px;
    margin: -5px 0 0 -5px;
    border: 0;
    border-radius: 50%;
    background: var(--polaris);
    box-shadow: 0 0 12px 2px color-mix(in oklab, var(--polaris) 55%, transparent);
    pointer-events: none;
    transform: translate3d(-40px, -40px, 0);
    transition:
      width var(--t-instrument) var(--e-house),
      height var(--t-instrument) var(--e-house),
      margin var(--t-instrument) var(--e-house),
      box-shadow var(--t-instrument) var(--e-house);
  }
  html.js.hat-zeiger:not(.mode-journey) .cursor i {
    display: none;
  }
  html.js.hat-zeiger:not(.mode-journey) .cursor.is-hot {
    width: 20px;
    height: 20px;
    margin: -10px 0 0 -10px;
    box-shadow: 0 0 28px 8px color-mix(in oklab, var(--polaris) 65%, transparent);
  }
  html.js.hat-zeiger:not(.mode-journey),
  html.js.hat-zeiger:not(.mode-journey) *:not(.licht, .licht *) {
    cursor: none;
  }
  html.js.hat-zeiger:not(.mode-journey) .licht {
    cursor: auto;
  }

  /* Markieren muss möglich bleiben: über Fließtext bekommt der Nutzer den
     nativen Textzeiger zurück (Kundenrückmeldung 28.08.). Der Polaris-Punkt
     wird zeitgleich per Skript ausgeblendet (zeiger.js / main.js, Listener
     auf `mouseover`), damit nicht zwei Zeiger nebeneinander stehen.
     `!important`, weil die Decke-Regel oben sonst höher spezifisch ist.
     Buttons/Links ausgenommen — dort bleibt der Punkt als Klick-Signal. */
  html.js.mode-journey
    :is(p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th, dd, dt, figcaption, small):not(
      button, a, button *, a *, .licht, .licht *
    ),
  html.js.hat-zeiger:not(.mode-journey)
    :is(p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th, dd, dt, figcaption, small):not(
      button, a, button *, a *, .licht, .licht *
    ),
  /* Kind-Elemente (z. B. .proof__line-Spans) erben nicht — die Decke-Regel
     setzt `none` auf JEDES Element, also hier explizit mitnehmen. */
  html.js.mode-journey
    :is(p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th, dd, dt, figcaption, small)
    :not(button, a, button *, a *, .licht, .licht *),
  html.js.hat-zeiger:not(.mode-journey)
    :is(p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th, dd, dt, figcaption, small)
    :not(button, a, button *, a *, .licht, .licht *) {
    cursor: text !important;
  }
}

.stats {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 70;
  padding: 10px 12px;
  border-radius: 2px;
  background: rgba(7, 10, 20, 0.82);
  border: 1px solid var(--lichtlinie);
  color: var(--mondgrau);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: none;
  line-height: 1.7;
  white-space: pre;
  pointer-events: none;
}
.stats b {
  color: var(--aurora-557);
  font-weight: 500;
}
.stats .bad {
  color: var(--warnung);
}

/* -------------------------------------------------------------------------
   9b — LICHT-REGLER (Entscheidungswerkzeug, KEIN Feature)

   Dieser Abschnitt, `licht.js` und der Markup-Block am Ende von index.html
   gehören zusammen und werden nach der Helligkeits-Freigabe gemeinsam wieder
   entfernt. Nichts hier vererbt in den Rest des Stylesheets.

   Sitzt bewusst LINKS unten: `.stats` (?stats) belegt die rechte Ecke, und
   beide Werkzeuge müssen gleichzeitig lesbar bleiben. Die eigenen Farben sind
   hartkodiert statt über die Himmels-Tokens gezogen — ein Panel, das sich mit
   dem Regler selbst verdunkelt, wäre am Skalenende nicht mehr bedienbar.
   ------------------------------------------------------------------------- */
.licht {
  position: fixed;
  left: 12px;
  bottom: 12px;
  z-index: 71;
  width: 268px;
  max-height: calc(100vh - 24px);
  overflow-y: auto;
  padding: 12px 14px 14px;
  border-radius: 3px;
  background: rgba(7, 10, 20, 0.93);
  border: 1px solid rgba(247, 255, 253, 0.14);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.5);
  color: #adb9c8;
  font-family: var(--font-sans);
}
.licht[hidden] {
  display: none;
}

.licht__kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.licht__kopf .mono {
  color: var(--aurora-557);
  font-size: 10px;
}
.licht__zu {
  background: none;
  border: 0;
  padding: 2px 4px;
  cursor: pointer;
  color: #7f8ea0;
  font-size: 13px;
  line-height: 1;
}
.licht__zu:hover {
  color: #f7fffd;
}

.licht__zeile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 10px 0 4px;
}
.licht__zeile--master {
  margin-top: 0;
}
.licht__name {
  font-size: 9.5px;
  color: #8e9dae;
}
.licht__wert {
  font-size: 10.5px;
  color: #f7fffd;
  font-variant-numeric: tabular-nums;
}
/* Ein Kanal, der vom Master abweicht, muss sofort sichtbar sein — sonst
   erklärt sich ein Bild nicht mehr aus der Master-Zahl allein. */
.licht__feld.is-abweichend .licht__wert {
  color: var(--polaris);
}
.licht__feld.is-inaktiv {
  opacity: 0.42;
}

.licht__regler {
  width: 100%;
  margin: 0;
  display: block;
  accent-color: var(--aurora-557);
  cursor: pointer;
}
.licht__regler:disabled {
  cursor: not-allowed;
}

.licht__enden {
  display: flex;
  justify-content: space-between;
  margin-top: 2px;
  font-size: 8.5px;
  color: #67788a;
}

.licht__presets {
  display: flex;
  gap: 6px;
  margin-top: 12px;
}
.licht__presets button {
  flex: 1 1 0;
  padding: 6px 4px;
  cursor: pointer;
  background: none;
  border: 1px solid rgba(247, 255, 253, 0.14);
  border-radius: 2px;
  font: 500 9px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #8e9dae;
}
.licht__presets button:hover {
  color: #f7fffd;
  border-color: var(--aurora-557);
}
.licht__presets button[aria-pressed="true"] {
  color: var(--zenit);
  background: var(--aurora-557);
  border-color: var(--aurora-557);
}

.licht__expert {
  margin-top: 14px;
  border-top: 1px solid rgba(247, 255, 253, 0.1);
  padding-top: 10px;
}
.licht__expert > summary {
  cursor: pointer;
  font-size: 9px;
  color: #8e9dae;
  list-style: revert;
}
.licht__expert > summary:hover {
  color: #f7fffd;
}
.licht__abw {
  color: var(--polaris);
  font-size: 11px;
}

.licht__hinweis {
  margin: 12px 0 0;
  font-size: 9.5px;
  line-height: 1.55;
  color: #67788a;
}
.licht__hinweis em {
  font-style: normal;
  color: #8e9dae;
}

.licht__reset {
  margin-top: 10px;
  width: 100%;
  padding: 6px;
  cursor: pointer;
  background: none;
  border: 1px solid rgba(247, 255, 253, 0.14);
  border-radius: 2px;
  font: 500 9px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #8e9dae;
}
.licht__reset:hover {
  color: #f7fffd;
  border-color: var(--aurora-557);
}

.licht__fuss {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid rgba(247, 255, 253, 0.1);
}
/* Unter 4.5:1 ist die Helligkeit nicht freigabefähig — das muss im Termin
   auffallen, nicht erst beim Gegenmessen. */
.licht__wert.is-schlecht {
  color: var(--warnung);
}

.licht__kopie {
  margin-top: 10px;
  width: 100%;
  padding: 8px;
  cursor: pointer;
  background: none;
  border: 1px solid var(--aurora-557);
  border-radius: 2px;
  font: 500 9px/1 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--aurora-557);
}
.licht__kopie:hover {
  color: var(--zenit);
  background: var(--aurora-557);
}

.licht__export {
  margin-top: 8px;
  width: 100%;
  resize: vertical;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(247, 255, 253, 0.14);
  border-radius: 2px;
  padding: 8px;
  color: #adb9c8;
  font-size: 9.5px;
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
}

/* -------------------------------------------------------------------------
   10 — MOTION-MODI
   ------------------------------------------------------------------------- */
html.motion-off .band,
html.motion-off .sky__tail {
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .hero__particles,
  .hero__dot-pop {
    display: none;
  }
  .hero__logo {
    opacity: 1 !important;
    clip-path: none !important;
    animation: none !important;
  }
  .band,
  .sky__tail {
    animation: none !important;
  }
  .ov[open] {
    animation: none;
  }
  .hd__panel,
  .hd__burgerbox i,
  .hd::before {
    transition: none !important;
  }
}

/* -------------------------------------------------------------------------
   11 — KLEINE VIEWPORTS
   Mobile bleibt bewusst im Fallback (Kap. 11) — hier nur Typo-Anpassung.
   ------------------------------------------------------------------------- */
@media (min-width: 900px) and (max-width: 1380px) {
  .hd {
    flex-wrap: wrap;
    gap: 12px 18px;
    padding: 14px 18px;
  }
  .hd__nav {
    order: 3;
    flex-basis: 100%;
    overflow-x: auto;
    gap: 16px;
    padding-bottom: 2px;
  }
  .hd__inst {
    margin-left: auto;
  }
  .hd__tog {
    padding: 5px 8px;
  }
}
@media (max-width: 1380px) {
  html.mode-journey .marker__label {
    display: none;
  }
}

/* --- Burger-Menü unter 900px --- */
@media (max-width: 899px) {
  .hd {
    padding: 14px 16px;
    gap: 12px;
    justify-content: space-between;
  }

  .hd__mark {
    z-index: 2;
  }
  .hd__burger {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    margin-left: auto;
    background: color-mix(in oklab, var(--nachtblau, #070a14) 55%, transparent);
    border: 1px solid color-mix(in oklab, var(--mondgrau) 32%, transparent);
    border-radius: 3px;
    cursor: pointer;
    flex: 0 0 auto;
    z-index: 2;
  }
  .hd__burgerbox {
    display: grid;
    gap: 4px;
    width: 18px;
  }
  .hd__burgerbox i {
    display: block;
    height: 1.5px;
    width: 100%;
    background: var(--sternenlicht);
    transition:
      transform 0.22s ease,
      opacity 0.18s ease;
  }
  .hd__burger[aria-expanded="true"] .hd__burgerbox i:nth-child(1) {
    transform: translateY(5.5px) rotate(45deg);
  }
  .hd__burger[aria-expanded="true"] .hd__burgerbox i:nth-child(2) {
    opacity: 0;
  }
  .hd__burger[aria-expanded="true"] .hd__burgerbox i:nth-child(3) {
    transform: translateY(-5.5px) rotate(-45deg);
  }

  .hd__panel {
    display: block;
    position: fixed;
    inset: 0;
    padding: 90px 22px 32px;
    background: color-mix(in oklab, var(--nachtblau, #070a14) 94%, transparent);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    overflow-y: auto;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition:
      opacity 0.22s ease,
      transform 0.22s ease,
      visibility 0.22s;
    z-index: 1;
  }
  .hd.is-open .hd__panel {
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  .hd__nav {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .nav__l {
    font-size: 13px;
    padding: 15px 0;
    border-bottom: 1px solid color-mix(in oklab, var(--mondgrau) 16%, transparent);
  }
  .nav__l::after {
    display: none;
  }

  .hd__inst {
    margin: 26px 0 0;
    flex-wrap: wrap;
    gap: 12px;
  }
  .hd__coord {
    display: block;
    flex-basis: 100%;
  }
}

@media (max-width: 1023px) {
  .act--0 {
    padding-top: 210px;
  }
  .act {
    overflow-x: clip;
  }
  .act--2 {
    overflow-x: visible;
  }
  body {
    font-size: 16px;
  }
}

@media (max-width: 640px) {
  .hd {
    gap: 10px 12px;
    padding: 12px 14px;
  }
  .hd__mark {
    width: 94px;
  }
  .hd__inst {
    gap: 10px;
  }
  .hd__tog {
    padding: 6px 10px;
    font-size: 10px;
    gap: 6px;
  }

  .odo {
    font-size: clamp(56px, 22vw, 96px);
  }
  .ov__box {
    padding: 22px 18px;
  }
  .ov__pillars {
    grid-template-columns: 1fr;
  }
  .hero__brand {
    width: min(84vw, 460px);
  }
  /* Lockup-Achse: gleiche Breite wie die Wortmarke, damit der Subclaim
     auch mobil auf dem "g" beginnt. */
  .act--0 h1.serif {
    width: min(84vw, 460px);
    padding-left: calc(min(84vw, 460px) * 0.542);
    font-size: clamp(14px, 4.2vw, 21px);
  }
}

/* -------------------------------------------------------------------------
   12 — MOBILE BILDKOMPOSITION (Runde 15)
   Auf schmalen Viewports war die Skyline (Bandhoehe an der BREITE) optisch
   zu klein und der Horizont zu tief; gleichzeitig sass der Hero am unteren
   Rand, sodass oben eine grosse Leerflaeche stand. Beides wird hier auf die
   Desktop-Anmutung zurueckgeholt: Motiv naeher heran, Logo mittig.
   ------------------------------------------------------------------------- */
/* Runde 17: Tablet/Mobile nutzen eine kompakter komponierte Skyline-Datei.
   Die Gebaeude selbst werden nicht schmaler gezogen; stattdessen rueckt die
   Bruecke naeher an Rheinturm und Gehry-Bauten heran. So bleibt die
   Laptop-Breite der einzelnen Bauten erhalten, ohne seitlich Gebaeude
   abzuschneiden. */
@media (max-width: 899px) {
  :root {
    --horizon: 52%;
  }
  .sky__skyline {
    /* Tablet/Mobile: volle Breite, Hoehe breitenbasiert (Stand wie zuvor). */
    left: 0;
    right: 0;
    height: 38vw;
    aspect-ratio: auto;
    background: url("assets/skyline-nocturne-mobile.svg") bottom center / 100% 100% no-repeat;
  }
  .act--0 {
    align-items: flex-end;
    padding-top: clamp(120px, 18vh, 180px);
    padding-bottom: clamp(130px, 22vh, 220px);
  }
}
@media (max-width: 640px) {
  .sky__skyline {
    /* Phones: volle Breite. */
    left: 0;
    right: 0;
    height: 42vw;
    aspect-ratio: auto;
    background: url("assets/skyline-nocturne-mobile.svg") bottom center / 100% 100% no-repeat;
  }
}
