/* css/motion.css - Bewegungsschicht des Showcase.
 *
 * Wird NACH css/stage.css geladen und ist die einzige Datei, in der
 * Folienwechsel, Reveal-Staffelung und Akt-Uebergang beschrieben sind.
 * Grundsatz (docs/STORY-CONCEPT.md Abschnitt 5, Skill frontend-design):
 * Bewegung zeigt eine Veraenderung, sie schmueckt nicht. Jede Folie kommt
 * einmal orchestriert herein und steht danach still.
 *
 * Alles Zeitliche steht in `@media (prefers-reduced-motion: no-preference)`.
 * Bei `reduce` bleibt nur die Farbtemperatur der Akte uebrig - die ist
 * Gestaltung, keine Bewegung.
 *
 * Farben ausschliesslich ueber Tokens aus dem :root-Block in index.html.
 * ============================================================ */

.main-stage {
  /* Eine einzige Beschleunigungskurve traegt das ganze Deck: schnell los,
   * lange ausrollen. Das ist der Grund, warum die Folien "schwer" wirken. */
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);

  --slide-ms: 240ms;      /* Folienwechsel innerhalb eines Akts */
  --act-ms: 700ms;        /* Divider-Moment zwischen zwei Akten */
  --act-hold: 300ms;      /* Zeitpunkt, zu dem die Zielfolie gerendert wird */
}

/* ============================================================
   1. Farbtemperatur je Akt
   Akt I kuehl (cyan-lastig), Akt II gemischt, Akt III warm (pink-lastig).
   Nur color-mix aus --brand-color und --brand-secondary, damit die Logik
   jedes Theme ueberlebt: twink-death mischt Rot mit Rot, onnetwork
   Dunkelblau mit Orange - die Richtung bleibt in jedem Fall dieselbe.
   Der Wechsel selbst passiert hinter der Divider-Blende, deshalb braucht
   es hier keine Transition.
   ============================================================ */

.main-stage {
  --aurora-a: var(--brand-color);
  --aurora-b: var(--brand-secondary);
}
.main-stage[data-act="1"] {
  --aurora-a: var(--brand-color);
  --aurora-b: color-mix(in srgb, var(--brand-color) 72%, var(--brand-secondary));
}
.main-stage[data-act="2"] {
  --aurora-a: color-mix(in srgb, var(--brand-color) 62%, var(--brand-secondary));
  --aurora-b: color-mix(in srgb, var(--brand-secondary) 58%, var(--brand-color));
}
.main-stage[data-act="3"] {
  --aurora-a: color-mix(in srgb, var(--brand-secondary) 70%, var(--brand-color));
  --aurora-b: var(--brand-secondary);
}

.main-stage .slide-aurora .aurora-blob-1 {
  background: radial-gradient(closest-side, var(--aurora-a), transparent 100%);
}
.main-stage .slide-aurora .aurora-blob-2 {
  background: radial-gradient(closest-side, var(--aurora-b), transparent 100%);
}

/* ============================================================
   2. Akt-Uebergang (Divider-Moment)
   700 ms, nur beim Wechsel des `act`-Feldes, also nur im Executive-Deck.
   Ablauf: Blende auf --surface-0 hoch (240 ms), Halten (160 ms, in dieser
   Phase rendert modules/stage.js die Zielfolie und die Aurora wechselt die
   Temperatur), Blende ab (300 ms, die Zielfolie laeuft darunter bereits an).
   ============================================================ */

/* Die Blende haengt am Buehnenrahmen. css/stage.css positioniert ihn nicht,
 * deshalb steht die Verankerung hier - ohne sie wuerde sich `inset: 0` am
 * initialen Containing Block orientieren und bei langen Folien verrutschen. */
.main-stage .stage-frame { position: relative; }

.act-divider {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  background: var(--surface-0);
  opacity: 0;
  pointer-events: none;
  text-align: center;
}
.act-divider[hidden] { display: none; }

/* Die Sektionsziffer der Zielfolie, dasselbe Wasserzeichen wie auf der
 * Folie selbst - der Uebergang zeigt damit, wohin er fuehrt. */
.act-divider-numeral {
  position: absolute;
  z-index: 0;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  font-family: var(--font-headline);
  font-size: 40vh;
  font-weight: 700;
  line-height: 0.78;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--aurora-a);
  opacity: 0.08;
}

.act-divider-act {
  position: relative;
  z-index: 1;
  margin: 0;
  font-family: var(--font-headline);
  font-size: clamp(24px, 3.4vw, 46px);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}

/* Eine Haarlinie unter dem Kicker, die in Leserichtung waechst. Sie ist das
 * einzige Ornament des Uebergangs und wiederholt die Geste des Hero-Pfeils. */
.act-divider-rule {
  position: relative;
  z-index: 1;
  width: min(280px, 34vw);
  height: 1px;
  background: var(--aurora-a);
  opacity: 0.55;
}

.act-divider-name {
  position: relative;
  z-index: 1;
  margin: 0;
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-caption);
}

/* ============================================================
   3. Bewegung - alles Folgende nur ohne Reduced-Motion-Wunsch
   ============================================================ */

@media (prefers-reduced-motion: no-preference) {

  /* --- 3.1 Akt-Uebergang ------------------------------------------------ */

  @keyframes act-veil {
    0%   { opacity: 0; }
    34%  { opacity: 1; }
    57%  { opacity: 1; }
    100% { opacity: 0; }
  }
  @keyframes act-numeral {
    from { opacity: 0; transform: scale(0.94); }
    to   { opacity: 0.08; transform: none; }
  }
  @keyframes act-rise {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes act-rule {
    from { transform: scaleX(0); }
    to   { transform: none; }
  }

  .act-divider.is-on {
    animation: act-veil var(--act-ms) var(--ease-out) forwards;
    will-change: opacity;
  }
  .act-divider.is-on .act-divider-numeral {
    animation: act-numeral 520ms var(--ease-expo) backwards;
  }
  .act-divider.is-on .act-divider-act {
    animation: act-rise 420ms var(--ease-expo) 60ms backwards;
  }
  .act-divider.is-on .act-divider-name {
    animation: act-rise 420ms var(--ease-expo) 140ms backwards;
  }
  .act-divider.is-on .act-divider-rule {
    transform-origin: left center;
    animation: act-rule 400ms var(--ease-expo) 120ms backwards;
  }
  /* Rueckwaerts laeuft dieselbe Choreografie spiegelbildlich. */
  .act-divider.is-on.is-reverse .act-divider-rule { transform-origin: right center; }

  /* --- 3.2 Folienwechsel innerhalb eines Akts --------------------------- */

  /* Der Traeger blendet in 240 ms; die Staffelung der Bestandteile kommt
   * unveraendert aus css/stage.css. Zwei Ebenen, eine Geste. */
  @keyframes slide-fade { from { opacity: 0; } to { opacity: 1; } }

  .slide.is-in {
    animation: slide-fade var(--slide-ms) var(--ease-out) backwards;
  }

  /* Rueckwaerts (Pfeil links, PageUp) kommen die Bestandteile von oben.
   * Die Bewegungsrichtung ist der einzige Unterschied - der Vortragende
   * soll spueren, dass er zurueckgeht, ohne es lesen zu muessen. */
  @keyframes slide-sink {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: none; }
  }
  .slide.is-in.is-reverse .slide-kicker,
  .slide.is-in.is-reverse .slide-title,
  .slide.is-in.is-reverse .slide-hero,
  .slide.is-in.is-reverse .slide-body,
  .slide.is-in.is-reverse .slide-bullets,
  .slide.is-in.is-reverse .slide-figure,
  .slide.is-in.is-reverse .slide-visual,
  .slide.is-in.is-reverse .slide-html > .grid2 > *,
  .slide.is-in.is-reverse .slide-html > .grid3 > *,
  .slide.is-in.is-reverse .slide-html > .grid4 > *,
  .slide.is-in.is-reverse .slide-html > .cardstack > * {
    animation-name: slide-sink;
  }

  /* --- 3.3 Hero-Zahl ---------------------------------------------------- */

  /* Die tragende Zahl setzt sich einmal: 0,96 auf 1 in 520 ms Ease-out-expo.
   * Kein Schwingen, kein Nachfedern - der Wert soll ankommen, nicht auftreten. */
  @keyframes hero-settle {
    from { opacity: 0; transform: scale(0.96); }
    to   { opacity: 1; transform: none; }
  }
  .slide.is-in .slide-hero .hero-value {
    transform-origin: left center;
    animation: hero-settle 520ms var(--ease-expo) 120ms backwards;
    will-change: transform, opacity;
  }
  .slide.is-in.is-v-statement .slide-hero .hero-value,
  .slide.is-in.is-title .slide-hero .hero-value { transform-origin: center; }
  /* Nach dem Auftritt ist die Zahl ein stehendes Objekt. */
  .slide .hero-value.is-settled { will-change: auto; }

  /* Vorher -> Nachher: der Pfeil wird als 1px-Linie gezogen, die in
   * Leserichtung waechst (400 ms). Erst wenn sie angekommen ist, erscheint
   * der Nachher-Wert. Die Folie behauptet damit nicht "41,4 wird 57,8",
   * sie zeigt die Richtung der Veraenderung. */
  @keyframes hero-rule {
    from { transform: scaleX(0); }
    to   { transform: none; }
  }
  @keyframes hero-arrow-in {
    from { color: transparent; -webkit-text-fill-color: transparent; }
    to   { color: var(--brand-color); -webkit-text-fill-color: var(--brand-color); }
  }
  @keyframes hero-after-in {
    from { opacity: 0; transform: translateX(6px); }
    to   { opacity: 1; transform: none; }
  }

  .hero-value .hero-arrow {
    position: relative;
    display: inline-block;
    padding: 0 0.3em;
  }
  .hero-value .hero-arrow::after {
    content: "";
    position: absolute;
    left: 0.06em;
    right: 0.06em;
    top: 54%;
    height: 1px;
    background: var(--brand-color);
    transform: scaleX(0);
    transform-origin: left center;
  }
  /* Solange die Zahl nicht steht (Hochzaehlen laeuft), bleiben Pfeil und
   * Nachher-Wert zurueck. `is-settled` setzt modules/stage.js. */
  .hero-value:not(.is-settled) .hero-arrow {
    color: transparent;
    -webkit-text-fill-color: transparent;
  }
  .hero-value:not(.is-settled) .hero-after { opacity: 0; }

  .hero-value.is-settled .hero-arrow::after {
    animation: hero-rule 400ms var(--ease-expo) forwards;
  }
  .hero-value.is-settled .hero-arrow {
    animation: hero-arrow-in 200ms linear 400ms backwards;
  }
  .hero-value.is-settled .hero-after {
    display: inline-block;
    animation: hero-after-in 320ms var(--ease-expo) 400ms backwards;
  }

  /* --- 3.4 Split-Ansicht ------------------------------------------------ */

  /* Beim Oeffnen der Split-Ansicht fahren Mockup und Quelltext aus der Mitte
   * auseinander: das Bild nach links, der Code nach rechts. 360 ms. */
  @keyframes pane-left {
    from { opacity: 0; transform: translateX(-16px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes pane-right {
    from { opacity: 0; transform: translateX(16px); }
    to   { opacity: 1; transform: none; }
  }
  .slide.is-in.is-split .slide-visual .mockup-pane {
    animation: pane-left 360ms var(--ease-expo) 200ms backwards;
  }
  .slide.is-in.is-split .slide-visual .code-pane {
    animation: pane-right 360ms var(--ease-expo) 200ms backwards;
  }

  /* --- 3.5 Quelltext ---------------------------------------------------- */

  /* Zeilen laufen von oben nach unten ein, 20 ms Abstand, gedeckelt bei
   * 600 ms Gesamtstaffelung. Zeilennummer und Zeile gehoeren zusammen und
   * bewegen sich deshalb synchron. Ab Zeile 31 kommt alles gemeinsam. */
  @keyframes code-line-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
  }
  .slide.is-in .code-source code > .code-line,
  .slide.is-in .code-gutter > span {
    display: block;
    animation: code-line-in 240ms var(--ease-out) 300ms backwards;
  }
  .slide.is-in .code-source code > .code-line:nth-child(1),
  .slide.is-in .code-gutter > span:nth-child(1) { animation-delay: 300ms; }
  .slide.is-in .code-source code > .code-line:nth-child(2),
  .slide.is-in .code-gutter > span:nth-child(2) { animation-delay: 320ms; }
  .slide.is-in .code-source code > .code-line:nth-child(3),
  .slide.is-in .code-gutter > span:nth-child(3) { animation-delay: 340ms; }
  .slide.is-in .code-source code > .code-line:nth-child(4),
  .slide.is-in .code-gutter > span:nth-child(4) { animation-delay: 360ms; }
  .slide.is-in .code-source code > .code-line:nth-child(5),
  .slide.is-in .code-gutter > span:nth-child(5) { animation-delay: 380ms; }
  .slide.is-in .code-source code > .code-line:nth-child(6),
  .slide.is-in .code-gutter > span:nth-child(6) { animation-delay: 400ms; }
  .slide.is-in .code-source code > .code-line:nth-child(7),
  .slide.is-in .code-gutter > span:nth-child(7) { animation-delay: 420ms; }
  .slide.is-in .code-source code > .code-line:nth-child(8),
  .slide.is-in .code-gutter > span:nth-child(8) { animation-delay: 440ms; }
  .slide.is-in .code-source code > .code-line:nth-child(9),
  .slide.is-in .code-gutter > span:nth-child(9) { animation-delay: 460ms; }
  .slide.is-in .code-source code > .code-line:nth-child(10),
  .slide.is-in .code-gutter > span:nth-child(10) { animation-delay: 480ms; }
  .slide.is-in .code-source code > .code-line:nth-child(11),
  .slide.is-in .code-gutter > span:nth-child(11) { animation-delay: 500ms; }
  .slide.is-in .code-source code > .code-line:nth-child(12),
  .slide.is-in .code-gutter > span:nth-child(12) { animation-delay: 520ms; }
  .slide.is-in .code-source code > .code-line:nth-child(13),
  .slide.is-in .code-gutter > span:nth-child(13) { animation-delay: 540ms; }
  .slide.is-in .code-source code > .code-line:nth-child(14),
  .slide.is-in .code-gutter > span:nth-child(14) { animation-delay: 560ms; }
  .slide.is-in .code-source code > .code-line:nth-child(15),
  .slide.is-in .code-gutter > span:nth-child(15) { animation-delay: 580ms; }
  .slide.is-in .code-source code > .code-line:nth-child(16),
  .slide.is-in .code-gutter > span:nth-child(16) { animation-delay: 600ms; }
  .slide.is-in .code-source code > .code-line:nth-child(17),
  .slide.is-in .code-gutter > span:nth-child(17) { animation-delay: 620ms; }
  .slide.is-in .code-source code > .code-line:nth-child(18),
  .slide.is-in .code-gutter > span:nth-child(18) { animation-delay: 640ms; }
  .slide.is-in .code-source code > .code-line:nth-child(19),
  .slide.is-in .code-gutter > span:nth-child(19) { animation-delay: 660ms; }
  .slide.is-in .code-source code > .code-line:nth-child(20),
  .slide.is-in .code-gutter > span:nth-child(20) { animation-delay: 680ms; }
  .slide.is-in .code-source code > .code-line:nth-child(21),
  .slide.is-in .code-gutter > span:nth-child(21) { animation-delay: 700ms; }
  .slide.is-in .code-source code > .code-line:nth-child(22),
  .slide.is-in .code-gutter > span:nth-child(22) { animation-delay: 720ms; }
  .slide.is-in .code-source code > .code-line:nth-child(23),
  .slide.is-in .code-gutter > span:nth-child(23) { animation-delay: 740ms; }
  .slide.is-in .code-source code > .code-line:nth-child(24),
  .slide.is-in .code-gutter > span:nth-child(24) { animation-delay: 760ms; }
  .slide.is-in .code-source code > .code-line:nth-child(25),
  .slide.is-in .code-gutter > span:nth-child(25) { animation-delay: 780ms; }
  .slide.is-in .code-source code > .code-line:nth-child(26),
  .slide.is-in .code-gutter > span:nth-child(26) { animation-delay: 800ms; }
  .slide.is-in .code-source code > .code-line:nth-child(27),
  .slide.is-in .code-gutter > span:nth-child(27) { animation-delay: 820ms; }
  .slide.is-in .code-source code > .code-line:nth-child(28),
  .slide.is-in .code-gutter > span:nth-child(28) { animation-delay: 840ms; }
  .slide.is-in .code-source code > .code-line:nth-child(29),
  .slide.is-in .code-gutter > span:nth-child(29) { animation-delay: 860ms; }
  .slide.is-in .code-source code > .code-line:nth-child(30),
  .slide.is-in .code-gutter > span:nth-child(30) { animation-delay: 880ms; }
  .slide.is-in .code-source code > .code-line:nth-child(n+31),
  .slide.is-in .code-gutter > span:nth-child(n+31) { animation-delay: 900ms; }

  /* --- 3.6 Funnel ------------------------------------------------------- */

  /* Die Balken wachsen von links auf ihren Wert, 60 ms versetzt. Die
   * Beschriftung und die Vorher/Nachher-Marken bewegen sich nicht: die
   * Zahlen sind Beweiswerte und stehen sofort (STORY-CONCEPT Abschnitt 5). */
  @keyframes funnel-grow {
    from { transform: scaleX(0); }
    to   { transform: none; }
  }
  .slide.is-in .funnel-bar {
    transform-box: fill-box;
    transform-origin: left center;
    animation: funnel-grow 500ms var(--ease-expo) 240ms backwards;
  }
  /* Je Stufe stehen im SVG zwei rect: Schiene, dann Balken. */
  .slide.is-in .funnel-bar:nth-of-type(4)  { animation-delay: 300ms; }
  .slide.is-in .funnel-bar:nth-of-type(6)  { animation-delay: 360ms; }
  .slide.is-in .funnel-bar:nth-of-type(8)  { animation-delay: 420ms; }
  .slide.is-in .funnel-bar:nth-of-type(10) { animation-delay: 480ms; }
  .slide.is-in .funnel-bar:nth-of-type(12) { animation-delay: 540ms; }
  .slide.is-in .funnel-bar:nth-of-type(n+14) { animation-delay: 600ms; }

  /* --- 3.7 Timeline ----------------------------------------------------- */

  /* Die Schiene wird gezogen, die Punkte setzen sich nacheinander. Der Text
   * der Zeilen steht dabei bereits - Pruefer sollen sofort lesen koennen,
   * bewegt wird nur die Struktur, die die Reihenfolge behauptet. */
  @keyframes rail-draw-x { from { transform: scaleX(0); } to { transform: none; } }
  @keyframes rail-draw-y { from { transform: scaleY(0); } to { transform: none; } }
  @keyframes dot-set {
    from { opacity: 0; transform: scale(0); }
    to   { opacity: 1; transform: none; }
  }

  /* Waagerechte Phasenleiste. */
  .slide.is-in.is-v-timeline .slide-html .phasen::before {
    transform-origin: left center;
    animation: rail-draw-x 520ms var(--ease-expo) 240ms backwards;
  }
  .slide.is-in.is-reverse.is-v-timeline .slide-html .phasen::before {
    transform-origin: right center;
  }
  .slide.is-in.is-v-timeline .slide-html .phasen span::before {
    animation: dot-set 320ms var(--ease-expo) 360ms backwards;
  }
  .slide.is-in.is-v-timeline .slide-html .phasen span:nth-child(2)::before { animation-delay: 420ms; }
  .slide.is-in.is-v-timeline .slide-html .phasen span:nth-child(3)::before { animation-delay: 480ms; }
  .slide.is-in.is-v-timeline .slide-html .phasen span:nth-child(4)::before { animation-delay: 540ms; }
  .slide.is-in.is-v-timeline .slide-html .phasen span:nth-child(n+5)::before { animation-delay: 600ms; }

  /* Senkrechte Roadmap-Schiene in der Tabelle. */
  .slide.is-in.is-v-timeline .slide-html table.tbl td:first-child::after {
    transform-origin: top center;
    animation: rail-draw-y 420ms var(--ease-out) 300ms backwards;
  }
  .slide.is-in.is-v-timeline .slide-html table.tbl td:first-child::before {
    animation: dot-set 300ms var(--ease-expo) 300ms backwards;
  }
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(2) td:first-child::before,
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(2) td:first-child::after { animation-delay: 360ms; }
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(3) td:first-child::before,
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(3) td:first-child::after { animation-delay: 420ms; }
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(4) td:first-child::before,
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(4) td:first-child::after { animation-delay: 480ms; }
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(5) td:first-child::before,
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(5) td:first-child::after { animation-delay: 540ms; }
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(n+6) td:first-child::before,
  .slide.is-in.is-v-timeline .slide-html table.tbl tr:nth-child(n+6) td:first-child::after { animation-delay: 600ms; }

  /* --- 3.8 Aurora ------------------------------------------------------- */

  /* Dauerbewegung gibt es nur dort, wo nichts zu lesen ist: auf Statement-
   * und Titelfolien. Sehr langsam und sehr klein - man bemerkt sie erst,
   * wenn man eine halbe Minute auf dieselbe Folie schaut. Alle anderen
   * Folien behalten das `animation: none` aus css/stage.css. */
  @keyframes aurora-drift {
    0%   { transform: none; }
    50%  { transform: translate3d(2.5%, -2%, 0) scale(1.05); }
    100% { transform: none; }
  }
  .slide.is-v-statement .slide-aurora .aurora-blob,
  .slide.is-title .slide-aurora .aurora-blob,
  .slide.is-divider .slide-aurora .aurora-blob {
    animation: aurora-drift 28s ease-in-out infinite;
    will-change: transform;
  }
  .slide.is-v-statement .slide-aurora .aurora-blob-2,
  .slide.is-title .slide-aurora .aurora-blob-2,
  .slide.is-divider .slide-aurora .aurora-blob-2 {
    animation-duration: 36s;
    animation-direction: alternate-reverse;
  }
}
