/* ============================================================
   MOTION — 1:1 nachgebaute Framer-Bewegungen
   ------------------------------------------------------------
   Gemessene Originalwerte:

   Überschrift (Wortreveal)
     from: opacity .001 | blur(10px) | translateY(10px)
     to:   opacity 1    | blur(0)    | translateY(0)
     1800ms · Feder (kritisch gedämpft) · 50ms Versatz je Wort

   Fließtext (Wortreveal)
     wie oben, aber blur(6px) und 1400ms

   Scroll-Scrub
     color: rgba(0,0,0,.1) → #111, 300ms linear, pro Wort
     an den Scrollfortschritt gekoppelt

   3D-Karte
     perspective(1200px) translateY(110px) scale(.52) rotateY(360deg)
     → translateY(0) scale(1) rotateY(180deg)

   UI-Zustände
     color                      300ms linear
     background, box-shadow     200ms cubic-bezier(.44,0,.56,1)
   ============================================================ */

/* ---------- WORT-REVEAL --------------------------------------------
   .reveal setzt bewusst KEIN display — das Element behält seinen
   natürlichen Fluss (h2 bleibt Block). Animiert wird nur je Wort. */
.reveal .word {
  display: inline-block;
  white-space: pre;
  opacity: 0.001;
  filter: blur(var(--blur-text));
  transform: translateY(var(--lift));
  will-change: opacity, filter, transform;
  transition:
    opacity   var(--d-reveal-text) var(--ease-spring) var(--delay, 0ms),
    filter    var(--d-reveal-text) var(--ease-spring) var(--delay, 0ms),
    transform var(--d-reveal-text) var(--ease-spring) var(--delay, 0ms);
}

/* Überschriften: stärkerer Blur, längere Feder */
.reveal--title .word {
  filter: blur(var(--blur-title));
  transition-duration: var(--d-reveal-title);
}

.reveal.is-in .word {
  opacity: 1;
  filter: blur(0px);
  transform: translateY(0);
}

/* Nach Abschluss die Compositing-Ebene wieder freigeben */
.reveal.is-done .word { will-change: auto; }


/* ---------- STICKY-STACK -------------------------------------------
   Der Hero ist 100vh hoch und bleibt am oberen Rand kleben, während
   die About-Sektion darüber hinwegschiebt. Der gemeinsame Container
   ist doppelt so hoch (200vh), Hero und About je 100vh.
   Gemessen im Original: Hero pinnt exakt 900px = eine Viewporthöhe. */
.stack { position: relative; }


.stack__over {
  position: relative;
  z-index: 2;
  background: var(--bg);
}

/* ---------- GEPINNTE SCRUB-SEKTION ---------------------------------
   Wrapper 150vh, Inhalt 100vh gepinnt → 50vh Pin-Distanz, über die
   sich der Text Wort für Wort einfärbt. Im Original: 1350 / 900. */
.pin-section { position: relative; height: 150svh; }

.pin-section__inner {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* ---------- SCROLL-SCRUB (Wort-für-Wort-Einfärbung) ----------------- */
/* Kein will-change: color — Farbe läuft ohnehin über Paint, der Hinweis
   bringt nichts und hielt 13 Elemente dauerhaft als Sonderfall. */
.scrub .word {
  display: inline-block;
  white-space: pre;
  color: var(--scrub-from);
  transition: color var(--d-color) linear;
}

.scrub .word.is-lit { color: var(--scrub-to); }

/* Hervorhebung im Scrub-Satz: das entscheidende Wort läuft nicht auf
   Tinte, sondern auf den dunklen Bernstein aus dem Hero (5,5:1 auf
   Creme). Höhere Spezifität als .scrub .word.is-lit — sonst bliebe es
   schwarz. */
.scrub .hl { font-style: normal; }
.scrub .hl .word.is-lit { color: var(--c-amber-deep); }

/* ---------- 3D-FLIP-KARTE ------------------------------------------ */
.flip {
  perspective: var(--perspective);
  transform-style: preserve-3d;
}

.flip__inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform: translateY(110px) scale(0.52) rotateY(360deg);
  will-change: transform;
  transition: transform 1400ms var(--ease-spring);
}

.flip.is-in .flip__inner { transform: translateY(0) scale(1) rotateY(180deg); }

.flip__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: var(--r-card);
  overflow: hidden;
}

.flip__face--back { transform: rotateY(180deg); }

/* Dauerrotation beim Hovern der Hero-Karte */
.flip:hover .flip__inner { transform: translateY(0) scale(1) rotateY(540deg); }

/* ---------- EINFACHER BLOCK-REVEAL (Karten, Bilder, Zeilen) --------- */
.rise {
  opacity: 0.001;
  filter: blur(var(--blur-text));
  transform: translateY(24px);
  will-change: opacity, filter, transform;
  transition:
    opacity   var(--d-reveal-text) var(--ease-spring) var(--delay, 0ms),
    filter    var(--d-reveal-text) var(--ease-spring) var(--delay, 0ms),
    transform var(--d-reveal-text) var(--ease-spring) var(--delay, 0ms);
}

.rise.is-in {
  opacity: 1;
  filter: blur(0px);
  transform: translateY(0);
}

/* Wie bei den Wörtern: nach dem Durchlauf die Compositing-Ebene wieder
   freigeben. Fehlte hier — die Blöcke blieben bis zum Seitenwechsel
   als eigene Ebene stehen. Das .is-done setzt derselbe Observer. */
.rise.is-done { will-change: auto; }

/* Sanftere Variante nach der Footer-Vorlage: kommt von oben statt von
   unten, kürzerer Weg, 800ms. */
.rise--soft {
  filter: blur(4px);
  transform: translateY(-8px);
  transition-duration: 800ms;
}

/* Unter 900px kein Weichzeichner: der animierte Blur auf rund 110
   Wort-Spans ist das GPU-teuerste der Seite, und auf Mittelklasse-
   Handys sichtbar. Opacity und Versatz laufen weiter — der Eindruck
   bleibt, die Kosten fallen. */
@media (max-width: 900px) {
  .reveal .word,
  .reveal--title .word,
  .reveal.is-in .word,
  .rise,
  .rise.is-in { filter: none; will-change: opacity, transform; }
}

/* ---------- REDUZIERTE BEWEGUNG ------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .reveal .word,
  .rise {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
    transition: none !important;
  }

  .scrub .word { color: var(--scrub-to); transition: none; }

  .flip__inner,
  .flip:hover .flip__inner {
    transform: rotateY(180deg);
    transition: none;
  }


  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
