/* ==========================================================================
   Scroll-reveal states + reduced-motion fallbacks
   js/reveal.js only toggles .is-in — every transition is declared here.
   ========================================================================== */

/* ---- Fade + rise ------------------------------------------------------- */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(1.75rem);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--delay, 0ms);
}

.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* ---- Rule that draws itself --------------------------------------------- */

.js [data-reveal="rule"] {
  opacity: 1;
  transform: none;
  transform-origin: left;
  scale: 0 1;
  transition: scale var(--dur-slow) var(--ease-in-out);
}

.js [data-reveal="rule"].is-in { scale: 1 1; }

/* ---- Plate uncovering from the bottom -----------------------------------
   The clip lives on the <img>, never on the observed <figure>: an element
   that clips itself away reports an intersection ratio of 0, so it would
   never trigger its own reveal.
   -------------------------------------------------------------------------- */

.js [data-reveal="plate"] {
  opacity: 1;
  transform: none;
}

.js [data-reveal="plate"] img {
  clip-path: inset(0 0 100% 0);
  transform: scale(1.18);
  transition: clip-path 1.3s var(--ease-in-out), transform 1.6s var(--ease-out);
  transition-delay: var(--delay, 0ms);
}

.js [data-reveal="plate"].is-in img {
  clip-path: inset(0 0 0 0);
  transform: scale(1);
}

/* ---- Line-by-line display type ------------------------------------------ */

/* js/reveal.js wraps each .line in a .line__mask clipping frame. */
.line__mask {
  display: block;
  overflow: hidden;
  /* Same reason as the bottom, at the other end: Thai stacks an upper vowel
     and a tone above the consonant, past the ascender these lines are leaded
     for, and the clip would take the tone mark off entirely. */
  padding-top: 0.3em;
  margin-top: -0.3em;
  /* 0.08em was a Latin descender's worth. Thai hangs a vowel BELOW the
     consonant as well as above it, and measured on this page the deepest
     line overran the old padding by 0.2em — five of twelve masked lines were
     losing their sara u. */
  padding-bottom: 0.34em;
  margin-bottom: -0.34em;
}

.js .line__mask > span {
  display: block;
  /* Exactly clears the padded mask: 100% is the line's own height, and the
     extra em covers the bottom padding the clip now has. A bare 105% left a
     23px sliver of the line showing before it was meant to rise. */
  transform: translateY(calc(100% + 0.4em));
  transition: transform 1.15s var(--ease-out);
  transition-delay: calc(var(--delay, 0ms) + var(--i, 0) * 90ms);
}

.js [data-reveal="lines"] {
  opacity: 1;
  transform: none;
}

.js [data-reveal="lines"].is-in .line__mask > span { transform: translateY(0); }

/* ---- Word-by-word ------------------------------------------------------- */

.js .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em);
  transition: opacity 760ms var(--ease-out), transform 760ms var(--ease-out);
  transition-delay: calc(var(--delay, 0ms) + var(--i, 0) * 38ms);
}

.js [data-reveal="words"] { opacity: 1; transform: none; }
.js [data-reveal="words"].is-in .word { opacity: 1; transform: none; }

/* ==========================================================================
   Reduced motion: everything resolves to its final state instantly.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  [data-reveal],
  [data-reveal].is-in {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    scale: 1 1 !important;
  }

  .line__mask > span,
  .word {
    transform: none !important;
    opacity: 1 !important;
  }

  [data-reveal="plate"] img {
    clip-path: none !important;
    transform: none !important;
  }

  .marquee__row { animation: none !important; }
  .hero__scroll { display: none; }

  /* The hero stops shrinking and simply holds its frame. */
  .hero__media { clip-path: none !important; }
  .hero__still,
  .hero__center { transform: none !important; }

  /* Pinned sections collapse to plain stacked blocks. */
  .stage { height: auto !important; padding-block: var(--section-tight); }

  .stage__inner {
    position: static;
    height: auto;
    display: block;
    overflow: visible;
    padding-block: var(--section-tight);
    text-align: center;
  }

  .stage__type,
  .stage__form {
    grid-area: auto;
    opacity: 1 !important;
    transform: none !important;
  }

  .stage__form { height: auto; margin-block: var(--section-tight); }

  .stage__form img {
    height: auto;
    width: min(100%, 22rem);
    margin-inline: auto;
  }

  .triptych { height: auto !important; }
  .triptych__track { position: static; height: auto; display: block; }
  .triptych__rail { transform: none !important; flex-direction: column; }
  .step { width: 100%; }
}
