/* =====================================================================
   animations.css  –  Scroll-Reveals & Keyframes
   ---------------------------------------------------------------------
   Reveal-System wird von js/modules/reveal.js (IntersectionObserver)
   gesteuert: Elemente mit [data-reveal] starten versteckt und bekommen
   beim Eintritt die Klasse .is-in. Über --d (Verzögerung) staffelbar.
   ===================================================================== */

/* ---- Reveal-Grundtypen -------------------------------------------- */
[data-reveal] { will-change: transform, opacity; }

/* fade-up (Standard) */
[data-reveal="up"]    { opacity: 0; transform: translateY(42px);        transition: opacity .9s var(--ease-out) var(--d, 0s), transform .9s var(--ease-out) var(--d, 0s); }
[data-reveal="fade"]  { opacity: 0;                                     transition: opacity 1.1s var(--ease-out) var(--d, 0s); }
[data-reveal="left"]  { opacity: 0; transform: translateX(-48px);       transition: opacity .9s var(--ease-out) var(--d, 0s), transform .9s var(--ease-out) var(--d, 0s); }
[data-reveal="right"] { opacity: 0; transform: translateX(48px);        transition: opacity .9s var(--ease-out) var(--d, 0s), transform .9s var(--ease-out) var(--d, 0s); }
[data-reveal="scale"] { opacity: 0; transform: scale(0.92);             transition: opacity .9s var(--ease-out) var(--d, 0s), transform .9s var(--ease-out) var(--d, 0s); }

[data-reveal].is-in { opacity: 1; transform: none; }

/* ---- Maskierter Zeilen-Reveal (für Headlines) ---------------------
   Markup: <span class="line-mask"><span class="line-inner">…</span></span>
   js/modules/reveal.js fügt .is-in am Container hinzu.               */
/* padding-top + negativer margin = Platz für Umlaut-Punkte (Ä Ö Ü),
   ohne dass die Maske sie abschneidet; Layout bleibt unverändert. */
.line-mask { display: block; overflow: hidden; padding-top: 0.14em; margin-top: -0.14em; line-height: 1.06; }
.line-inner { display: block; transform: translateY(115%); transition: transform 1s var(--ease-out) var(--d, 0s); }
.is-in > .line-mask > .line-inner,
.line-mask.is-in > .line-inner { transform: translateY(0); }

/* ---- Wort-für-Wort Reveal (von splitText in reveal.js erzeugt) ---- */
.word { display: inline-block; overflow: hidden; vertical-align: top; padding-top: 0.12em; margin-top: -0.12em; }
.word > span { display: inline-block; transform: translateY(118%); transition: transform .8s var(--ease-out); }
.is-in .word > span { transform: translateY(0); }

/* ---- Dauer-Animationen -------------------------------------------- */
@keyframes floaty   { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes spinSlow { to { transform: rotate(360deg); } }
@keyframes pulseGlow { 0%,100% { opacity: .35; } 50% { opacity: .7; } }

.floaty   { animation: floaty 6s ease-in-out infinite; }
.spin-badge { animation: spinSlow 14s linear infinite; }

/* ---- Korn/Noise-Overlay (filmischer Look) -------------------------- */
.grain { position: fixed; inset: 0; z-index: 7000; pointer-events: none; opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>"); }
