/* ═══════════════════════════════════════════════════════════════════
   Grundgestaltung
   1) Tokens  2) Basis  3) Raster  4) Header  5) Fußleiste  6) Hero
   7) Aussage  8) Projekte  9) Laufband  10) Footer  11) Bewegung
   ═══════════════════════════════════════════════════════════════════ */

/* ── 1) Tokens ───────────────────────────────────────────────────── */
:root {
  --bg:        #f7f6f1;
  --fg:        #0b0b0a;
  --muted:     #77746c;
  --line:      rgba(11, 11, 10, 0.14);
  --line-soft: rgba(11, 11, 10, 0.07);
  --grid:      rgba(11, 11, 10, 0.09);
  --hover-bg:  rgba(11, 11, 10, 0.04);
  --accent:    #1f9d55;
  /* Eine Signalfarbe für alles: das Grün des Headsets. Etiketten,
     Spur, Pointe und Schimmer ziehen am selben Strang. */
  --neon:      #4ade80;
  --neon-fg:   #0b0b0a;
  --headset-gruen: #4ade80;

  /* ── Die Farbreise ──────────────────────────────────────────────
     Die Seite wandert beim Scrollen durch vier Stimmungen, wie in der
     Vorlage: heller Himmel im Hero, ruhiges Creme bei den Projekten,
     tiefes Schwarz im Tunnel, zum Schluss wieder Blau.
     --warp-start ist als RGB-Tripel notiert, weil script.js daraus
     laufend Zwischentöne mischt.
     ──────────────────────────────────────────────────────────── */
  --himmel-oben:  #bcd9f7;
  --himmel-unten: #eaf3fd;
  --himmel-licht: rgba(255, 252, 236, 0.85);
  --creme:        #f7f6f1;
  --abend-oben:   #dbe9fa;
  --abend-unten:  #c2dbf6;
  --warp-start:   247, 246, 241;

  --font-sans: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "SFMono-Regular", "JetBrains Mono", "Consolas", "Courier New", monospace;

  --pad:  clamp(1.25rem, 3.4vw, 3.25rem);
  --bar:  3.25rem;        /* Höhe der festen Leisten oben und unten */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Dunkel ist der Normalfall der Seite — tiefer als die Vorlage,
   fast schwarz, damit das Grün darauf leuchten kann. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #070808;
    --fg:        #f2f1ea;
    --muted:     #8b877e;
    --line:      rgba(242, 241, 234, 0.16);
    --line-soft: rgba(242, 241, 234, 0.08);
    --grid:      rgba(242, 241, 234, 0.10);
    --hover-bg:  rgba(242, 241, 234, 0.05);
    --accent:    #4ade80;

    --himmel-oben:  #0e1a2b;
    --himmel-unten: #060a12;
    --himmel-licht: rgba(120, 170, 240, 0.14);
    --creme:        #070808;
    --abend-oben:   #091422;
    --abend-unten:  #060a12;
    --warp-start:   7, 8, 8;
  }
}
:root[data-theme="dark"] {
  --bg:        #070808;
  --fg:        #f2f1ea;
  --muted:     #8b877e;
  --line:      rgba(242, 241, 234, 0.16);
  --line-soft: rgba(242, 241, 234, 0.08);
  --grid:      rgba(242, 241, 234, 0.10);
  --hover-bg:  rgba(242, 241, 234, 0.05);
  --accent:    #4ade80;

  --himmel-oben:  #0e1a2b;
  --himmel-unten: #060a12;
  --himmel-licht: rgba(120, 170, 240, 0.14);
  --creme:        #070808;
  --abend-oben:   #091422;
  --abend-unten:  #060a12;
  --warp-start:   7, 8, 8;
}

/* ── 2) Basis ────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  transition: background-color 0.4s var(--ease), color 0.4s var(--ease);
}

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

::selection { background: var(--fg); color: var(--bg); }

/* Der Mauszeiger bleibt der gewohnte des Systems — nur die Spur
   dahinter ist eigen. Die Quadrate tragen das Grün des Headsets.
   Die Elemente legt script.js an. */
.trail {
  position: fixed;
  top: 0; left: 0;
  background: var(--headset-gruen);
  pointer-events: none;
  z-index: 250;
  opacity: 0;
  will-change: opacity;
}

/* Über dem schwarzen Tunnel schalten die festen Leisten auf helle
   Schrift um. Kopf und Fuß werden getrennt geschaltet: am Tunnelende
   liegt oben noch Schwarz, unten aber schon das helle Blau des
   Abspanns — eine gemeinsame Klasse würde eine der beiden Leisten
   unlesbar machen. Beides setzt script.js. */
:root.kopf-hell .site-header,
:root.fuss-hell .hud-bar {
  color: #f2f1ea;
  border-color: rgba(242, 241, 234, 0.16);
  background: transparent;
}
:root.kopf-hell .logo-suffix,
:root.fuss-hell .hud-dim { color: rgba(242, 241, 234, 0.55); }

/* Feines Filmkorn — nimmt der Fläche das Digitale. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 300;
  pointer-events: none;
  opacity: 0.5;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.16'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] body::after { mix-blend-mode: screen; opacity: 0.28; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body::after { mix-blend-mode: screen; opacity: 0.28; }
}

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: var(--pad); top: 0.5rem; z-index: 400;
  background: var(--fg); color: var(--bg);
  padding: 0.5rem 0.9rem;
  font-family: var(--font-mono); font-size: 0.75rem;
}

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

/* ── Auswahlrahmen wie in alten Oberflächen ──────────────────────
   Gepunkteter Rahmen beim Überfahren. Bewusst nicht `outline: dotted`
   — das rendert je nach Browser runde Punkte. Vier Verläufe ergeben
   saubere eckige Kästchen, die auf dem Pixelraster sitzen.
   ──────────────────────────────────────────────────────────────── */
/* Nur auf Text, nicht auf Bildern und Projektkacheln. */
.nav-link,
.footer-link,
.btn,
.ilink { position: relative; }

.nav-link::before,
.footer-link::before,
.btn::before,
.ilink::before {
  content: "";
  position: absolute;
  inset: var(--sel, -6px);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s steps(2);
  background:
    repeating-linear-gradient(to right,  currentColor 0 3px, transparent 3px 6px) left top    / 100% 2px no-repeat,
    repeating-linear-gradient(to right,  currentColor 0 3px, transparent 3px 6px) left bottom / 100% 2px no-repeat,
    repeating-linear-gradient(to bottom, currentColor 0 3px, transparent 3px 6px) left top    / 2px 100% no-repeat,
    repeating-linear-gradient(to bottom, currentColor 0 3px, transparent 3px 6px) right top   / 2px 100% no-repeat;
}

.nav-link:hover::before,
.footer-link:hover::before,
.btn:hover::before,
.ilink:hover::before { opacity: 1; }

.ilink      { --sel: -3px; }
.footer-link{ --sel: 4px; }

/* Die Unterstreichung der Navigation entfällt, der Rahmen genügt. */
.nav-link::after { display: none; }

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

/* Gemeinsame Schrift für alle technischen Kleinangaben */
.mono {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* ── 3) Sichtbares Spaltenraster ─────────────────────────────────── */
/* Vier Spalten mit Haarlinien, dazu Fadenkreuze an den Kreuzungen.
   Liegt fest über der Seite und scrollt nicht mit — dadurch wirkt der
   Inhalt, als liefe er hinter einem Messraster durch. */
.grid-overlay {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  padding: 0 var(--pad);
}
.grid-overlay .rule {
  position: absolute;
  top: 0; bottom: 0;
  width: 1px;
  background: var(--grid);
}
.grid-overlay .cross {
  position: absolute;
  width: 11px; height: 11px;
  margin: -5px 0 0 -5px;
}
.grid-overlay .cross::before,
.grid-overlay .cross::after {
  content: "";
  position: absolute;
  background: var(--grid);
}
.grid-overlay .cross::before { left: 0; right: 0; top: 5px; height: 1px; }
.grid-overlay .cross::after  { top: 0; bottom: 0; left: 5px; width: 1px; }

@media (max-width: 720px) {
  .grid-overlay .rule:nth-child(2),
  .grid-overlay .rule:nth-child(4) { display: none; }
  .grid-overlay .cross { display: none; }
}

/* Alles Inhaltliche liegt über dem Raster. */
.site-header, .hud-bar, main, .site-footer { position: relative; z-index: 2; }

/* ── 4) Header ───────────────────────────────────────────────────── */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  display: flex;
  align-items: center;
  height: var(--bar);
  padding: 0 var(--pad);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.logo { font-weight: 500; white-space: nowrap; }
.logo-suffix { color: var(--muted); }

/* Die Navigation sitzt in der rechten Hälfte und verteilt sich dort
   gleichmäßig — wie eine Messskala, nicht wie ein Menü. */
.nav {
  margin-left: auto;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: min(52%, 34rem);
}

.nav-link {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  justify-self: start;
  /* Für den Magnet-Effekt aus script.js: der Rücksprung federt weich */
  transition: transform 0.35s var(--ease);
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -4px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}
.nav-link:hover::after { transform: scaleX(1); transform-origin: left; }

/* Lesefortschritt als Haarlinie unter dem Header */
.site-header::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--fg);
  transform: scaleX(var(--progress, 0));
  transform-origin: left;
}

/* ── 5) Feste Leiste am unteren Rand ─────────────────────────────── */
.hud-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 50;
  display: flex;
  align-items: center;
  height: var(--bar);
  padding: 0 var(--pad);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg);
  /* Bewusst OHNE Verlauf dahinter: Der Creme-Schleier legte sich wie
     Milch über alles, was unten ins Bild scrollt. Die Vorlage lässt
     ihre Leiste auch nackt über dem Inhalt stehen. */
  background: transparent;
}
.hud-left  { margin-right: auto; }
.hud-mid   { position: absolute; left: 50%; transform: translateX(-50%); }
.hud-right { margin-left: auto; display: flex; align-items: center; gap: 1.25rem; }
.hud-dim   { color: var(--muted); }

.hud-btn {
  appearance: none;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  padding: 0;
  cursor: pointer;
}
.hud-btn:hover { color: var(--accent); }

@media (max-width: 900px) { .hud-mid { display: none; } }

/* ── 6) Hero ─────────────────────────────────────────────────────── */
/* Erste Station der Farbreise: der Himmel. Er endet exakt im Creme des
   nächsten Abschnitts — dadurch ist die Naht dazwischen unsichtbar. */
.hero {
  background: linear-gradient(178deg,
    var(--himmel-oben) 0%,
    var(--himmel-unten) 58%,
    var(--creme) 100%);
  position: relative;          /* Bezugspunkt für .hero-art */
  isolation: isolate;
  /* Die Platte läuft absichtlich über den rechten Rand hinaus. Ohne
     dieses overflow würde die Seite dadurch seitlich scrollbar — eine
     rotierende quadratische Fläche beansprucht mehr Platz als sie zeigt. */
  overflow: hidden;
  min-height: 100svh;
  padding: calc(var(--bar) + 1.5rem) var(--pad) calc(var(--bar) + 1rem);
  display: flex;
  flex-direction: column;
}

/* Kopfzone: drei Textblöcke, die den Spalten des Rasters folgen. */
.hero-top {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem;
}

.hero-name {
  grid-column: 1;
  margin: 0;
  font-size: clamp(1.5rem, 2.4vw, 2.125rem);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.03em;
}

/* Gleiche Größe wie der Vorstellungstext rechts — die beiden gehören
   als Paar zusammen und sollen sich nicht gegenseitig unterordnen. */
.hero-claim {
  grid-column: 2;
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(0.875rem, 1.05vw, 1.0625rem);
  line-height: 1.65;
  color: var(--fg);
}

/* Der Vorstellungstext trägt den Inhalt des Hero — er darf nicht wie
   eine Fußnote wirken. Deshalb spürbar größer als die Randbeschriftung
   und über zwei Spalten, damit die Zeilen nicht zu kurz brechen. */
.hero-intro {
  grid-column: 3 / -1;
  margin: 0;
  max-width: 46ch;
  justify-self: end;
  font-family: var(--font-mono);
  font-size: clamp(0.875rem, 1.05vw, 1.0625rem);
  line-height: 1.65;
}
.hero-intro a { border-bottom: 1px solid var(--line); }
.hero-intro a:hover { border-color: var(--accent); color: var(--accent); }

/* Geschwärzte Stelle — wie ein Schwarzbalken in einer Akte. */
.redacted {
  display: inline-block;
  background: var(--fg);
  color: transparent;
  border-radius: 1px;
  user-select: none;
}

/* Der große Satz sitzt unten und füllt die Breite. */
.hero-statement {
  position: relative;
  z-index: 1;
  margin: auto 0 0;
  font-size: clamp(2.5rem, 7.4vw, 7rem);
  font-weight: 700;
  line-height: 0.94;
  letter-spacing: -0.045em;
  text-transform: uppercase;
}

/* Sonnenstrahlen über dem Himmel — schräge, weiche Lichtbahnen wie in
   der Vorlage. Reines CSS, kein Bild, kein Ladeaufwand. */
.hero-art {
  position: absolute;
  inset: -20%;                 /* Überstand, damit die Schrägen nicht abreißen */
  z-index: 0;                  /* liegt hinter dem Text, aber über der Fläche */
  pointer-events: none;
  opacity: 0.9;
  background:
    linear-gradient(102deg,
      transparent 12%, var(--himmel-licht) 17%, transparent 23%,
      transparent 38%, var(--himmel-licht) 44%, transparent 52%,
      transparent 66%, var(--himmel-licht) 71%, transparent 79%);
  filter: blur(14px);
  /* Die Strahlen lösen sich vor der Unterkante auf. Ohne das reißen sie
     am Abschnittsende hart ab und erzeugen genau die sichtbare Naht,
     die hier nicht sein soll. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 46%, transparent 78%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 46%, transparent 78%);
}
/* Im Dunkeln bleiben die Bahnen, werden aber zu schwachem Sternenlicht —
   die Farbe steckt bereits in --himmel-licht. */
:root[data-theme="dark"] .hero-art { opacity: 0.7; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero-art { opacity: 0.7; }
}

/* ── Signaturbild: gläsernes Headset und tanzendes Skelett ───────
   Das Headset ist die Glasfassung von assets/headset-glas.svg —
   durchscheinend, außen grün schimmernd, wie die aufgeblasenen
   Glasbuchstaben der Vorlage. Es schwebt mittig und groß über dem
   Hero. Das Skelett daneben ist das echte Sprite-Blatt aus der
   Track-Attack-App — dasselbe, das dort sieben Stunden gekostet hat.
   ─────────────────────────────────────────────────────────────── */
/* Trägt nur noch das Skelett — es tanzt links unterhalb des Grußes. */
.hero-object {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  width: clamp(20rem, 62vw, 56rem);
  aspect-ratio: 1;
  pointer-events: none;
}

/* ── Der gläserne Gruß ───────────────────────────────────────────
   Das Gegenstück zum „hello" der Vorlage: ein echter 3D-Glasrender
   statt nachgebauter Vektorformen. Drei ineinander liegende Ebenen,
   weil sich Schweben, Neigung und Licht sonst dieselbe
   transform-Eigenschaft teilen müssten und sich gegenseitig
   überschreiben würden.
   ─────────────────────────────────────────────────────────────── */
.glas-wort {
  position: absolute;
  z-index: 0;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  width: clamp(19rem, 64vw, 58rem);
  pointer-events: none;      /* die Maus soll den Text darunter treffen */
  perspective: 70rem;
}

.glas-schwebt { animation: glasSchwebt 17s ease-in-out infinite; }
@keyframes glasSchwebt {
  0%, 100% { transform: translateY(-1.6%) rotate(-1.2deg); }
  50%      { transform: translateY(1.6%)  rotate(1.2deg); }
}

/* Neigung zur Maus (--ry/--rx) und das Einklappen beim Wegscrollen
   (--klapp/--kskal) teilen sich dieselbe Eigenschaft — deshalb stehen
   sie hier hintereinander in einer Kette. Beides setzt script.js. */
.glas-kern {
  position: relative;
  transform:
    rotateY(var(--ry, 0deg))
    rotateX(var(--rx, 0deg))
    rotateX(var(--klapp, 0deg))
    scale(var(--kskal, 1));
  transform-style: preserve-3d;
  will-change: transform;
}

/* Das Canvas liegt deckungsgleich über dem Bild. */
.glas-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
}
.glas-wort.hat-shader .glas-canvas { display: block; }
/* Das Bild bleibt als Textur im DOM, wird aber unsichtbar — der Shader
   zeichnet ab jetzt. visibility statt display, sonst verliert das
   Element seine Maße und das Canvas hätte keine Höhe mehr. */
.glas-wort.hat-shader .glas-bild { visibility: hidden; }
/* Den Glanz übernimmt dann der Shader selbst. */
.glas-wort.hat-shader .glas-licht { display: none; }

.glas-bild {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 1.5rem 3.5rem rgba(120, 150, 255, 0.22));
}

/* Das Wanderlicht: eine helle Stelle, die nur auf dem Glas sichtbar
   ist. Die Maske schneidet den Schein exakt auf die Buchstaben zu,
   sonst läge ein rechteckiger Fleck über dem Hero. */
.glas-licht {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.45s var(--ease);
  background: radial-gradient(
    22rem 22rem at var(--mx, 50%) var(--my, 50%),
    rgba(255, 255, 255, 0.85),
    rgba(190, 215, 255, 0.35) 38%,
    transparent 68%
  );
  mix-blend-mode: screen;
  /* Die Maske ist je Glaswort ein anderes Bild — sie kommt als
     Variable aus dem style-Attribut des jeweiligen .glas-wort. */
  -webkit-mask-image: var(--glas-maske, url("assets/moin-glas.png"));
          mask-image: var(--glas-maske, url("assets/moin-glas.png"));
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}
.hero:hover .glas-licht,
.site-footer:hover .glas-licht { opacity: 1; }

/* ── Der gläserne Schlussruf im Footer ──────────────────────────
   Gleiche Machart wie der Gruß oben, nur als Hintergrund für den
   Schlusssatz: mittig, hinter Titel und Links, gut sichtbar über
   dem Abendblau. */
/* Im Footer tauchen die Fallteile weich UNTER der Oberkante auf,
   statt voll sichtbar an ihr zu erscheinen — sonst zeichnet ihr
   Aufploppen genau die Kante nach, die unsichtbar bleiben soll. */
.site-footer .fall-layer {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 90%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 90%, transparent 100%);
}

.site-footer .glas-wort {
  /* Oben im Polster, nicht mittig: Der Ruf steht ÜBER dem Schlusssatz.
     Die Unterkante darf die Überschrift leicht anschneiden — wie die
     Glasbuchstaben der Vorlage in den Text ragen. */
  top: clamp(1.5rem, 5vh, 4rem);
  translate: -50% 0;
  width: clamp(19rem, 52vw, 50rem);
  opacity: 0.95;
}

@media (max-width: 900px) {
  .glas-wort { width: 84vw; }
}
@media (prefers-reduced-motion: reduce) {
  .glas-schwebt { animation: none; }
  .glas-kern { transform: none; }
  .glas-licht { display: none; }
}

/* ── Fallende Teile aus den Projekten ───────────────────────────
   Wie die verstreuten Sticker der Vorlage, nur in Bewegung: kleine
   Glasstücke, Karten, Schallplatten und Pixel sinken langsam durch
   den Hero. Position, Größe und Takt stehen als Variablen im HTML,
   damit jedes Teil seinen eigenen Rhythmus hat.
   ─────────────────────────────────────────────────────────────── */
.fall-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  /* Sehr lang auslaufende Maske: Die Abschnittskante würde die Teile
     sonst hart abschneiden und damit genau die Linie zeichnen, die
     unsichtbar bleiben soll. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 42%, transparent 92%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 42%, transparent 92%);
  /* Beim Verlassen des Hero verblassen die Teile zu Schemen,
     statt zu verschwinden. --fall-deck kommt aus script.js. */
  opacity: var(--fall-deck, 1);
}

/* Verlässt der Hero das Bild, halten die Fallteile an, statt
   unsichtbar weiterzufallen — wie in der Vorlage. Das Skelett ist
   bewusst ausgenommen: Es tanzt weiter, auch beim Scrollen.
   Setzt script.js. */
.hero.eingefroren .fall,
.hero.eingefroren .fall-kern { animation-play-state: paused; }

.fall {
  position: absolute;
  top: -18vh;
  left: var(--x, 50%);
  width: var(--gr, 3rem);
  aspect-ratio: 1;
  opacity: 0;
  animation: fallen var(--dauer, 17s) linear var(--warte, 0s) infinite;
  will-change: transform, opacity;
}
/* --dx lässt Teile schräg wandern (auch von rechts hereinfliegen),
   --weite bestimmt die Fallstrecke — im Footer reicht weniger.
   script.js würfelt Tempo, Versatz und Drift bei jedem Laden neu,
   damit nichts nach Schleife aussieht. */
/* --px/--py sind der Ausweichschub vor dem Mauszeiger. Sie stehen in
   beiden Eckbildern, damit der Schub über die ganze Fallstrecke gilt
   und nicht wegen der Interpolation zum Ende hin verpufft. */
@keyframes fallen {
  0%   { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(var(--rot0, 0deg)); opacity: 0; }
  8%   { opacity: var(--deck, 0.8); }
  85%  { opacity: var(--deck, 0.8); }
  100% {
    transform:
      translate(calc(var(--dx, 0rem) + var(--px, 0px)), calc(var(--weite, 135vh) + var(--py, 0px)))
      rotate(var(--rot1, 200deg));
    opacity: 0;
  }
}

/* ── Räumliche Teile ─────────────────────────────────────────────
   Die Hülle fällt, der Kern taumelt dabei um zwei Achsen — so
   kippen die Teile im Raum, statt nur flach zu rotieren. */
.fall-3d { perspective: 40rem; }
/* Die Hülle muss das Format der Karte annehmen. Sonst zwängt das
   quadratische .fall die Karte in ein Quadrat: object-fit rettet zwar
   das Bild, es erscheint aber zu klein, und die Ausweichzone säße
   falsch. */
.fall-3d:has(> .fall-tier) { aspect-ratio: 400 / 295; }
.fall-3d > .fall-kern {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  /* Pendeln statt Vollrotation: bei 360-Grad-Drehungen stünde die
     Fläche die halbe Zeit auf der Kante und wäre unsichtbar. */
  animation: taumeln var(--tdauer, 8s) ease-in-out infinite;
}
@keyframes taumeln {
  0%, 100% { transform: rotateX(14deg)  rotateY(-42deg) rotateZ(-5deg); }
  50%      { transform: rotateX(-14deg) rotateY(42deg)  rotateZ(5deg); }
}

/* Ganze Rollenkarten fallen mit — komplett mit Rahmen und Text,
   ausgeschnitten aus dem Kontaktbogen. drop-shadow statt box-shadow,
   damit der Schein der runden Kartenkontur folgt statt dem Kasten. */
.fall-tier {
  aspect-ratio: 400 / 295;
  object-fit: contain;
  filter:
    drop-shadow(0 0 0.9rem rgba(74, 222, 128, 0.25))
    drop-shadow(0 0.35rem 0.9rem rgba(0, 0, 0, 0.45));
}

/* Das kleine Headset fällt als freies Objekt — die SVG hat einen
   transparenten Hintergrund, kein Kasten drumherum. */
.fall-headset {
  /* height:auto ist nötig — sonst gewinnt das height-Attribut aus dem
     HTML als Darstellungsvorgabe und zwängt das Bild in eine hohe Box. */
  height: auto;
  aspect-ratio: 1;
  object-fit: contain;
  filter: drop-shadow(0 0 1rem rgba(74, 222, 128, 0.35));
}

/* Glasplättchen: dieselbe Materialsprache wie das große Headset */
.fall-glas {
  border-radius: 0.45rem;
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.16), rgba(74, 222, 128, 0.08) 55%, rgba(74, 222, 128, 0.16));
  border: 1px solid rgba(74, 222, 128, 0.45);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 0 1.5rem rgba(74, 222, 128, 0.18);
  backdrop-filter: blur(2px);
}

/* Rollenkarte im Hochformat */
.fall-karte {
  aspect-ratio: 5 / 7;
  border-radius: 0.6rem;
}

/* Mini-Schallplatte — Erbe der großen Platte, die hier früher stand.
   Eine perfekt runde Scheibe zeigt beim Drehen nichts: erst der
   asymmetrische Lichtkeil (::before) macht die Rotation sichtbar.
   Er dreht unabhängig vom Fall, wie eine laufende Platte. */
.fall-vinyl {
  position: relative;
  border-radius: 50%;
  background:
    repeating-radial-gradient(circle at center, rgba(27, 28, 32, 0.9) 0 2px, rgba(16, 17, 21, 0.9) 2px 4px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: 0 0 1.5rem rgba(74, 222, 128, 0.15);
  overflow: hidden;
}
.fall-vinyl::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(
    rgba(255, 255, 255, 0.20) 0 26deg,
    transparent 26deg 174deg,
    rgba(255, 255, 255, 0.10) 174deg 208deg,
    transparent 208deg
  );
  animation: platte 2.4s linear infinite;
}
/* Das Label liegt still über dem drehenden Licht — mit einer kleinen
   Kerbe, die mitläuft, sieht man auch dem Etikett die Drehung an. */
.fall-vinyl::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 38%;
  height: 38%;
  border-radius: 50%;
  background:
    conic-gradient(rgba(11, 11, 10, 0.55) 0 40deg, transparent 40deg),
    radial-gradient(circle at 42% 36%, #4ade80, #1f9d55 65%, #14803a);
  animation: platte 2.4s linear infinite;
}
@keyframes platte { to { transform: rotate(360deg); } }

/* Einzelne Pixel — dieselben Quadrate wie die Spur hinter der Maus */
.fall-pixel {
  width: var(--gr, 0.875rem);
  background: var(--headset-gruen);
  box-shadow: 0 0 0.9rem rgba(74, 222, 128, 0.55);
}

/* Sticker: die Logos der Projekte, leicht gekippt wie aufgeklebt */
.fall-logo {
  height: auto;
  aspect-ratio: auto;
  filter: drop-shadow(0 0.4rem 1.2rem rgba(0, 0, 0, 0.35));
}

/* Sprite-Blatt: 5275 × 424 px, 25 Einzelbilder à 211 px in zwei Reihen.
   Gerechnet wird in Pixeln statt Prozent — nur so trifft jeder Schritt
   exakt eine Bildkante. --fw ist die Breite eines Einzelbilds. */
.skeleton {
  --fw: clamp(5rem, 9vw, 8.5rem);
  position: absolute;
  left: -6%;
  bottom: 18%;
  width: var(--fw);
  height: calc(var(--fw) * 212 / 211);
  background-image: url("assets/skelett-sprite.png");
  background-repeat: no-repeat;
  background-size: calc(var(--fw) * 25) calc(var(--fw) * 424 / 211);
  background-position: 0 0;         /* obere Reihe */
  animation: dance 1.1s steps(25) infinite;
  filter: drop-shadow(0 0 1.5rem rgba(31, 157, 85, 0.45));
}
@keyframes dance { to { background-position-x: calc(var(--fw) * -25); } }

@media (max-width: 900px) {
  .hero-object { opacity: 0.55; width: 17rem; }
  /* Auf kleinen Bildschirmen fällt nur die Hälfte — weniger Unruhe,
     weniger Rechenlast. */
  .fall:nth-child(even) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .glas-headset { animation: none; }
  .footer-echo { animation: none; transform: rotate(14deg); }
  .skeleton { animation: none; }
  .fall { display: none; }
}

/* ── 7) Aussage ──────────────────────────────────────────────────── */
/* Zweite Station: das ruhige Creme, in dem die Projekte stehen.
   Der Verlauf oben blendet den Himmel weich aus. */
.statement {
  background: var(--creme);
  padding: clamp(6rem, 16vh, 11rem) var(--pad);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem;
}
.statement-label { grid-column: 1; }
.statement-body  { grid-column: 2 / -1; }

.statement-title {
  margin: 0;
  font-size: clamp(1.75rem, 4.4vw, 3.75rem);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.035em;
  max-width: 22ch;
}
.statement-title .accent { color: var(--accent); }

/* ── Der Kringel ─────────────────────────────────────────────────
   Ein Wort bekommt eine handgezogene neongrüne Ellipse, die sich
   beim Einblenden selbst zeichnet — wie mit dem Stift umkreist.
   Die Vorlage macht das im Tunnel, wir an der Kernaussage.
   ─────────────────────────────────────────────────────────────── */
.ring {
  position: relative;
  display: inline-block;
}
.ring-svg {
  position: absolute;
  inset: -0.22em -0.3em -0.28em;
  width: calc(100% + 0.6em);
  height: calc(100% + 0.5em);
  overflow: visible;
  pointer-events: none;
}
.ring-svg ellipse {
  fill: none;
  stroke: var(--headset-gruen);
  stroke-width: 2.5;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  transform: rotate(-2deg);
  transform-origin: center;
  transition: stroke-dashoffset 1.1s var(--ease) 0.55s;
}
.line.is-in .ring-svg ellipse { stroke-dashoffset: 0; }

.statement-text {
  margin: 2rem 0 0;
  max-width: 46ch;
  color: var(--muted);
  font-size: clamp(0.95rem, 1.3vw, 1.125rem);
}

/* ── 8) Projekte als Bildblöcke ──────────────────────────────────── */
.work {
  background: var(--creme);
  padding: 0 var(--pad) clamp(4rem, 10vh, 8rem);
}

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
}

/* Die Kacheln sitzen versetzt im Vierspaltenraster: mal links, mal
   rechts, unterschiedlich breit und gegeneinander nach unten geschoben.
   Dadurch entsteht der Rhythmus statt einer Kette gleicher Blöcke. */
.work-list {
  list-style: none;
  margin: clamp(2.5rem, 6vw, 5rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(3rem, 7vw, 6rem) 1.5rem;
}


.work-item:nth-child(1) { grid-column: 1 / 3; }
.work-item:nth-child(2) { grid-column: 3 / 5; margin-top: clamp(3rem, 9vw, 8rem); }
.work-item:nth-child(3) { grid-column: 1 / 3; margin-top: clamp(0rem, 4vw, 4rem); }
.work-item:nth-child(4) { grid-column: 3 / 5; margin-top: clamp(2rem, 6vw, 5rem); }
.work-item:nth-child(5) { grid-column: 1 / 3; margin-top: clamp(1rem, 5vw, 4rem); }
.work-item:nth-child(6) { grid-column: 3 / 5; margin-top: clamp(3rem, 9vw, 8rem); }

/* Die Seite über die Seite steht IMMER zuletzt und über die volle
   Breite — sie ist der Schlusspunkt. Deshalb :last-child statt einer
   festen Nummer: Neue Projekte reihen sich davor ein, ohne dass hier
   etwas nachgezogen werden muss. Das flachere Format sorgt dafür, dass
   sie die gestaffelten Kacheln darüber nicht erschlägt. */
.work-item:last-child { grid-column: 1 / 5; margin-top: clamp(3rem, 8vw, 7rem); }
.work-item:last-child .work-figure { aspect-ratio: 2.6 / 1; }

/* Bild oben, darunter Titel links und Angaben rechts. */
.work-link {
  position: relative;        /* Anker für das Blätter-Canvas */
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1rem 1.5rem;
  align-items: baseline;
}

/* Der Blätter-Effekt (Ecken-Aufrollen) ist vorerst ausgebaut —
   Begründung und Versuchshistorie in der Projekt-Erinnerung. */

.work-figure {
  grid-column: 1 / -1;
  position: relative;
  /* 2:1 entspricht dem Zuschnitt der Projektbilder — nichts wird
     an den Seiten weggeschnitten. */
  aspect-ratio: 2 / 1;
  overflow: hidden;
  background: var(--hover-bg);
}
/* Zwei Kacheln stehen etwas höher, damit die Reihe nicht monoton wird.
   3:2 statt 4:3 — bei 4:3 wurde von den 2:1-Bildern zu viel weggeschnitten. */
.work-item:nth-child(2) .work-figure,
.work-item:nth-child(4) .work-figure { aspect-ratio: 3 / 2; }

/* Beim Showcase steht die Überschrift links — sonst schneidet der
   Zuschnitt sie an. */
.work-item:nth-child(2) .work-figure > img { object-position: left center; }
.work-figure img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  /* --shift kommt aus script.js und erzeugt die leichte Parallaxe */
  transform: scale(1.08) translateY(var(--shift, 0));
  transition: transform 0.9s var(--ease);
}
.work-link:hover .work-figure img { transform: scale(1.13) translateY(var(--shift, 0)); }

/* ── Überblendung beim Überfahren ────────────────────────────────
   Aus der Vorschau wird eine Marke auf schwarzem Grund. Der Inhalt
   steckt im HTML, damit jedes Projekt sein eigenes Zeichen bekommt.
   ──────────────────────────────────────────────────────────────── */
/* Die Überblendung selbst ist IMMER da, aber durchsichtig — den
   sichtbaren Auftritt übernimmt die Pixel-Welle: knallige Farbblöcke
   (--hover-farbe im HTML), die von der Mitte nach außen aufpoppen,
   bis die ganze Kachel gedeckt ist. Gezeichnet von script.js. */
.work-hover {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 1.5rem;
  padding: 1.5rem;
  text-align: center;
  background: transparent;
  pointer-events: none;
}

.pixel-bild {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  pointer-events: none;
}

/* Der Text kommt parallel zur Welle: schnell, mit kleinem Schub. */
.work-hover-frage, .work-hover-label {
  position: relative;
  z-index: 1;
  opacity: 0;
  transform: translateY(0.6rem);
  transition: opacity 0.22s var(--ease) 0.08s, transform 0.28s var(--ease) 0.08s;
}
.work-link:hover .work-hover-frage,
.work-link:focus-visible .work-hover-frage,
.work-link:hover .work-hover-label,
.work-link:focus-visible .work-hover-label {
  opacity: 1;
  transform: none;
}
/* Kein Bild, sondern ein Satz, der neugierig macht. */
.work-hover-frage {
  margin: 0;
  max-width: 24ch;
  font-size: clamp(1.15rem, 2.1vw, 1.75rem);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
}

.work-hover-label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--neon);
}
.work-hover-label::after {
  content: "→";
  transition: transform 0.4s var(--ease);
}
.work-link:hover .work-hover-label::after { transform: translateX(0.35rem); }

/* Touch-Geräte kennen kein Überfahren: Dort setzt script.js die
   Klasse .ist-aktiv, wenn die Kachel beim Scrollen das mittlere Band
   des Bildschirms durchquert — gleiche Optik wie der Hover-Zustand. */
.work-item.ist-aktiv .work-hover-frage,
.work-item.ist-aktiv .work-hover-label { opacity: 1; transform: none; }
.work-item.ist-aktiv .work-hover-label::after { transform: translateX(0.35rem); }
.work-item.ist-aktiv .work-figure img { transform: scale(1.13) translateY(var(--shift, 0)); }

/* Etikett in Signalfarbe, oben rechts auf dem Bild */
.work-kind {
  position: absolute;
  top: 0; right: 0;
  z-index: 2;
  padding: 0.3rem 0.6rem;
  background: var(--neon);
  color: var(--neon-fg);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

/* Titel links unter dem Bild, Angaben rechts. */
.work-title {
  grid-column: 1;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.work-meta {
  grid-column: 2;
  justify-self: end;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

@media (max-width: 900px) {
  .work-list { grid-template-columns: 1fr; gap: clamp(2.5rem, 8vw, 4rem) 0; }
  .work-item:nth-child(1),
  .work-item:nth-child(2),
  .work-item:nth-child(3),
  .work-item:nth-child(4),
  .work-item:nth-child(5),
  .work-item:nth-child(6) { grid-column: 1; margin-top: 0; }
  .work-item .work-figure { aspect-ratio: 2 / 1; }
  /* Die letzte behält ihr flaches Format — das Bild ist genau dafür
     zugeschnitten, ein 2:1-Kasten würde links und rechts hineinschneiden. */
  .work-item:last-child .work-figure { aspect-ratio: 2.6 / 1; }
}

/* Platzhalter-Eintrag, solange kein Bild existiert */
.work-figure.is-empty {
  display: grid;
  place-items: center;
  border: 1px dashed var(--line);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ── 9a) Warp-Tunnel ─────────────────────────────────────────────
   Ein hoher Abschnitt, in dem eine haftende Bühne stehenbleibt.
   Der Scroll-Fortschritt darin steuert Tempo, Dunkelheit und
   welcher Satz gerade zu sehen ist. Die Striche zeichnet script.js
   auf ein Canvas.
   ──────────────────────────────────────────────────────────────── */
/* Höhe geteilt durch die Anzahl der Sätze ergibt, wie lange jeder
   stehen bleibt. Bei sieben Schritten braucht es entsprechend Platz. */
/* Länger als der Flug selbst: die letzten rund 30 Prozent dieser Höhe
   sind Standzeit für die Pointe (siehe HALT in script.js). */
.warp {
  position: relative;
  height: 1010vh;
  /* Bewusst OHNE Trennlinie: Der Tunnel soll keine erkennbare eigene
     Seite sein. Er beginnt in der Creme-Farbe des Vorgängers und
     kippt ins Schwarz — die Bühne färbt script.js laufend um. */
  border-top: 0;
  background: var(--creme);
}

.warp-stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--bg);
  transition: background-color 0.2s linear;
}

.warp-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.warp-core {
  position: relative;
  z-index: 2;
  pointer-events: none;
  display: grid;
  justify-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding: 0 var(--pad);
  text-align: center;
}

/* Der Hülle gibt script.js Größe und Bahn — sie wächst, bis die
   Platte das Bild füllt, und trägt sie am Ende wieder davon. */
.warp-objekt {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  pointer-events: none;
  will-change: transform, opacity;
}

/* Die Schallplatte: fast schwarzer Rillenkörper mit grünem Label.
   Massiv und geschlossen — deshalb kann sie, anders als das offene
   Glas-Headset, beim Hineinfliegen wirklich den Bildschirm schlucken.
   Die Drehung läuft unabhängig vom Scrollen auf dem inneren Element,
   sonst überschrieben sich Drehung und Wachstum gegenseitig. */
.warp-vinyl {
  width: clamp(15rem, 30vw, 26rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at center, #05060a 0 2.4%, transparent 2.6%),
    radial-gradient(circle at center, #3fae66 0 11%, #1f9d55 11% 17.5%, transparent 18%),
    linear-gradient(115deg, transparent 40%, rgba(255, 255, 255, 0.08) 47%, transparent 55%),
    repeating-radial-gradient(circle at center, #17181c 0 3px, #0c0d10 3px 6px);
  box-shadow:
    0 0 4rem rgba(74, 222, 128, 0.22),
    0 2rem 5rem rgba(0, 0, 0, 0.5);
  animation: platte 7s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .warp-vinyl { animation: none; }
}

.warp-line {
  margin: 0;
  max-width: 16ch;
  font-size: clamp(2rem, 6.5vw, 5.5rem);
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  color: var(--fg);
  transition: opacity 0.35s var(--ease), color 0.3s linear;
}
.warp-line.is-swapping { opacity: 0; }

/* Der Schluss: in Signalfarbe, aber ruhig. Es ist eine Feststellung,
   kein Ausruf — deshalb nur wenig größer als die Zeilen davor und
   ohne den harten Einschlag von vorher. */
.warp-line.is-finale {
  font-size: clamp(2.25rem, 7vw, 5.5rem);
  color: var(--headset-gruen);
  max-width: 20ch;
  text-shadow: 0 0 4rem rgba(74, 222, 128, 0.35);
  animation: einschlag 0.8s var(--ease) both;
}
@keyframes einschlag {
  from { transform: scale(1.06); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

.warp-hint {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* steht auf der dunklen Platte, nicht auf der Bühne */
  color: rgba(255, 255, 255, 0.65);
  transition: opacity 0.4s var(--ease);
}

/* ── Satelliten-Sätze ────────────────────────────────────────────
   Mitten im Flug verteilen sich vier Sätze über den Rahmen, wie in
   der Vorlage: leichteres Gewicht, keine Versalien, jeder an seinem
   eigenen Platz. script.js blendet sie über .is-da ein und aus.
   ─────────────────────────────────────────────────────────────── */
.warp-satellit {
  position: absolute;
  z-index: 2;
  max-width: 18ch;
  margin: 0;
  font-size: clamp(1.15rem, 2.4vw, 1.9rem);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.015em;
  color: #ffffff;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
  pointer-events: none;
}
/* Keine Verzögerungen mehr: Die Staffelung kommt aus dem Scrollweg —
   jeder Satz hat in script.js sein eigenes Fenster, im Gleichschritt
   mit dem Planetenaufbau. */
.warp-satellit:nth-of-type(1) { left: var(--pad); top: 16%; }
.warp-satellit:nth-of-type(2) { right: var(--pad); top: 32%; text-align: right; }
.warp-satellit:nth-of-type(3) { left: calc(var(--pad) + 4vw); bottom: 26%; }
.warp-satellit:nth-of-type(4) { right: calc(var(--pad) + 6vw); bottom: 13%; text-align: right; }
.warp-satellit.is-da { opacity: 1; transform: none; }

/* ── Das Skelett fliegt mit ──────────────────────────────────────
   Im Tunnel tanzt es die zweite Reihe des Sprite-Blatts: die Arme
   gehen zur Seite. Gleiche Pixelrechnung wie im Hero — nur die
   Startzeile ist um eine Bildhöhe nach oben verschoben. Die
   dance-Keyframes bewegen nur die X-Position, deshalb können sich
   beide Skelette dieselbe Animation teilen. */
.warp-skelett {
  --fw: clamp(4.5rem, 7vw, 7rem);
  position: absolute;
  left: 7%;
  bottom: 10%;
  z-index: 2;
  width: var(--fw);
  height: calc(var(--fw) * 212 / 211);
  background-image: url("assets/skelett-sprite.png");
  background-repeat: no-repeat;
  background-size: calc(var(--fw) * 25) calc(var(--fw) * 424 / 211);
  background-position: 0 calc(var(--fw) * -212 / 211);
  animation: dance 1.1s steps(25) infinite;
  filter: drop-shadow(0 0 1.5rem rgba(74, 222, 128, 0.45));
  pointer-events: none;
  /* Erst im Tunnel: unsichtbar und angehalten, bis script.js über
     .is-da freigibt — es fängt drinnen an zu tanzen, nicht davor. */
  opacity: 0;
  animation-play-state: paused;
  transition: opacity 0.5s var(--ease);
}
.warp-skelett.is-da {
  opacity: 1;
  animation-play-state: running;
}
@media (prefers-reduced-motion: reduce) {
  .warp-skelett { animation: none; }
}

/* Ohne Bewegung bleibt ein ruhiges Bild stehen. */
@media (prefers-reduced-motion: reduce) {
  .warp { height: auto; }
  .warp-stage { position: static; height: auto; padding: clamp(5rem, 14vh, 9rem) 0; }
  .warp-canvas { display: none; }
}

/* ── 9) Laufband ─────────────────────────────────────────────────── */
/* Vierte Station: Der Tunnel endet wieder HELL — alles ist in die
   Platte zurückgekehrt, die Bühne steht auf Creme. Von dort geht es
   wie oben beim Start weich ins Blau: Beige → Abendhimmel. */
.banner {
  background: linear-gradient(180deg, var(--creme) 0%, var(--abend-oben) 78%);
  color: var(--fg);
  padding: clamp(4rem, 12vh, 8rem) 0;
  border-top: 0;
  overflow: hidden;
}
.marquee {
  display: flex;
  width: max-content;
  animation: slide 34s linear infinite;
}
/* Bewusst kein Anhalten beim Überfahren: Der Balken nimmt die ganze
   Breite ein, dadurch stoppte das Band jedes Mal, wenn der Zeiger
   unten langfuhr — das sah nach Ruckeln aus, nicht nach Absicht. */
.marquee span {
  display: block;
  padding-right: 0.3em;
  font-size: clamp(2.5rem, 9vw, 7.5rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  white-space: nowrap;
}
.marquee .sep { color: var(--accent); }
@keyframes slide { to { transform: translateX(-50%); } }

/* ── 10) Footer ──────────────────────────────────────────────────── */
/* Ziel der Farbreise: wieder Blau, wie am Anfang. Das große Polster
   oben ist die Bühne für den gläsernen Schlussruf — er steht über dem
   Schlusssatz, nicht hinter ihm, und braucht dafür eigenen Raum. */
.site-footer {
  position: relative;          /* Bezugspunkt für Glas-Echo und Sticker */
  overflow: hidden;
  background: linear-gradient(180deg, var(--abend-oben), var(--abend-unten));
  padding: clamp(14rem, 34vh, 24rem) var(--pad) calc(var(--bar) + 1.5rem);
  border-top: 0;
}

.footer-title {
  position: relative;
  z-index: 1;                  /* Text liegt über dem Glas, wie in der Vorlage */
  margin: 0 0 clamp(2.5rem, 7vw, 4.5rem);
  font-size: clamp(2.25rem, 8.2vw, 8rem);
  font-weight: 700;
  line-height: 0.94;
  letter-spacing: -0.045em;
  text-transform: uppercase;
}

/* ── Glas-Echo im Footer ─────────────────────────────────────────
   Die Vorlage legt ihre Glasbuchstaben hinter den Schlusssatz.
   Bei uns kehrt das gläserne Headset wieder — groß, gekippt,
   halb aus dem Bild laufend. Dazu die Projektlogos als Sticker.
   ─────────────────────────────────────────────────────────────── */
.footer-echo {
  position: absolute;
  z-index: 0;
  right: clamp(-7rem, -5vw, -2rem);
  top: -2.5rem;
  width: clamp(16rem, 32vw, 30rem);
  opacity: 0.55;
  pointer-events: none;
  /* Auch unten dreht das Glas — etwas gemächlicher als oben. */
  animation: echodreh 24s ease-in-out infinite;
}
@keyframes echodreh {
  0%, 100% { transform: rotate(14deg) perspective(60rem) rotateY(-24deg); }
  50%      { transform: rotate(8deg)  perspective(60rem) rotateY(24deg); }
}

@media (max-width: 720px) {
  .footer-echo { opacity: 0.3; }
}

.footer-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.footer-link {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1.5rem 0.75rem;
  border-bottom: 1px solid var(--line);
  transition: background-color 0.3s var(--ease), padding-left 0.35s var(--ease);
}
.footer-link:hover { background: var(--hover-bg); padding-left: 1.5rem; }
.footer-link-label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.footer-link-value { font-size: 1.0625rem; letter-spacing: -0.015em; overflow-wrap: anywhere; }

.footer-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2.5rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.footer-legal { display: flex; gap: 1.25rem; }
.footer-legal a:hover { color: var(--fg); }

/* ── 11) Bewegung ────────────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

/* Überschriftenzeilen fahren hinter einer Kante hervor. Das innere
   <span> wird von script.js eingezogen. */
.line {
  display: block;
  overflow: hidden;
  /* oben Platz für Umlaut-Punkte, unten für Unterlängen */
  padding-top: 0.22em;
  margin-top: -0.22em;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.line > .line-in {
  display: block;
  transform: translateY(110%);
  transition: transform 0.95s var(--ease);
}
.line.is-in > .line-in { transform: none; }
.line.reveal { opacity: 1; transform: none; }
.line.reveal:nth-child(2) > .line-in { transition-delay: 0.09s; }
.line.reveal:nth-child(3) > .line-in { transition-delay: 0.18s; }
.line.reveal:nth-child(4) > .line-in { transition-delay: 0.27s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .line > .line-in { transform: none; transition: none; }
  .marquee { animation: none; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ── Mobil ───────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .nav { width: auto; grid-auto-columns: auto; gap: 1.25rem; }
  .hero-top { grid-template-columns: 1fr; gap: 1.75rem; }
  .hero-name, .hero-claim, .hero-intro { grid-column: 1; }
  .hero-intro { max-width: 42ch; }
  .statement { grid-template-columns: 1fr; }
  .statement-label, .statement-body { grid-column: 1; }
}
