/* ============================================================
   Chasing Dreams Interactive — Orbit

   Die Seite ist eine einzige Kamerafahrt. In der Mitte steht die
   Rüstung, fest im Bild; der Scroll dreht die Kamera einmal ganz
   um sie herum. Links und rechts ziehen die Projekte und Themen
   vorbei — jedes an seinem Punkt der Umrundung.

   Farbe kommt aus dem Bild selbst: assets/orbit/accents.json hält
   je Frame eine Leitfarbe, orbit.js schreibt sie als --accent.
   Alles hier drunter rechnet mit dieser einen Variable.

   Aufbau
     1  Grundlagen & Farben
     2  Bühne (fixer Hintergrund: Ambient, Säule, Glut)
     3  Kopfzeile
     4  Akte — das Raster aus Mitte und Seitenspalten
     5  Tafeln links/rechts
     6  Projekt-Karten
     7  Umrundungs-Leiste
     8  Fußzeile
     9  Schmale Viewports
    10  Reduzierte Bewegung, kein JS, Druck
   ============================================================ */

/* ---------- 1 · Grundlagen & Farben ---------- */

:root {
  /* Leitfarbe des aktuellen Frames — orbit.js aktualisiert sie beim
     Scrollen. Der Startwert ist die Farbe von Frame 0 (Feuerseite). */
  --accent: #e9556a;

  --ink: #f4f0ec;          /* warmes Weiß — Stahl im Feuerschein */
  --muted: #a8a09c;
  --faint: rgba(244, 240, 236, .34);
  --void: #08060a;         /* die Nacht hinter allem */
  --line: rgba(244, 240, 236, .12);

  --font-display: "Lora", Georgia, "Times New Roman", serif;
  --font-body: "Inter", system-ui, -apple-system, sans-serif;

  /* Maße der Säule. Die Bildsequenz ist 720 × 1237 (0.582). */
  --stage-h: min(84svh, 860px);
  --stage-w: calc(var(--stage-h) * 0.582);
  --gutter: clamp(20px, 4vw, 64px);
  --rail-w: 62px;

  /* Standbild für den Fall, dass die Sequenz nicht läuft */
  --poster: url("assets/orbit/poster.webp");
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  color-scheme: dark;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Der Riegel gegen jedes Wackeln zur Seite. hidden und nicht clip:
     clip wird am Wurzelelement nicht an den Viewport weitergegeben,
     die Seite ließe sich dann trotzdem schieben (gemessen in Chrome).
     position:fixed bleibt unberührt — das bezieht sich immer auf den
     Viewport, nicht auf das Wurzelelement. Die eigentlichen Ursachen
     sind unten abgestellt; das hier ist nur die Absicherung. */
  overflow-x: hidden;
}

body {
  background: var(--void);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; }

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

::selection { background: color-mix(in srgb, var(--accent) 45%, transparent); }

/* Kleintypografie: Kicker, Tags, Jahreszahlen */
.micro {
  font-size: .66rem;
  font-weight: 500;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--muted);
}

.num { font-variant-numeric: tabular-nums; }

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

/* ---------- 2 · Bühne ---------- */

#stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  contain: layout paint;
}
/* Mit JavaScript blendet die Bühne auf, sobald das erste Bild da ist. */
.js #stage { opacity: 0; transition: opacity 1.1s ease .1s; }
.js #stage.is-live { opacity: 1; }

/* Ambient-Licht: derselbe Frame, winzig gerendert und weich
   hochskaliert. Kostet fast nichts und färbt den ganzen Bildschirm
   in dem Licht, das gerade um die Rüstung herum liegt. */
#ambient {
  position: absolute;
  /* Etwas größer als der Bildschirm, damit die Unschärfe an den
     Rändern nicht ausläuft. Über inset statt über vw-Breite: so ist
     die Fläche an die Bühne gebunden und taucht in keiner Overflow-
     Rechnung des Dokuments auf. */
  inset: -7%;
  width: auto; height: auto;
  filter: blur(58px) saturate(1.5) brightness(.62);
  opacity: .82;
}

/* Die Säule: das scharfe Bild, mittig, im Hochformat des Clips. */
#column {
  position: absolute;
  left: 50%; top: 50%;
  width: var(--stage-w);
  height: var(--stage-h);
  translate: -50% -50%;
  /* --settle: 1 beim Auftakt (etwas größer), 0 danach */
  scale: calc(1 + .07 * var(--settle, 0));
  border-radius: clamp(14px, 1.6vw, 26px);
  overflow: hidden;
  background: var(--void) center / cover no-repeat;
  box-shadow:
    0 40px 120px -20px rgba(0, 0, 0, .82),
    0 0 0 1px rgba(244, 240, 236, .07),
    0 0 90px -10px color-mix(in srgb, var(--accent) 30%, transparent);
  will-change: scale;
}

/* Die Leinwand ist deckend (schneller), also verdeckt sie von Anfang
   an das winzige Vorschaubild im Hintergrund der Säule. Sie blendet
   deshalb erst auf, wenn wirklich ein Frame darin steht. */
#orbit {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity .5s ease;
}
#stage.is-drawn #orbit { opacity: 1; }

/* Im Auftakt liegt der Name über der Rüstung. Damit er lesbar bleibt,
   steht sie zunächst im Halbdunkel und tritt beim Weiterscrollen ins
   Licht — --settle läuft dabei von 1 auf 0. */
#column::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(6, 4, 8, .62);
  opacity: var(--settle, 0);
}

/* Der Rand der Säule verliert sich nach unten in der Nacht. */
#column::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(8, 6, 10, .42) 0%,
    transparent 22%,
    transparent 62%,
    rgba(8, 6, 10, .58) 100%);
}

/* Glut: feine Funken, die aufsteigen. */
#embers {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  mix-blend-mode: screen;
  opacity: .9;
}

/* Vignette + Filmkorn liegen über der Bühne, unter dem Inhalt. */
#veil {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(128% 96% at 50% 44%,
      transparent 42%,
      rgba(8, 6, 10, .55) 82%,
      rgba(8, 6, 10, .86) 100%);
}
#veil::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: .045;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>");
}

/* ---------- 3 · Kopfzeile ---------- */

/* Sprungmarke: mit der Tabulatortaste zuerst erreichbar, sonst unsichtbar. */
.skip {
  position: fixed;
  left: 50%; top: 10px;
  z-index: 60;
  translate: -50% -160%;
  padding: 12px 22px;
  border-radius: 999px;
  background: var(--ink);
  color: #100a0d;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: translate .25s ease;
}
.skip:focus-visible { translate: -50% 0; }

#site-head {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px var(--gutter);
  border-bottom: 1px solid transparent;
  transition: background .45s ease, border-color .45s ease, backdrop-filter .45s ease;
}
#site-head.is-scrolled {
  background: rgba(8, 6, 10, .58);
  border-bottom-color: var(--line);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
}

.brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; }
.brand-mark {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 80%, transparent);
  flex: none;
}
.brand-word {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: .98rem;
  letter-spacing: .06em;
  white-space: nowrap;
}

.site-nav { display: flex; gap: clamp(14px, 2.6vw, 32px); }
.site-nav a {
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  padding: 10px 2px;
  transition: color .25s ease;
}
.site-nav a:hover,
.site-nav a[aria-current="true"] { color: var(--ink); }

.lang-switch { display: flex; align-items: center; gap: 2px; flex: none; }
.lang-switch button {
  appearance: none;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: .64rem;
  font-weight: 500;
  letter-spacing: .16em;
  color: var(--muted);
  padding: 8px 7px;
  border-radius: 4px;
  transition: color .25s ease, background-color .25s ease;
}
.lang-switch button:hover { color: var(--ink); }
.lang-switch button[aria-pressed="true"] {
  color: var(--ink);
  background: rgba(244, 240, 236, .1);
}

/* ---------- 4 · Akte ---------- */

#scene { position: relative; z-index: 2; }

/* Drei Spalten: linke Seitenspalte, die Säule in der Mitte, rechte
   Seitenspalte. Die Mitte bleibt frei — dort steht die Rüstung. */
.act {
  position: relative;
  /* clip statt hidden: es entsteht kein Scroll-Container, es wird nur
     abgeschnitten. Ohne das ragen die Schleier hinter den Tafeln
     (.panel::before) über den Rand und die Seite ließe sich schieben —
     Pseudo-Elemente fallen bei der Fehlersuche leicht durchs Raster,
     weil sie in keiner Element-Liste auftauchen. */
  overflow: clip;
  min-height: 100svh;
  display: grid;
  grid-template-columns:
    minmax(0, 1fr)
    minmax(0, var(--stage-w))
    minmax(0, 1fr);
  align-items: center;
  /* Links und rechts gleich viel Rand — sonst liegt die mittlere
     Rasterspalte nicht über der Säule, die ja im Fenster mittig
     steht, und die rechten Tafeln rücken ihr auf die Schulter.
     Die Kapitelleiste am rechten Rand wird auf beiden Seiten
     eingerechnet. */
  padding: 96px calc(var(--gutter) + var(--rail-w));
  scroll-margin-top: 0;
}

/* Auftakt und Schluss dürfen die Mitte benutzen — dort steht der
   Text absichtlich vor der Rüstung. */
.act--center { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; }

/* ---------- 5 · Tafeln ---------- */

.panel {
  position: relative;
  max-width: 27rem;
  /* --t: -1 (noch unterwegs) … 0 (in der Mitte) … 1 (schon vorbei),
     --a: der Betrag davon. main.js schreibt beide beim Scrollen; der
     Betrag kommt fertig aus JS, damit hier kein abs() nötig ist.
     --side ist -1 links, +1 rechts: die Tafel kommt von außen und
     geht nach außen wieder hinaus. */
  --t: 0;
  --a: 0;
  --b: 0;
  --side: 1;
  opacity: clamp(0, calc(1 - var(--a) * 1.25), 1);
  /* Waagerecht immer nach außen (--a), senkrecht mit der Laufrichtung
     (--t): die Tafel steigt herein und zieht nach oben wieder ab. */
  transform:
    translate3d(calc(var(--a) * var(--side) * 3.4rem), calc(var(--t) * 1.2rem), 0);
  filter: blur(calc(var(--b) * 3px));
  will-change: transform, opacity;
}
/* Zur Säule hin bleibt Luft, nach außen darf die Tafel atmen. */
.act--left  .panel { grid-column: 1; justify-self: end;   --side: -1; padding-right: clamp(14px, 2.2vw, 44px); }
.act--right .panel { grid-column: 3; justify-self: start; --side:  1; padding-left:  clamp(14px, 2.2vw, 44px); }
.act--center .panel { --side: 0; max-width: 46rem; }

/* Weicher Schleier hinter dem Text — hält ihn lesbar, ohne dass
   eine Karte im Bild klebt. Nach außen greift er weiter aus als zur
   Säule hin, sonst legt er sich der Rüstung auf die Schulter. */
.panel::before {
  content: "";
  position: absolute;
  inset: -20% -12% -20% -20%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(8, 6, 10, .86), rgba(8, 6, 10, .5) 60%, transparent 100%);
}
.act--right .panel::before { inset: -20% -20% -20% -12%; }
.act--center .panel::before { inset: -26% -14%; }
.act--hero .panel::before {
  background: radial-gradient(closest-side,
    rgba(6, 4, 8, .9), rgba(6, 4, 8, .6) 58%, transparent 100%);
}

.panel-kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  color: color-mix(in srgb, var(--accent) 62%, var(--ink));
  text-shadow: 0 1px 14px rgba(8, 6, 10, .9);
}
.panel-kicker::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 55%, transparent), transparent);
}
.act--left .panel-kicker { flex-direction: row-reverse; }
.act--left .panel-kicker::after {
  background: linear-gradient(270deg,
    color-mix(in srgb, var(--accent) 55%, transparent), transparent);
}
.act--left .panel { text-align: right; }

/* In der Mitte sitzt die Zeile zwischen zwei Strichen. */
.act--center .panel-kicker,
.foot-cta .panel-kicker { justify-content: center; }

/* Dank und Beratungshinweis stehen dort, wo auch die Adresse steht —
   nach den Projekten, nicht davor. */
.foot-cta-copy {
  max-width: 34rem;
  margin: 20px auto 0;
  font-size: .92rem;
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}
.act--center .panel-kicker::before,
.foot-cta .panel-kicker::before,
.act--center .panel-kicker::after,
.foot-cta .panel-kicker::after {
  content: "";
  flex: 0 1 68px;
  height: 1px;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--accent) 55%, transparent));
}
.act--center .panel-kicker::after,
.foot-cta .panel-kicker::after {
  background: linear-gradient(270deg, transparent,
    color-mix(in srgb, var(--accent) 55%, transparent));
}

.panel-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.7rem, 3.1vw, 2.7rem);
  line-height: 1.16;
  letter-spacing: -.012em;
  margin-top: 18px;
  text-wrap: balance;
  text-shadow: 0 2px 30px rgba(8, 6, 10, .9);
}

.panel-copy {
  margin-top: 18px;
  max-width: 36ch;
  font-size: .95rem;
  line-height: 1.75;
  color: var(--muted);
  text-shadow: 0 1px 18px rgba(8, 6, 10, .9);
}
.act--left .panel-copy { margin-left: auto; }
.act--center .panel-copy { margin-inline: auto; }

/* Wortweises Aufhellen beim Heranscrollen: --lit steht auf der
   Überschrift und wandert beim Scrollen über die Wörter hinweg,
   --i ist die Position des einzelnen Wortes. */
.panel-title .wd {
  display: inline-block;
  opacity: clamp(.13, calc(var(--lit, 99) - var(--i)), 1);
}

/* ---------- Auftakt ---------- */

.act--hero { padding-top: 120px; }

.hero-kicker {
  color: rgba(244, 240, 236, .62);
  text-shadow: 0 2px 20px rgba(6, 4, 8, .95);
}

/* Der Namenszug ist aus demselben Material wie die Rüstung: polierter
   Stahl, von oben angeleuchtet. Die Wärme kommt nicht in den
   Buchstaben, sondern als Schein darum herum — die Farbe dafür hängt
   an --accent und wandert mit der Kamera mit. Ein Verlauf ins Warme
   *innerhalb* der Buchstaben war der erste Versuch; er färbte vor
   allem die Kleinbuchstaben rosa, weil deren x-Höhe genau in der
   unteren Hälfte des Verlaufs sitzt. */
#title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.1rem, 6.6vw, 5.1rem);
  line-height: 1.05;
  letter-spacing: -.004em;
  margin-top: 20px;
  text-wrap: balance;
  color: #ece5df;
  text-shadow:
    0 4px 60px rgba(8, 6, 10, .95),
    0 0 46px color-mix(in srgb, var(--accent) 38%, transparent);
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
  /* Der Verlauf sitzt auf jedem Buchstaben statt auf der Überschrift:
     die Buchstaben werden beim Auftakt einzeln bewegt, und ein Clip
     auf dem Elternelement folgt dieser Bewegung nicht überall. Weil
     alle Buchstaben gleich hoch stehen, sieht beides identisch aus. */
  #title .ch {
    background-image: linear-gradient(180deg,
      #ffffff 8%,
      #f4efea 44%,
      #ded6d0 80%,
      #c8bfb9 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
#title .w { display: inline-block; white-space: nowrap; }
#title .ch { display: inline-block; }

/* Auftakt: der Name baut sich einmal buchstabenweise auf. */
.js #title .ch {
  animation: rise .9s cubic-bezier(.2, .8, .2, 1) backwards;
  animation-delay: calc(var(--i) * 22ms + .3s);
}
.js .hero-kicker { animation: fade .9s ease .1s backwards; }
.js #tagline,
.js .scroll-cue { animation: fade 1s ease .85s backwards; }
@keyframes rise { from { opacity: 0; translate: 0 .7em; } }
@keyframes fade { from { opacity: 0; translate: 0 .4em; } }

#tagline {
  margin-top: 20px;
  font-size: clamp(.92rem, 1.8vw, 1.08rem);
  color: rgba(244, 240, 236, .76);
  text-shadow: 0 2px 24px rgba(6, 4, 8, .98);
}

.scroll-cue {
  position: absolute;
  bottom: clamp(24px, 5vh, 52px);
  left: 50%;
  translate: -50% 0;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: rgba(244, 240, 236, .68);
  text-shadow: 0 2px 18px rgba(6, 4, 8, .95);
  transition: color .25s ease;
}
.scroll-cue:hover { color: var(--ink); }
.scroll-cue-line {
  width: 1px; height: 42px;
  background: linear-gradient(180deg, var(--accent), transparent);
  animation: cue 2.6s ease-in-out infinite;
  transform-origin: top;
}
@keyframes cue {
  0%, 100% { scale: 1 .35; opacity: .4; }
  50%      { scale: 1 1;   opacity: 1; }
}

/* ---------- 6 · Projekt-Karten ---------- */

.work { display: block; text-decoration: none; }

.work-media {
  position: relative;
  display: block;
  margin-top: 24px;
  aspect-ratio: 16 / 10;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: #0c0a0d;
  box-shadow: 0 22px 54px -18px rgba(0, 0, 0, .8);
  transition: border-color .45s ease, box-shadow .45s ease;
}
.work-media img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: scale .8s cubic-bezier(.2, .8, .2, 1), filter .45s ease;
}
.work-media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(122% 94% at 50% 42%, transparent 58%, rgba(8, 6, 10, .16) 100%);
}

.work:hover .work-media,
.work:focus-visible .work-media {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow:
    0 22px 60px -18px rgba(0, 0, 0, .8),
    0 0 40px -12px color-mix(in srgb, var(--accent) 60%, transparent);
}
.work:hover .work-media img,
.work:focus-visible .work-media img { scale: 1.05; filter: brightness(1.08); }

.work-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.act--left .work-foot { flex-direction: row-reverse; }

.work-go {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}
.work-go .arrow { display: inline-block; transition: translate .35s cubic-bezier(.2, .8, .2, 1); }
.work:hover .work-go .arrow { translate: 5px 0; }
.act--left .work:hover .work-go .arrow { translate: -5px 0; }

.work-desc {
  display: block;
  font-size: .88rem;
  line-height: 1.6;
  color: var(--muted);
}

.work-badge { margin-top: 16px; line-height: 0; }
.act--left .work-badge { text-align: right; }
.work-badge img {
  max-width: 190px; height: auto;
  opacity: .6;
  transition: opacity .3s ease;
}
.work-badge a:hover img { opacity: 1; }

/* ---------- Schluss: der Aufruf steht in der Fußzeile ---------- */

.foot-cta {
  grid-column: 1 / -1;
  text-align: center;
  padding-bottom: clamp(28px, 5vh, 56px);
}
.foot-cta .panel-kicker { justify-content: center; }

/* Dank und Beratungshinweis stehen dort, wo auch die Adresse steht —
   nach den Projekten, nicht davor. */
.foot-cta-copy {
  max-width: 34rem;
  margin: 20px auto 0;
  font-size: .92rem;
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}

.cta-btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 36px;
  padding: 16px 34px;
  border-radius: 999px;
  background: var(--ink);
  color: #100a0d;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  text-decoration: none;
  transition: translate .3s ease, box-shadow .3s ease;
}
.cta-btn:hover {
  translate: 0 -2px;
  box-shadow: 0 12px 40px -10px color-mix(in srgb, var(--accent) 85%, transparent);
}

/* ---------- 7 · Umrundungs-Leiste ---------- */

.rail {
  position: fixed;
  z-index: 35;
  right: calc(var(--gutter) * .55);
  top: 50%;
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 4px;
}


.rail-track {
  --orbit: 0;
  position: relative;
  width: 1px;
  height: min(46vh, 380px);
  background: var(--line);
}
/* Der gefüllte Teil zeigt, wie weit die Umrundung ist. */
.rail-track::after {
  content: "";
  position: absolute;
  left: 0; top: 0;
  width: 1px;
  height: calc(var(--orbit) * 100%);
  background: linear-gradient(180deg,
    transparent, color-mix(in srgb, var(--accent) 90%, transparent));
}

/* Die Punkte sitzen dort, wo der jeweilige Akt wirklich anfängt —
   main.js rechnet --p beim Vermessen aus. */
.rail-dots { position: absolute; inset: 0; }
.rail-dots a {
  position: absolute;
  left: 50%;
  top: calc(var(--p, 0) * 100%);
  translate: -50% -50%;
  display: block;
  width: 24px; height: 24px;
  border-radius: 50%;
  text-decoration: none;
}
.rail-dots a::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  translate: -50% -50%;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: rgba(244, 240, 236, .28);
  transition: background-color .3s ease, scale .3s ease;
}
.rail-dots a:hover::before { background: var(--ink); scale: 1.3; }
.rail-dots a[aria-current="true"]::before {
  background: var(--accent);
  scale: 1.6;
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 90%, transparent);
}
/* Beschriftung erscheint links vom Punkt */
.rail-dots a span {
  position: absolute;
  right: 26px; top: 50%;
  translate: 0 -50%;
  white-space: nowrap;
  font-size: .6rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0;
  transition: opacity .3s ease, translate .3s ease;
  pointer-events: none;
}
.rail-dots a:hover span,
.rail-dots a:focus-visible span { opacity: 1; translate: -4px -50%; }

/* ---------- 8 · Fußzeile ---------- */

#contact {
  position: relative;
  z-index: 2;
  padding: 10vh max(var(--gutter), calc((100% - 1180px) / 2)) 44px;
  /* Keine Trennlinie: die Fußzeile läuft über die ganze Breite, ein
     Strich am oberen Rand würde der Rüstung quer übers Bild schneiden.
     Den Übergang macht der Verlauf darunter. */
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 28px 44px;
  align-items: start;
  /* Am Ende der Umrundung senkt sich die Nacht wieder über alles. */
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(8, 6, 10, .72) 24%,
    var(--void) 58%);
}
.foot-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.12rem;
  letter-spacing: .06em;
}
.foot-claim { margin-top: 6px; font-size: .82rem; color: var(--muted); }
.foot-nav { display: flex; flex-direction: column; gap: 8px; text-align: right; }
.foot-nav a {
  font-size: .8rem;
  color: var(--muted);
  text-decoration: none;
  padding: 6px 0;
  transition: color .25s ease;
}
.foot-nav a:hover { color: var(--ink); }
.foot-copy {
  grid-column: 1 / -1;
  padding-top: 18px;
  border-top: 1px solid rgba(244, 240, 236, .06);
  font-size: .72rem;
  color: rgba(244, 240, 236, .5);
}
/* Die KI-Offenlegung steht noch eine Stufe leiser als das Copyright —
   sie soll da sein, aber nicht das letzte Wort an sich reißen. */
.foot-ai {
  grid-column: 1 / -1;
  margin-top: 8px;
  max-width: 52ch;
  font-size: .7rem;
  line-height: 1.6;
  color: var(--faint);
}

/* ---------- 9 · Schmale Viewports ---------- */

/* Unter 1024px passen keine Seitenspalten mehr neben die Säule.
   Die Rüstung füllt dann formatfüllend den Hintergrund, der Inhalt
   liegt mittig darüber. */
@media (max-width: 1023px) {
  :root { --rail-w: 0px; }

  #column {
    width: 100%;
    height: 100%;
    border-radius: 0;
    scale: 1;
    box-shadow: none;
  }
  #ambient { opacity: .5; }
  #column::after {
    background: linear-gradient(180deg,
      rgba(8, 6, 10, .74) 0%,
      rgba(8, 6, 10, .5) 32%,
      rgba(8, 6, 10, .62) 68%,
      rgba(8, 6, 10, .88) 100%);
  }

  .act {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    padding: 88px var(--gutter);
    min-height: 96svh;
  }
  .act--hero { padding-top: 100px; }
  .act--left .panel,
  .act--right .panel {
    grid-column: 1;
    justify-self: center;
    text-align: left;
    /* Mittig stehende Tafeln fahren nur senkrecht ein. Seitwärts
       würden sie über den Bildschirmrand hinausragen. */
    --side: 0;
  }
  .act--left .panel-kicker { flex-direction: row; }
  .act--left .panel-kicker::after {
    background: linear-gradient(90deg,
      color-mix(in srgb, var(--accent) 55%, transparent), transparent);
  }
  .act--left .work-foot { flex-direction: row; }
  .act--left .work-badge { text-align: left; }
  .act--left .work:hover .work-go .arrow { translate: 5px 0; }

  .panel { max-width: 34rem; }
  .panel::before { inset: -14% -14%; }

  .rail { right: 8px; gap: 10px; }
  .rail-track { height: min(30vh, 220px); }
  .rail-dots a span { display: none; }
}

@media (max-width: 620px) {
  :root { --gutter: 20px; }
  body { font-size: 15px; }
  .brand-tail { display: none; }
  .site-nav { gap: 14px; }
  .site-nav a { font-size: .6rem; letter-spacing: .14em; }
  .panel-title { font-size: clamp(1.55rem, 7vw, 2.1rem); }
  #contact { grid-template-columns: 1fr; }
  .foot-nav { text-align: left; }
  .rail { display: none; }
}

/* Sehr flache Fenster: die Säule darf nicht über den Rand wachsen */
@media (min-width: 1024px) and (max-height: 620px) {
  :root { --stage-h: 90svh; }
}

/* ---------- 10 · Reduzierte Bewegung, kein JS, Druck ---------- */

/* Wer weniger Bewegung will, bekommt ein stehendes Bild statt der
   Kamerafahrt — und Tafeln, die einfach da sind. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  #embers { display: none; }
  .scroll-cue-line { animation: none; opacity: .7; }
  .js #title .ch,
  .js .hero-kicker,
  .js #tagline,
  .js .scroll-cue { animation: none; }
  .panel-title .wd { opacity: 1; }
  /* Die Kamera bleibt stehen (siehe orbit.js) — eine Gradzahl,
     die sich nie ändert, wäre nur verwirrend. */
  #column { scale: 1 !important; }
  .panel {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  .work-media img, .work-go span, .cta-btn { transition: none; }
}

/* Ohne JavaScript — und wenn die Sequenz nicht geladen werden kann —
   bleibt das Posterbild stehen und der Inhalt lesbar. */
.no-js #column,
.no-orbit #column { background-image: var(--poster); background-size: cover; }
.no-js #orbit,
.no-js #embers,
.no-js .rail,
.no-orbit #orbit { display: none; }
.no-js .panel { opacity: 1; transform: none; filter: none; }
.no-js .act { padding-inline: var(--gutter); }

@media print {
  #stage, #veil, .rail, #site-head { display: none; }
  body { background: #fff; color: #000; }
  .act { min-height: auto; display: block; padding: 24px 0; }
  .panel { opacity: 1 !important; transform: none !important; filter: none !important; max-width: none; }
}
