/* base.css setzt html { scroll-behavior: smooth } fuer Anker-Sprungmarken.
   Auf dieser Seite steuert Lenis das Scrollen selbst (setzt window.scrollTo
   viele Male pro Sekunde) — mit aktivem scroll-behavior:smooth faengt der
   Browser jeden einzelnen dieser Aufrufe zusaetzlich ab und glaettet ihn
   nochmal obendrauf. Zwei Bremsen hintereinander statt einer, spuerbar
   traeger als beabsichtigt. Deshalb hier gezielt zurueckgesetzt, nur fuer
   diese Seite. */
html { scroll-behavior: auto; }

:root {
  --void: #05060A;
  --chrome: #EAEEF5;
  --cyan: #22E0D6;
  --magenta: #FF3DAF;
  --amber: #FFA43D;
  --dim: #7A8697;
  --footer-line: rgba(234,238,245,.14);
  --ease: cubic-bezier(.16,1,.3,1);
}

body {
  background: var(--void);
  color: var(--chrome);
  font-family: "JetBrains Mono", monospace;
  overflow-x: hidden;
}

/* ---------- Dauerhafte Ebenen ---------- */

.gs-loader {
  position: fixed; left: 0; top: 0; right: 0; height: 2px; z-index: 90;
  background: rgba(234,238,245,.08); opacity: 1; transition: opacity .6s ease;
}
.gs-loader.is-done { opacity: 0; }
.gs-loader i { display: block; height: 100%; width: 0%; background: linear-gradient(90deg, var(--cyan), var(--magenta)); }

.gs-cursor {
  position: fixed; left: 0; top: 0; z-index: 95;
  width: 26px; height: 26px; margin: -13px 0 0 -13px;
  border: 1px solid rgba(234,238,245,.5); border-radius: 50%;
  pointer-events: none; opacity: 0;
  transition: opacity .3s ease, transform .18s var(--ease), background-color .18s ease;
}
.gs-cursor.is-live { opacity: 1; }
.gs-cursor.is-hot { transform: scale(1.9); background: rgba(34,224,214,.14); }
@media (hover: none) { .gs-cursor { display: none; } }

.gs-grain {
  position: fixed; inset: 0; z-index: 80; pointer-events: none;
  opacity: .16; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
.gs-grain::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 50% 50%, transparent 55%, rgba(0,0,0,.6));
}

.gs-head {
  position: fixed; top: 0; left: 0; right: 0; z-index: 85;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.4rem 1.6rem; font-size: .72rem; letter-spacing: .08em;
  color: #fff; text-shadow: 0 1px 18px rgba(0,0,0,.6); pointer-events: none;
}
.gs-head::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 320%; z-index: -1;
  background: linear-gradient(to bottom, rgba(5,6,10,.7), rgba(5,6,10,0));
}
.gs-back { pointer-events: auto; color: currentColor; }
.gs-back:hover { color: var(--cyan); }
.gs-readout { display: flex; align-items: center; gap: .7rem; }
.gs-progress { display: block; width: 84px; height: 1px; background: rgba(234,238,245,.25); }
.gs-progress i { display: block; height: 100%; width: 0%; background: var(--cyan); }
body.on-light .gs-head { color: #05060A; text-shadow: 0 1px 18px rgba(255,255,255,.5); }
body.on-light .gs-progress { background: rgba(5,6,10,.3); }

/* ---------- Der Film ---------- */

.gs-film { position: relative; height: 420vh; height: 420svh; }
.gs-stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; background: var(--void); }
#film-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.gs-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 1; transition: opacity .8s ease; }
.gs-poster.is-hidden { opacity: 0; }
.gs-stage-fade { position: absolute; inset: auto 0 0 0; height: 30vh; opacity: 0; background: linear-gradient(to bottom, transparent, var(--void)); }

/* --gs-beat-drift kommt aus js/gaming-intro-film.js (tick()) und traegt nur
   den vertikalen Reveal-Versatz. Faellt kein JS-Wert, greift -50% als
   Ruhezustand — dieselbe Zentrierung wie zuvor rein statisch. So kann jeder
   Beat seine eigene horizontale Positionierung behalten (translateX), ohne
   dass der Takt sie mit einem festen translateY() ueberschreibt. */
.gs-beat { position: absolute; z-index: 3; left: 8vw; top: 50%; transform: translateY(var(--gs-beat-drift, -50%)); max-width: 44rem; }
.gs-beat::before {
  content: ""; position: absolute; z-index: -1; inset: -70% -24% -70% -14%;
  background: radial-gradient(60% 58% at 24% 50%, rgba(5,6,10,.78), rgba(5,6,10,.4) 45%, transparent 78%);
}
.gs-beat h1 {
  font-family: "Anton", sans-serif; font-weight: 400;
  font-size: clamp(3rem, 11vw, 9rem); line-height: .88;
  margin: 0 0 1.2rem; letter-spacing: .01em; color: #fff;
  text-shadow: 0 2px 40px rgba(0,0,0,.5);
}
.gs-kicker { margin: 0 0 2rem; font-size: .8rem; letter-spacing: .3em; color: var(--cyan); }
.gs-cue { font-size: .72rem; letter-spacing: .2em; color: var(--dim); }
.gs-beat--mid { left: auto; right: 8vw; text-align: right; max-width: 30rem; }
.gs-beat--mid::before { inset: -70% -14% -70% -24%; background: radial-gradient(60% 58% at 76% 50%, rgba(5,6,10,.78), rgba(5,6,10,.4) 45%, transparent 78%); }
.gs-line { font-size: clamp(1.1rem, 2.4vw, 1.9rem); line-height: 1.4; margin: 0; }
/* Bilanz-Beat: mittig statt links/rechts wie die beiden Text-Beats, mit einem
   runderen, kraeftigeren Schein dahinter — die grosse Zahl braucht mehr
   Abdunkelung als eine Zeile Fliesstext, sonst verschwimmt sie mit dem hellen
   Kernbild darunter. */
/* max-width: none statt eines festen rem-Werts — die Zahl darf so breit
   werden, wie sie bei aktueller Stundenzahl tatsaechlich ist (white-space:
   nowrap auf .gs-huge verhindert den Umbruch); die eigentliche Begrenzung
   passiert ueber deren eigenen font-size-clamp, nicht ueber diese Box. */
.gs-beat--stats { left: 50%; right: auto; top: 50%; transform: translate(-50%, var(--gs-beat-drift, -50%)); max-width: none; text-align: center; }
.gs-beat--stats::before { inset: -55% -35%; background: radial-gradient(62% 62% at 50% 50%, rgba(5,6,10,.82), rgba(5,6,10,.45) 48%, transparent 78%); }

/* ---------- Kapitel, gemeinsam ---------- */

.gs-ch { position: relative; min-height: min(96vh, 940px); min-height: min(96svh, 940px); display: flex; align-items: center; overflow: hidden; }
.gs-wrap { position: relative; z-index: 3; width: 100%; max-width: 1100px; margin: 0 auto; padding: 5rem 1.6rem; }
.gs-eyebrow { font-size: .72rem; letter-spacing: .3em; color: var(--cyan); margin: 0 0 1.4rem; }

/* Signal, Bestand, Portal rücken enger zusammen — gut halbe Bildschirmhöhe
   statt fast voller Höhe wie die übrigen Kapitel. */
#ch-field, #ch-ticker, #ch-portal { min-height: min(62vh, 620px); min-height: min(62svh, 620px); }
#ch-field .gs-wrap, #ch-portal .gs-wrap { padding: 2.6rem 1.6rem; }

/* Kapitel 1 — Die Zahl.
   Liegt seit dem Umbau nicht mehr als eigene Sektion mit eigenem Hintergrund
   hier, sondern als .gs-beat--stats direkt im Film (siehe oben) — den
   sichtbaren Hintergrund liefert dort automatisch das Kernbild selbst, auf
   dem der Film in seiner Haltezone stehen bleibt. Die folgenden Regeln
   gestalten nur noch die Zahl selbst, nicht mehr ihren Hintergrund. */
.gs-huge {
  position: relative;
  font-family: "Anton", sans-serif;
  /* War clamp(5rem,24vw,22rem) — passte zur alten, eigenstaendigen Sektion mit
     1100px breitem .gs-wrap. Als Beat auf dem Film braucht die Zahl eine
     Groesse, die auf typischen Desktop-Breiten sicher in einer Zeile bleibt
     (siehe white-space unten), auch wenn die Gesamtstundenzahl noch auf
     sechs Stellen waechst. */
  font-size: clamp(3.5rem, 13vw, 15rem); line-height: .82;
  color: #fff; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Der warme Schein lag früher als text-shadow direkt auf den Ziffern —
   seit die Zahl aus Walzen mit overflow:hidden besteht, schnitt das den
   Schein an jeder Walzenkante ab. Jetzt liegt er als eigenes Element
   hinter der gesamten Zahl, ausserhalb der beschneidenden Walzen. */
.gs-huge::before {
  content: ""; position: absolute; inset: -35% -12%; z-index: -1;
  pointer-events: none;
  background: radial-gradient(52% 52% at 50% 50%, rgba(255,164,61,.30), transparent 70%);
}
.gs-under { font-size: clamp(.9rem, 1.6vw, 1.2rem); color: var(--dim); margin: 1.6rem 0 0; }
.gs-under span { color: var(--amber); }

/* Walzenzähler: jede Ziffer ist ein 1em hohes Sichtfenster über einem
   Streifen aus Ziffern 0–9; verschoben per translateY auf dem <i>. Bleibt
   ohne Skript unangetastet — der fertige Zahlentext steht dann einfach da. */
.gs-od { display: inline-block; overflow: hidden; height: 1em; vertical-align: bottom; }
.gs-od i { display: block; font-style: normal; }
.gs-od i b { display: block; height: 1em; line-height: 1; font-weight: inherit; font-style: normal; }
.gs-od-sep { display: inline-block; }

/* Kapitel 2 — Der Name.
   Der schwarze Block liegt über dem Canvas und wird per multiply gemischt:
   Schwarz bleibt schwarz und deckt ab, Weiß lässt den Film durch. Dadurch
   läuft der Film exakt in den Buchstaben. */
.gs-ch--type { background: #000; isolation: isolate; padding: 0; }
.gs-type-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Rückfallebene, wenn kein Filmframe gezeichnet werden kann: animiertes Chrom.
   Muss als zentriertes Quadrat gesetzt werden (nicht per inset auf ein
   Rechteck): ein rotierendes Rechteck deckt seine Fläche in jeder Drehlage
   nicht ab. 150vmax ist mindestens die Diagonale jeder Sektion. */
.gs-ch--type::before {
  background: conic-gradient(from 0deg, #0b0d14, #6a7488, #EAEEF5, #6a7488, #0b0d14, #2a3040, #EAEEF5, #0b0d14);
}
/* WICHTIG: hier NICHT display:none verwenden. Das Canvas muss von Anfang an
   eine Größe haben, sonst ist clientWidth 0, es kann nichts gezeichnet werden,
   die Klasse gs-filmtext wird nie gesetzt — und das Canvas bliebe für immer
   versteckt. Ein klassischer Verklemmungsfehler. */
body:not(.gs-filmtext) .gs-type-canvas { opacity: 0; }
body.gs-filmtext .gs-type-canvas { opacity: 1; transition: opacity .5s ease; }
body.gs-filmtext .gs-ch--type::before { display: none; }

.gs-type-knock {
  position: absolute; inset: 0; z-index: 3;
  display: grid; place-items: center;
  background: #000; mix-blend-mode: multiply;
}
.gs-type-knock span {
  font-family: "Anton", sans-serif; color: #fff;
  font-size: clamp(3.4rem, 17vw, 16rem); line-height: .84; letter-spacing: .02em;
  text-align: center;
}
/* Weiche Ränder: die Sektion läuft ins Schwarz der Nachbarn aus statt hart
   anzusetzen. Muss über der Knockout-Ebene (z-index 3) liegen, sonst hat der
   Verlauf keine sichtbare Wirkung — daher z-index 5. ::after ist damit
   belegt, ::before trägt bereits den Chrom-Verlauf: keine weiteren
   Pseudo-Elemente auf dieser Sektion einplanen. */
.gs-ch--type::after {
  content: ""; position: absolute; inset: 0; z-index: 5; pointer-events: none;
  background: linear-gradient(to bottom,
    var(--void) 0%, rgba(5,6,10,0) 17%,
    rgba(5,6,10,0) 83%, var(--void) 100%);
}

/* Kapitel 3 — Querlauf */
.gs-ch--run { background: var(--void); }
.gs-run-track { display: flex; gap: 2.4rem; align-items: center; padding: 0 8vw; width: max-content; }
.gs-plate {
  position: relative; flex: 0 0 auto;
  width: clamp(280px, 30vw, 430px); aspect-ratio: 3 / 4;
  border: 1px solid rgba(234,238,245,.14); border-radius: 6px;
  overflow: hidden; background: #0A0C12;
  display: flex; flex-direction: column; justify-content: flex-end; padding: 1.4rem;
  transform-style: preserve-3d; will-change: transform;
}
.gs-plate::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: radial-gradient(90% 70% at 50% 12%, var(--accent), transparent 70%);
  opacity: .34;
}
.gs-plate img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .35; }
/* Monogramm ist nur noch ein schwaches Wasserzeichen hinter der Typografie,
   nicht mehr das Hauptmotiv der Karte. */
.gs-plate-mark {
  position: absolute; top: -4%; right: -3%; z-index: 0; text-align: right;
  font-family: "Anton", sans-serif; font-size: clamp(5rem, 15vw, 11rem);
  color: var(--accent); opacity: .12; line-height: 1; pointer-events: none;
}
.gs-plate-body { position: relative; z-index: 2; }
.gs-plate h3 {
  margin: 0 0 1rem; font-family: "Anton", sans-serif; font-weight: 400;
  font-size: clamp(1.5rem, 2.6vw, 2.3rem); line-height: 1.05; color: #fff;
}
.gs-plate-stats { display: flex; gap: 1.6rem; }
.gs-plate-stats > div { display: flex; flex-direction: column; gap: .3rem; }
.gs-plate-label { font-size: .68rem; letter-spacing: .18em; color: var(--dim); }
.gs-plate-value {
  font-family: "JetBrains Mono", monospace; font-weight: 600;
  font-size: clamp(1.15rem, 1.9vw, 1.6rem); color: var(--accent);
}

/* Kapitel 4 — Das Feld */
.gs-ch--field { background: var(--void); }
.gs-field-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.gs-field-text {
  font-family: "Anton", sans-serif; font-weight: 400;
  font-size: clamp(2rem, 6.5vw, 5.4rem); line-height: 1.02; margin: 0;
  max-width: 18ch; text-shadow: 0 2px 50px rgba(5,6,10,.9);
}

/* Kapitel 5 — Der Ticker */
.gs-ch--ticker { background: var(--void); flex-direction: column; justify-content: center; gap: .8rem; padding: 2.6rem 0; }
.gs-ticker-row { width: 100%; overflow: hidden; will-change: transform; }
.gs-ticker-inner { display: flex; width: max-content; gap: 3rem; }
.gs-ticker-inner span {
  font-family: "Anton", sans-serif; font-size: clamp(2.6rem, 8vw, 7rem);
  line-height: 1.1; color: transparent;
  -webkit-text-stroke: 1px rgba(234,238,245,.34);
  white-space: nowrap;
}
/* Farbe rein: Zeile 1 in Cyan, Zeile 2 gefüllt in Magenta, Zeile 3 in Bernstein. */
#ticker-1 span { -webkit-text-stroke: 1px var(--cyan); }
#ticker-2 span { color: rgba(255,61,175,.5); -webkit-text-stroke: 0; }
#ticker-3 span { -webkit-text-stroke: 1px var(--amber); }

/* Kapitel 6 — Das Portal */
.gs-ch--portal { background: var(--void); text-align: center; }
.gs-ch--portal::before {
  background: conic-gradient(from 0deg, transparent, rgba(34,224,214,.16), transparent 40%, rgba(255,164,61,.16), transparent 70%);
}
/* Beide rotierenden Rückfallebenen (Portal + Chrom hinter dem Schriftzug):
   zentriertes Quadrat statt inset-Rechteck, Rotation von der Skalierung
   getrennt. Siehe Kommentar bei .gs-ch--type::before. */
.gs-ch--portal::before,
.gs-ch--type::before {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  left: 50%; top: 50%;
  width: 150vmax; height: 150vmax;
  margin: -75vmax 0 0 -75vmax;
  animation: gs-rotate 22s linear infinite;
}
@keyframes gs-rotate { to { transform: rotate(1turn); } }
/* Zweite Ebene, die den rotierenden Verlauf zusätzlich pulsieren lässt —
   eigenes Pseudo-Element, weil eine zweite Animation auf derselben Ebene
   deren transform (die Rotation) sonst ersetzen statt ergänzen würde. */
.gs-ch--portal::after {
  content: ""; position: absolute; inset: -40%;
  background: conic-gradient(from 0deg, transparent, rgba(34,224,214,.16), transparent 40%, rgba(255,164,61,.16), transparent 70%);
  animation: gs-portal-pulse 4s ease-in-out infinite alternate;
}
@keyframes gs-portal-pulse {
  from { opacity: .5; transform: scale(1); }
  to   { opacity: 1; transform: scale(1.12); }
}
.gs-portal {
  position: relative; display: inline-block; overflow: hidden;
  padding: 1.3rem 3rem; border-radius: 999px;
  font-size: 1rem; font-weight: 600; letter-spacing: .06em; color: var(--void);
  background: linear-gradient(90deg, var(--cyan), var(--amber));
  box-shadow: 0 0 90px rgba(34,224,214,.45);
  transition: box-shadow .25s ease; will-change: transform;
  animation: gs-portal-btn-pulse 3s ease-in-out infinite alternate;
}
@keyframes gs-portal-btn-pulse {
  from { box-shadow: 0 0 90px rgba(34,224,214,.45); }
  to   { box-shadow: 0 0 120px rgba(34,224,214,.65); }
}
.gs-portal span { position: relative; z-index: 2; }
.gs-portal::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: -60%; width: 40%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.75), transparent);
  transform: skewX(-18deg); transition: left .7s var(--ease);
}
.gs-portal:hover::after { left: 120%; }
.gs-portal:hover { box-shadow: 0 0 80px rgba(255,164,61,.45); }

.footer-name { color: var(--chrome); }
.footer-tag, .social-link { color: var(--dim); }
.social-link:hover { color: var(--cyan); border-color: var(--cyan); }

/* ---------- Ruhezustand ----------
   Greift bei prefers-reduced-motion und wenn GSAP fehlt (Klasse gs-still). */
@media (prefers-reduced-motion: reduce) {
  .gs-film { height: auto; }
  .gs-stage { position: relative; height: auto; min-height: 80vh; min-height: 80svh; }
  .gs-beat { position: relative; left: auto; right: auto; top: auto; transform: none; padding: 4rem 8vw; max-width: none; text-align: left; }
  .gs-beat--mid { text-align: left; }
  .gs-beat--stats { text-align: center; }
  #film-canvas, .gs-grain, .gs-field-canvas { display: none; }
  .gs-ch--type::before, .gs-ch--portal::before { animation: none; }
  .gs-ch--portal::after, .gs-portal { animation: none; }
}
body.gs-still .gs-film { height: auto; }
body.gs-still .gs-stage { position: relative; height: auto; min-height: 80vh; min-height: 80svh; }
body.gs-still .gs-beat { position: relative; left: auto; right: auto; top: auto; transform: none; opacity: 1 !important; visibility: visible !important; padding: 4rem 8vw; max-width: none; text-align: left; }
body.gs-still .gs-beat--stats { text-align: center; }
body.gs-still #film-canvas, body.gs-still .gs-field-canvas { display: none; }
body.gs-still .gs-ch--type::before, body.gs-still .gs-ch--portal::before { animation: none; }
body.gs-still .gs-ch--portal::after, body.gs-still .gs-portal { animation: none; }
body.gs-still .gs-run-track { flex-wrap: wrap; width: auto; justify-content: center; }
body.gs-still .gs-ticker-inner { flex-wrap: wrap; width: auto; justify-content: center; }
body.gs-still .gs-loader { display: none; }

@media (max-width: 760px) {
  .gs-beat { left: 6vw; right: 6vw; max-width: none; }
  .gs-beat--mid { text-align: left; }
  /* Ohne diese left/right-Ausnahme wuerde die Zeile darueber (.gs-beat
     left:6vw; right:6vw) die Bilanz genauso links/rechts einspannen wie die
     beiden Textzeilen — kombiniert mit translateX(-50%) aus der Basisregel
     laege sie dann weit ausserhalb des Bildschirms statt mittig. */
  .gs-beat--stats { left: 50%; right: auto; max-width: none; text-align: center; }
  .gs-run-track { padding: 0 6vw; }

  /* Kopfzeile: rechnete sich auf 11,5px herunter, jetzt lesbar. */
  .gs-head { font-size: .78rem; padding: 1.1rem 1.1rem; }

  /* 420svh sind auf dem Handy rund 3400px Scrollweg fuer 10 Sekunden Film —
     das verlangt sehr viel Daumen. Die Haltezone am Ende bleibt unveraendert,
     weil sie in der Engine aus innerHeight berechnet wird. */
  .gs-film { height: 320vh; height: 320svh; }

  /* Acht Karten a 280px ergeben einen zaehen gepinnten Querlauf auf dem
     Handy. Schmalere Karten verkuerzen den Lauf, ohne die Schriftgroessen
     auf der Karte zu veraendern (die haengen an vw des Viewports, nicht an
     der Kartenbreite). */
  .gs-plate { width: 240px; }
}
