/* ============================================================
   scroll-fx — Zustaende der Scroll-Animationen
   Gehoert zu js/scroll-fx.js; die Attribut-Schnittstelle ist dort im
   Dateikopf dokumentiert.

   Der versteckte Startzustand steht statisch hier im CSS, sonst blitzt der
   Inhalt vor dem Skriptstart kurz auf. Damit daraus kein dauerhaft
   unsichtbares Element werden kann, traegt er eine Notbremse: [data-reveal]
   laeuft nach 2 s von selbst in den sichtbaren Zustand. scroll-fx.js setzt
   beim Uebernehmen sofort data-sfx, und [data-reveal][data-sfx] schaltet die
   Notbremse wieder ab — sie greift also nur, wenn das Skript ausfaellt.
   ============================================================ */

:root{
  --sfx-ease: cubic-bezier(.16,1,.3,1);   /* identisch zu --ease-out der Seiten */
  --sfx-dur: 1.05s;                       /* Opacity */
  --sfx-dur-move: 1.2s;                   /* Transform */
  --sfx-dur-line: 1.15s;                  /* Masked-Line */
  --sfx-step: 100ms;                      /* ein Staffelschritt */
  --sfx-shift: 30px;                      /* Weg fuer up */
  --sfx-shift-x: 32px;                    /* Weg fuer left/right */
}

/* ---------- Startzustand ----------
   Bewusst in zwei Bloecke geteilt:

   (a) Die Variablen stehen mit EINFACHER Spezifitaet da, damit eine Seite sie
       gezielt umstellen kann (z. B. index.html: .step[data-reveal] dreht den
       Startpunkt unter 769 px von seitlich auf von-unten).

   (b) Die Wirkung steht doppelt gewichtet ([data-reveal][data-reveal]). Eine
       Seitenregel wie .beispiel{transition:transform .5s} haette sonst gleiche
       Spezifitaet, stuende spaeter und wuerde die transition-Kurzform komplett
       ersetzen — das Element spraenge dann ohne Ueberblendung und ohne
       Staffelung herein. So braucht es dafuer kein !important. */
[data-reveal]{
  --sfx-from: translate3d(0,var(--sfx-shift),0);
  --sfx-op: 0;
}
[data-reveal][data-reveal]{
  opacity: var(--sfx-op);
  transform: var(--sfx-from);
  transition:
    opacity var(--sfx-dur) var(--sfx-ease) var(--sfx-delay,0ms),
    transform var(--sfx-dur-move) var(--sfx-ease) var(--sfx-delay,0ms);
  /* Notbremse, siehe Dateikopf */
  animation: sfx-failsafe 1ms linear 2s forwards;
}

/* Varianten: nur Startpunkt und Start-Deckkraft, nie das Timing.
   Der Wert ist eine Wortliste, "up line" ist also erlaubt — deshalb ~= . */
[data-reveal~="fade"] { --sfx-from: none; }
[data-reveal~="scale"]{ --sfx-from: scale(.94); }
[data-reveal~="left"] { --sfx-from: translate3d(calc(-1 * var(--sfx-shift-x)),0,0); }
[data-reveal~="right"]{ --sfx-from: translate3d(var(--sfx-shift-x),0,0); }
[data-reveal~="grow-x"]{ --sfx-from: scaleX(.4); --sfx-op: .35; }
/* "line" allein bewegt nur die Innenzeile; das Element selbst bleibt
   sichtbar, damit Headlines keinen doppelten Fade bekommen. In Kombination
   ("up line") gilt weiter der Auftritt der jeweils anderen Variante. */
[data-reveal="line"] {
  --sfx-from: none; --sfx-op: 1;
  /* Kleiner Versatz, damit die Headline der Flaeche folgt statt mit ihr
     gleichzeitig zu starten (frueher: .reveal.visible h2 .mask-inner). */
  --sfx-delay: 60ms;
}

/* ---------- scroll-fx.js hat uebernommen ----------
   Gleiche Spezifitaet wie der Basisblock oben, steht aber spaeter — damit
   gewinnt hier die Reihenfolge, wie es sein soll. */
[data-reveal][data-sfx]{ animation: none; }
[data-reveal][data-sfx="armed"]{ will-change: opacity, transform; }
[data-reveal][data-sfx="in"]{
  opacity: 1; transform: none;
  will-change: opacity, transform;
}
/* "done" wird ~2,4 s nach dem Start gesetzt und nimmt will-change wieder
   weg — sonst haelt der Browser fuer jedes animierte Element dauerhaft
   einen Compositing-Layer vor. */
[data-reveal][data-sfx="done"]{
  opacity: 1; transform: none;
  will-change: auto;
}

@keyframes sfx-failsafe{ to{ opacity:1; transform:none; } }

/* ---------- Erster Bildschirm (data-reveal-eager) ----------
   Diese Elemente warten auf keinen Trigger. Ihr Auftritt steckt deshalb in
   einer Animation statt in einer Uebergangs-Eigenschaft: sie laeuft mit dem
   ersten Bild los und braucht dafuer kein Skript. Faellt scroll-fx.js aus
   oder kommt es spaet, ist der Bereich trotzdem nach seinem normalen Auftritt
   da statt erst nach der 2-Sekunden-Notbremse.

   Steht bewusst NACH [data-reveal][data-sfx]{animation:none} und wiegt bei
   gleicher Spezifitaet durch die Reihenfolge schwerer — sonst wuerde das
   Uebernehmen des Skripts den laufenden Auftritt abschneiden. Der
   fill-mode both haelt Anfangs- und Endbild, damit weder die versteckte
   Grundregel darueber noch ein spaeter Zustandswechsel dazwischenfunkt. */
[data-reveal-eager] [data-reveal],
[data-reveal][data-reveal-eager]{
  animation: sfx-eager-in var(--sfx-dur-move) var(--sfx-ease) var(--sfx-delay,0ms) both;
}
@keyframes sfx-eager-in{
  from{ opacity: var(--sfx-op); transform: var(--sfx-from); }
  to{ opacity: 1; transform: none; }
}

/* ---------- Staffelschritte ----------
   Als Regeln statt als Inline-Style: so muss scroll-fx.js beim Start keine
   Style-Eigenschaft pro Element schreiben. */
[data-reveal-delay="1"]{ --sfx-delay: 100ms; }
[data-reveal-delay="2"]{ --sfx-delay: 200ms; }
[data-reveal-delay="3"]{ --sfx-delay: 300ms; }
[data-reveal-delay="4"]{ --sfx-delay: 400ms; }
[data-reveal-delay="5"]{ --sfx-delay: 500ms; }
[data-reveal-delay="6"]{ --sfx-delay: 600ms; }
[data-reveal-delay="7"]{ --sfx-delay: 700ms; }
[data-reveal-delay="8"]{ --sfx-delay: 800ms; }

/* ---------- Masked-Line (data-reveal="line") ----------
   Wrapper baut scroll-fx.js zur Laufzeit; ohne Skript existiert er nicht
   und die Headline steht ganz normal da. */
.sfx-line{ display:block; overflow:hidden; }
.sfx-line-inner{
  display:block;
  transform: translate3d(0,108%,0);
  transition: transform var(--sfx-dur-line) var(--sfx-ease) var(--sfx-delay,0ms);
  will-change: transform;
}
[data-sfx="in"] > .sfx-line > .sfx-line-inner,
[data-sfx="done"] > .sfx-line > .sfx-line-inner{ transform: none; }
[data-sfx="done"] > .sfx-line > .sfx-line-inner{ will-change: auto; }

/* ---------- Scrub (scroll-gekoppelt, braucht GSAP+ScrollTrigger) ---------- */
[data-scrub]{ will-change: transform; }

/* ---------- Reduzierte Bewegung ----------
   Harte Abschaltung: keine Animation, kein Uebergang, nichts versetzt.
   !important, weil das die Barrierefreiheits-Notbremse ist und ueber
   jeder Seiten-Regel stehen muss. */
@media (prefers-reduced-motion: reduce){
  [data-reveal],
  [data-reveal][data-sfx],
  .sfx-line-inner{
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
    will-change: auto !important;
  }
  [data-scrub]{ transform: none !important; opacity: 1 !important; will-change: auto !important; }
}
