/* Mathe-Seite.de – Start-Zustände der Animationen
   ==============================================

   ALLE Regeln hier hängen an `html.anim-ready`. Diese Klasse setzt
   anim-init.js, und zwar nur wenn JavaScript läuft, der Browser modern genug
   ist und der Besucher keine Bewegungsreduktion verlangt.

   Das ist der Kern der Progressive-Enhancement-Strategie: ohne die Klasse gibt
   es keinen einzigen versteckten Zustand, die Seite ist vollständig lesbar.
   Ein `opacity: 0` ohne diese Bedingung würde bei abgeschaltetem JavaScript,
   einem Ladefehler oder einem Adblocker, der die Vendor-Datei blockt, die
   halbe Seite dauerhaft unsichtbar machen. Bei einer Lernseite, die Schülern
   Inhalte liefern soll, ist das der schlimmste denkbare Fehler.

   Animiert werden ausschließlich `opacity` und `transform`. Beide laufen im
   Compositor, brauchen kein Layout und verursachen damit kein Layout-Shift
   (CLS). Höhen, `top`, `margin` oder `width` zu animieren sähe ähnlich aus,
   würde aber bei jedem Frame Neuberechnung erzwingen und auf schwachen
   Schul-Laptops ruckeln. */

/* ---------- Grundmuster: Einblenden mit leichtem Versatz ----------

   `:not(.anim-done)` ist hier zwingend, nicht Kosmetik.

   Ablauf einer Animation: CSS versteckt (opacity:0) → GSAP animiert per
   Inline-Style auf 1 → GSAP räumt die Inline-Styles per `clearProps` weg.
   Nach Schritt 3 würde ohne diese Bedingung wieder die Regel von hier gelten
   und das Element GENAU DANN verschwinden, wenn die Animation fertig ist.

   anim.js setzt deshalb `anim-done` auf jedes Element, sobald seine Animation
   beginnt. Danach greift keine versteckende Regel mehr und kein Inline-Style —
   das Element steht in seinem natürlichen Zustand, und CSS-Transitions wie der
   Hover-Effekt der Karten funktionieren wieder.

   Der naheliegende Weg, stattdessen `opacity: 1` per Klasse zu ERZWINGEN, wäre
   falsch: `.anim-ready [data-anim].anim-done` hat Spezifität (0,3,0) und würde
   `.card--link:hover { transform: … }` (0,2,0) überschreiben — der Hover wäre
   tot. Die Regel zu entfernen ist sauberer als sie zu übertrumpfen. */
.anim-ready [data-anim]:not(.anim-done) {
    opacity: 0;
}

/* Richtungsvarianten.

   Der Versatz ist mit 40–56px deutlich spürbar (vorher 24px: technisch korrekt,
   aber kaum wahrnehmbar). Dazu ein leichter Blur im Startzustand — das liest
   sich als „kommt in den Fokus“ und ist der wirksamste Weg zu mehr Präsenz
   ohne größere Bewegung: der Weg bleibt kurz, der Eindruck wird stärker.

   `filter: blur()` läuft NICHT im Compositor wie opacity und transform, sondern
   kostet pro Frame Rechenzeit. Deshalb bewusst dosiert: 6px auf wenigen
   Elementen gleichzeitig, und bei großen Gruppen (Kapitellisten mit 90
   Einträgen) weiter unten explizit abgeschaltet. */
.anim-ready [data-anim="up"]:not(.anim-done) {
    transform: translate3d(0, 48px, 0);
    filter: blur(6px);
}
.anim-ready [data-anim="left"]:not(.anim-done) {
    transform: translate3d(-56px, 0, 0);
    filter: blur(6px);
}
.anim-ready [data-anim="right"]:not(.anim-done) {
    transform: translate3d(56px, 0, 0);
    filter: blur(6px);
}
.anim-ready [data-anim="scale"]:not(.anim-done) {
    transform: scale(0.88);
    filter: blur(6px);
}
/* Für Bild-/Textblöcke im Wechsel: leichte Drehung plus Versatz. Wirkt
   räumlich, ohne kippelig zu werden — mehr als 3deg sieht nach Baukasten aus. */
.anim-ready [data-anim="tilt-left"]:not(.anim-done) {
    transform: translate3d(-48px, 24px, 0) rotate(-3deg);
    filter: blur(6px);
}
.anim-ready [data-anim="tilt-right"]:not(.anim-done) {
    transform: translate3d(48px, 24px, 0) rotate(3deg);
    filter: blur(6px);
}

/* Gestaffelte Gruppen: die Kinder starten versetzt, nicht der Container.
   Der Container selbst bleibt sichtbar, damit seine Höhe von Anfang an steht
   und beim Einblenden nichts springt. */
.anim-ready [data-anim-group] > *:not(.anim-done) {
    opacity: 0;
    transform: translate3d(0, 40px, 0) scale(0.97);
}

/* Karten-Gruppen dürfen kräftiger kommen: hier zählt der Wellen-Eindruck.
   Kein Blur — bei bis zu 90 gleichzeitig animierten Karten wäre das der Punkt,
   an dem schwache Schul-Laptops sichtbar einbrechen. */
.anim-ready [data-anim-group="cards"] > *:not(.anim-done) {
    transform: translate3d(0, 56px, 0) scale(0.94);
}

/* will-change bewusst NICHT global setzen. Es reserviert eine GPU-Schicht pro
   Element; auf einer Seite mit 90 Kapitelkarten kostet das mehr Speicher als
   es an Performance bringt. GSAP setzt es selbst für die Dauer der Animation
   und räumt danach auf – das ist genau richtig. */

/* ---------- Ausnahmen: was nie versteckt werden darf ---------- */

/* Die H1 und der Header sind vom Verstecken ausgenommen (siehe anim.js).
   Die H1 ist auf den meisten Seiten das LCP-Element; sie per opacity:0 zu
   starten verschiebt den Largest-Contentful-Paint messbar nach hinten und
   verschlechtert damit eine Kennzahl, die Google direkt bewertet. Der
   sichtbare Effekt wäre minimal, der Preis real. */

/* Der Consent-Banner wird nicht animiert. Seine Sichtbarkeit läuft über das
   `hidden`-Attribut; eine parallele opacity-Animation wäre eine zweite Quelle
   für denselben Zustand und damit die nächste Fehlerquelle. Rechtlich muss er
   zudem sofort und unverändert erscheinen. */
.anim-ready .consent,
.anim-ready .consent * {
    opacity: 1;
    transform: none;
    filter: none;
}

/* Werbeflächen bleiben unangetastet: Vermarkter messen Sichtbarkeit
   (Viewability), und ein per opacity ausgeblendetes Banner kann als nicht
   ausgeliefert gelten. Das wäre ein Abrechnungsproblem, kein Designdetail. */
.anim-ready .adslot,
.anim-ready .adslot * {
    opacity: 1;
    transform: none;
    filter: none;
}

/* ---------- Ladefehler ---------- */
/* Falls GSAP nicht geladen werden konnte, entfernt anim-init.js `anim-ready`
   und setzt `anim-failed`. Diese Regel ist die Versicherung obendrauf.
   `filter` muss hier mit zurückgesetzt werden — sonst bliebe bei einem
   Ladefehler ein unscharfer Text stehen, was schlimmer ist als ein
   unsichtbarer: er sieht wie ein Renderfehler aus. */
.anim-failed [data-anim],
.anim-failed [data-anim-group] > * {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
}

/* ---------- Bewegungsreduktion ---------- */
/* anim-init.js lädt GSAP dann gar nicht und setzt `anim-ready` nicht. Diese
   Regel greift also nur, wenn der Besucher die Einstellung MITTEN in der
   Sitzung ändert (macOS erlaubt das ohne Reload). */
@media (prefers-reduced-motion: reduce) {
    .anim-ready [data-anim],
    .anim-ready [data-anim-group] > * {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
    }
}

/* ---------- Zählende Statistik ---------- */
/* Die Zahlen im Hero zählen hoch. Tabellenziffern verhindern, dass die Breite
   bei jedem Zwischenwert springt – ohne das zappelt die ganze Zeile. */
.stat__value {
    font-variant-numeric: tabular-nums;
}
