/* ============================================================
   MOTION-SYSTEM — CSS-Seite
   Technik-Entscheidung (siehe docs/ENTSCHEIDUNGEN.md):
   Natives CSS + IntersectionObserver + rAF. Kein GSAP.
   Alle Bausteine respektieren prefers-reduced-motion.
   ============================================================ */

/* ---------- 1. SECTION REVEAL ----------
   data-reveal            → fade + rise
   data-reveal="left"     → von links
   data-reveal="right"    → von rechts
   data-reveal="scale"    → sanfter Zoom
   JS setzt .is-inview beim Eintritt in den Viewport. */
/* Versteckte Ausgangszustände gelten erst, wenn das Motion-JS läuft
   (html.motion-ready). Ohne JavaScript bleibt alles sichtbar. */
.motion-ready [data-reveal] {
  opacity: 0;
  transform: translateY(var(--reveal-distance));
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.motion-ready [data-reveal="left"]  { transform: translateX(calc(-1 * var(--reveal-distance))); }
.motion-ready [data-reveal="right"] { transform: translateX(var(--reveal-distance)); }
.motion-ready [data-reveal="scale"] { transform: scale(0.94); }
[data-reveal].is-inview {
  opacity: 1;
  transform: none;
}

/* ---------- 2. STAGGER REVEAL ----------
   data-stagger auf dem Container: Kinder erscheinen nacheinander.
   JS vergibt --reveal-delay je Kind (stagger-step-Token). */
.motion-ready [data-stagger] > * {
  opacity: 0;
  transform: translateY(var(--reveal-distance));
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-stagger].is-inview > * { opacity: 1; transform: none; }

/* ---------- 3. TEXT REVEAL ----------
   data-reveal-text: JS zerlegt in Zeilen-Spans (.line > .line-inner),
   die maskiert nach oben einfahren. Große Headline-Momente. */
[data-reveal-text] .line { display: block; overflow: clip; }
[data-reveal-text] .line-inner {
  display: block;
  transform: translateY(110%);
  transition: transform calc(var(--dur-reveal) * 1.1) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal-text].is-inview .line-inner { transform: none; }

/* ---------- 4. IMAGE REVEAL / MASK ----------
   data-reveal-mask auf .media: Vorhang zieht sich auf,
   Bild fährt aus leichtem Zoom zurück. */
[data-reveal-mask] {
  position: relative;
  --mask-c: var(--reveal-mask-color, var(--c-bg));
}
.motion-ready [data-reveal-mask]::after {
  content: ""; position: absolute; inset: 0;
  background: var(--mask-c);
  transform: scaleX(1); transform-origin: right;
  transition: transform calc(var(--dur-reveal) * 1.2) var(--ease-in-out);
  transition-delay: var(--reveal-delay, 0ms);
  z-index: 1;
}
.motion-ready [data-reveal-mask] img,
.motion-ready [data-reveal-mask] video {
  transform: scale(1.15);
  transition: transform calc(var(--dur-reveal) * 1.6) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal-mask].is-inview::after { transform: scaleX(0); }
[data-reveal-mask].is-inview img,
[data-reveal-mask].is-inview video { transform: scale(1); }

/* ---------- 5. PARALLAX ----------
   data-parallax="0.15" → Element bewegt sich mit 15% der
   Scrollgeschwindigkeit gegenläufig. JS setzt --parallax-y via rAF.
   Dezent halten: 0.08–0.2. */
[data-parallax] {
  transform: translateY(var(--parallax-y, 0));
  will-change: transform;
}
/* Bild im Container leicht überdimensionieren, damit beim
   Verschieben keine Ränder aufreißen. */
.parallax-media { overflow: clip; }
.parallax-media > img, .parallax-media > video {
  height: 118%; width: 100%; object-fit: cover;
}

/* ---------- 6. STICKY SECTION / SCROLL-INSZENIERUNG ----------
   .sticky-scene: hoher Wrapper, inneres Panel bleibt stehen,
   Schritte (.scene-step) blenden nacheinander ein.
   JS setzt .is-active auf den aktuellen Schritt. */
.sticky-scene { position: relative; }
.sticky-scene .scene-panel {
  position: sticky; top: 0;
  min-height: 100vh; min-height: 100svh;
  display: flex; align-items: center;
  overflow: clip;
}
.scene-step {
  opacity: 0.25;
  transition: opacity var(--dur-base) var(--ease-out);
}
.scene-step.is-active { opacity: 1; }

/* Scroll-Progress im Hero (JS setzt --scroll-p 0..1):
   Hero-Inhalt weicht sanft nach oben und blendet aus. */
.hero-fade {
  opacity: calc(1 - var(--scroll-p, 0) * 1.3);
  transform: translateY(calc(var(--scroll-p, 0) * -60px));
}

/* ---------- 7. BILDWECHSEL (Crossfade-Rotation) ----------
   data-rotator: Kinder .rotator-item wechseln per Crossfade.
   JS steuert .is-current. */
[data-rotator] { position: relative; }
[data-rotator] .rotator-item {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity calc(var(--dur-slow) * 1.5) var(--ease-in-out);
}
[data-rotator] .rotator-item.is-current { opacity: 1; }

/* ---------- 8. COUNT-UP ----------
   data-countup="250" data-countup-suffix="+" — JS zählt hoch,
   sobald sichtbar. Kein CSS nötig außer tabellarischen Ziffern
   (bereits im .stat-value). */

/* ---------- REDUCED MOTION ----------
   Harte Garantie: Alles sofort sichtbar, nichts bewegt sich. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-reveal], [data-stagger] > *,
  [data-reveal-text] .line-inner,
  [data-reveal-mask] img, [data-reveal-mask] video {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  [data-reveal-mask]::after { display: none; }
  [data-parallax] { transform: none !important; }
  .hero-fade { opacity: 1; transform: none; }
  .marquee-track { animation: none; }
  .scene-step { opacity: 1; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
