/* ================================================================
   Reveal-System  —  zeitbasiert, ausgeloest wenn wirklich im Bild
   ================================================================

   ══ WAS SICH BEWEGEN DARF ═══════════════════════════════════════════
   Bewegt wird nur, was eine Struktureinheit ist: Sektionskopf, Trennlinie,
   Kartenreihe, Illustration. NICHT bewegt werden Fliesstext, Listen,
   einzelne Absaetze, Tabellenzeilen.

   Der Grund ist nicht Geschmack, sondern Bedeutung. Wenn beim Scrollen
   alles einzeln hereinkommt, heisst Bewegung nichts mehr und die Seite
   wirkt unruhig — egal wie dezent der einzelne Effekt ist. Bewegt sich
   nur der Sektionsanfang, sagt jede Bewegung: hier beginnt ein neuer
   Gedanke. Als Richtwert: 12 bis 15 bewegte Elemente je Seite, nicht 60.

   Und: wenige Mittel, konsequent. Fuer eine normale Seite genuegen drei —
   mask fuer Ueberschriften, up fuer Inhalte, line fuer Sektionswechsel.
   Alles Weitere ist Sonderfall (SVG-Innenleben, Akkordeon, Scrub) und
   gehoert nicht in den Regelbetrieb. Sieben Varianten auf einer Seite
   lesen sich als Effektschau, nicht als Sorgfalt.
   ════════════════════════════════════════════════════════════════════

   ALLES WIRD IN CSS GEREGELT. Das Skript liest diese Werte aus und
   rechnet nur noch. Wer den Auftritt der ganzen Seite aendern will,
   aendert hier — nicht im Markup, nicht im JavaScript.

     --rv-at     Ausloesepunkt: auf welchen Anteil der Viewporthoehe
                 die Oberkante des Elements gewandert sein muss.
                 65 = unteres Drittel. Kleiner = spaeter.
     --rv-step   Versatz von Glied zu Glied
     --rv-dur    Dauer je Element
     --rv-dist   Weg der Aufwaertsbewegung
     --rv-ease   Beschleunigungskurve

   Je Sektion ueberschreibbar, ebenfalls in CSS:
     .ruhige-sektion{--rv-step:140ms;--rv-dur:640ms}
     .frueh{--rv-at:80}

   ----------------------------------------------------------------
   WIE AUSGELOEST WIRD

   Jedes Glied loest fuer sich aus, sobald seine eigene Oberkante die
   Marke erreicht. Die Staffelung bleibt trotzdem erhalten: das erste
   Glied einer Gruppe startet die Uhr, jedes weitere bekommt seine
   Verzoegerung relativ dazu. Wer schon dran waere, laeuft sofort.

   Das ist der Unterschied zu gruppenweisem Ausloesen und der Grund
   dafuer: auf Mobile fallen Raster auf eine Spalte, eine Sektion wird
   dann schnell 3000px hoch. Wuerde die ganze Gruppe an ihrer Oberkante
   ausloesen, liefen die unteren Glieder weit unter der Falz ab und
   waeren fertig, bevor man sie sieht.

   Nebeneffekt, der erwuenscht ist: auf dem Desktop kommt eine Rasterzeile
   gemeinsam an und staffelt sich ueber den Index. Auf Mobile kommt jede
   Karte einzeln an und tritt einzeln auf. Dieselben Angaben, beide Male
   richtig — ohne Media Query.

   ----------------------------------------------------------------
   MARKUP

     <div class="section-in" data-rv>
       <div class="section-hdr" data-rv-i="0">     Ueberschrift, immer 0
       <div class="karte"       data-rv-i="1">     erster Inhalt
       <div class="karte"       data-rv-i="1.6">   jeder weitere
       <div class="karte"       data-rv-i="2.2">
     </div>

   Ganzer Takt 1.0, Schritt 0.6. Alle Indizes Vielfache von 0.6 ab 1.0,
   damit jeder Abstand bei 0.6 x --rv-step liegt — bei 200ms sind das
   120ms, innerhalb der brauchbaren Spanne von 50 bis 200ms.
   Achtung: --rv-step multipliziert sich mit dem groessten Index. Die
   tk-Sektion reicht bis 6.4, bei 200ms dauert ihre Kaskade also rund
   2,2 Sekunden. Wer sie kuerzer will, senkt --rv-step, nicht --rv-dur.

   Mehrere Ketten nebeneinander (z.B. drei Spalten): jede Spalte ist eine
   Kette, die Spalten um einen Schritt versetzt, damit sie sich nicht ins
   Wort fallen:
     Spalte 1: 1.0  1.6  2.2  2.8 ...
     Spalte 2: 1.6  2.2  2.8  3.4 ...
     Spalte 3: 2.2  2.8  3.4  4.0 ...

   WICHTIG: jedes sichtbare Element muss teilnehmen. Ein Block ohne
   Auftritt ist von Anfang an da und laesst alles danach zu spaet wirken.

     data-rv            Gruppe. Darf zugleich Glied sein.
     data-rv-i="n"      Reihenfolge, Nachkommastellen erlaubt
     data-rv-fx="..."   Regelbetrieb:  mask | up (Vorgabe) | line
                        Sonderfaelle:  drop | slide | fade | grow | draw
                                       | tint | cool | unfold
     data-rv-split      auf eine Ueberschrift: richtet die Maske selbst ein
     data-rv-scrub      Fortschritt = Scrollposition, setzt --p von 0 bis 1

   drop schiebt und skaliert zugleich, ohne die Hoehe anzutasten — fuer
   Raster, in denen unfold die Nachbarn waehrend des Auftritts verschieben
   wuerde. Mit negativem --rv-dist kommt es von oben herunter.

   slide schiebt waagrecht statt senkrecht. --rv-dist negativ = von links,
   positiv = von rechts. Aendert ebenfalls nichts am Platzbedarf.

   unfold faltet ein Element aus der Hoehe null auf und skaliert es dabei
   von .92 hoch — die Umkehrung der Bewegung, mit der die Auswahlkaesten
   im Wizard beim Anklicken zusammenklappen. Nachbarn ruecken dabei mit,
   weil sich die Hoehe wirklich aendert und nicht nur verschoben wird.
     data-rv-once       nur einmal, statt bei jedem Wiedereintritt

   RICHTUNG
   Beim Hochscrollen laeuft alles spiegelverkehrt: die Glieder kommen von
   oben herein, also rutschen sie von oben herunter statt von unten herauf,
   und die Kaskade laeuft von hinten nach vorne — in der Reihenfolge, in
   der man sie tatsaechlich zu Gesicht bekommt.
   Abschalten mit --rv-back:0; dann bleibt stehen, was nach oben
   hinausgescrollt ist, und nur abwaerts wird animiert.

   --rv-dist darf negativ sein. Eine Gruppe mit --rv-dist:-30px kommt
   grundsaetzlich von oben herunter statt von unten herauf.

   Vorgabe ist wiederkehrend: ein Glied wird zurueckgesetzt, sobald es den
   Viewport vollstaendig verlaesst — nach oben wie nach unten. Solange auch
   nur ein Pixel im Bild ist, bleibt es stehen; Zurueckscrollen zum
   Nachlesen nimmt also nichts weg.
   ================================================================ */
:root{
  --rv-at:95;
  --rv-back:1;
  --rv-dur:650ms;
  --rv-step:200ms;
  --rv-dist:30px;
  --rv-ease:var(--ease-out,cubic-bezier(.22,1,.36,1));
}

/* Die Verzoegerung setzt das Skript inline, weil sie davon abhaengt, wie
   viel der Staffelung beim Eintreffen schon verstrichen ist. */
.rv-armed[data-rv-i],.rv-armed [data-rv-i],
.rv-in[data-rv-i],   .rv-in [data-rv-i]{
  transition:
    opacity           var(--rv-dur) var(--rv-ease),
    transform         var(--rv-dur) var(--rv-ease),
    fill              var(--rv-dur) var(--rv-ease),
    stroke-dashoffset var(--rv-dur) var(--rv-ease);
}

/* Ausgangszustand nur, wenn das Skript geschaerft hat.
   Ohne JavaScript bleibt alles sichtbar. */
.rv-armed[data-rv-i],.rv-armed [data-rv-i]{
  opacity:0;transform:translateY(calc(var(--rv-dir,1) * var(--rv-dist)));
  /* nur waehrend der Wartestellung — eine eigene Ebene fuer die Dauer der
     Bewegung, danach gibt der Browser sie wieder frei */
  will-change:opacity,transform}
.rv-armed[data-rv-fx="fade"],.rv-armed [data-rv-fx="fade"]{transform:none}
.rv-armed[data-rv-fx="drop"],.rv-armed [data-rv-fx="drop"]{
  transform:translateY(calc(var(--rv-dir,1) * var(--rv-dist))) scale(.96)}
.rv-armed[data-rv-fx="slide"],.rv-armed [data-rv-fx="slide"]{
  transform:translateX(var(--rv-dist))}
.rv-armed[data-rv-fx="grow"],.rv-armed [data-rv-fx="grow"]{
  opacity:1;transform:scaleY(0)}
.rv-armed[data-rv-fx="draw"],.rv-armed [data-rv-fx="draw"]{
  opacity:.15;transform:none;stroke-dashoffset:var(--rv-len,70)}
.rv-armed[data-rv-fx="tint"],.rv-armed [data-rv-fx="tint"]{
  opacity:1;transform:none;fill:var(--rv-from,#2A3B4D)}
.rv-armed[data-rv-fx="cool"],.rv-armed [data-rv-fx="cool"]{
  opacity:1;transform:scaleY(1);fill:var(--rv-from,#2A3B4D)}

/* Zielzustand. --rv-opacity, falls etwas nicht auf 1 enden soll. */
.rv-in[data-rv-i],.rv-in [data-rv-i]{
  opacity:var(--rv-opacity,1);transform:none}
.rv-in[data-rv-fx="drop"],.rv-in [data-rv-fx="drop"]{transform:none}
.rv-in[data-rv-fx="slide"],.rv-in [data-rv-fx="slide"]{transform:none}
.rv-in[data-rv-fx="grow"],.rv-in [data-rv-fx="grow"]{transform:scaleY(1)}
.rv-in[data-rv-fx="draw"],.rv-in [data-rv-fx="draw"]{
  opacity:1;stroke-dashoffset:0}
.rv-in[data-rv-fx="tint"],.rv-in [data-rv-fx="tint"]{fill:var(--rv-to,#33607F)}
.rv-in[data-rv-fx="cool"],.rv-in [data-rv-fx="cool"]{
  fill:var(--rv-to,#33607F);transform:scaleY(var(--rv-scale,.38))}

/* unfold: faltet aus der Hoehe null auf, Nachbarn ruecken mit.
   Braucht eine eigene Uebergangsliste, weil Hoehe und Innenabstand
   mitlaufen muessen. Muss nach der allgemeinen Liste stehen. */
[data-rv-fx="unfold"]{overflow:hidden}
.rv-armed[data-rv-fx="unfold"],.rv-armed [data-rv-fx="unfold"],
.rv-in[data-rv-fx="unfold"],   .rv-in [data-rv-fx="unfold"]{
  transition:
    opacity      var(--rv-dur) var(--rv-ease),
    transform    var(--rv-dur) var(--rv-ease),
    max-height   var(--rv-dur) var(--rv-ease),
    padding      var(--rv-dur) var(--rv-ease),
    border-color var(--rv-dur) var(--rv-ease)}
.rv-armed[data-rv-fx="unfold"],.rv-armed [data-rv-fx="unfold"]{
  opacity:0;transform:scale(.92);max-height:0;
  padding-top:0;padding-bottom:0;border-color:transparent}
.rv-in[data-rv-fx="unfold"],.rv-in [data-rv-fx="unfold"]{
  opacity:1;transform:none;max-height:var(--rv-hoehe,220px)}

/* ---------------------------------------------------------------- mask
   Die Ueberschrift steigt hinter einer Kante herauf statt einzublenden.
   Das Elternelement schneidet ab, das Kind faehrt von unten herein.
   padding-bottom schafft Platz fuer Unterlaengen (g, j, p, q, y). */
[data-rv-split]{overflow:hidden;padding-bottom:.14em}
[data-rv-split] > .rv-zeile{display:block}
.rv-armed[data-rv-fx="mask"],.rv-armed [data-rv-fx="mask"]{
  opacity:0;transform:translateY(100%)}
.rv-in[data-rv-fx="mask"],.rv-in [data-rv-fx="mask"]{
  opacity:1;transform:translateY(0)}

/* ---------------------------------------------------------------- line
   Die Trennlinie waechst aus der Mitte. Markiert einen Sektionswechsel,
   ohne selbst aufzufallen. Das Element braucht kein eigenes ::after —
   das System bringt es mit. */
[data-rv-fx="line"]{position:relative}
[data-rv-fx="line"]::after{content:'';position:absolute;bottom:0;left:50%;
  transform:translateX(-50%);height:1px;width:0;
  background:linear-gradient(to right,transparent,
    var(--rv-linie,rgba(28,43,58,.18)),transparent);
  transition:width var(--rv-dur) var(--rv-ease) var(--rv-delay,0ms)}
.rv-in[data-rv-fx="line"]::after,.rv-in [data-rv-fx="line"]::after{
  width:var(--rv-linie-breite,min(580px,62%))}

/* SVG braucht einen definierten Bezugsrahmen fuer transform */
[data-rv-fx="grow"],[data-rv-fx="cool"]{
  transform-box:fill-box;transform-origin:50% 100%}

/* Waagrechte Auftritte brauchen keine Farb- und Pfadeigenschaften in der
   Uebergangsliste. Je kuerzer die Liste, desto weniger hat der Browser je
   Frame zu vergleichen. */
.rv-armed[data-rv-fx="slide"],.rv-armed [data-rv-fx="slide"],
.rv-in[data-rv-fx="slide"],   .rv-in [data-rv-fx="slide"],
.rv-armed[data-rv-fx="drop"], .rv-armed [data-rv-fx="drop"],
.rv-in[data-rv-fx="drop"],    .rv-in [data-rv-fx="drop"]{
  transition:opacity var(--rv-dur) var(--rv-ease),
             transform var(--rv-dur) var(--rv-ease)}

/* Die drei Icons in "Gut zu wissen" laufen bewusst langsamer: das
   Absinken der Quecksilbersaeule, das Zeichnen der Schallwellen und das
   Wachsen der Balken sind der Inhalt der Illustration, nicht nur ein
   Auftritt. --rv-dur gilt je Element, der Takt der Sektion bleibt davon
   unberuehrt. */
.tkMerc,.tkBulb,.tkTick,.tkWav,.tkBar{--rv-dur:1500ms}

/* --------------------------------------------------------------- scrub
   Dritte Kategorie neben Auftritt und Dauerschleife: der Fortschritt ist
   die Scrollposition selbst. Das System setzt --p von 0 bis 1, waehrend
   das Element durchs Bild wandert; was damit geschieht, entscheidet die
   Seite. Fuer Dinge, die mitgehen sollen statt einmal aufzutreten —
   eine Quecksilbersaeule, ein Fortschrittsbalken, eine Parallaxe. */
[data-rv-scrub]{--p:0}

@media (prefers-reduced-motion:reduce){
  [data-rv-scrub]{--p:1}
  .rv-armed[data-rv-i],.rv-armed [data-rv-i],
  .rv-in[data-rv-i],   .rv-in [data-rv-i]{transition:none}
}
