/* ==========================================================================
   ARSENE GAME STUDIO — motion.css
   Keyframes, motion states toggled by the js modules, will-change gating,
   reduced-motion overrides. No literal colours (tokens.css only).
   Classes toggled here are owned by: hero.js (.cover.is-pinned/.is-live/.is-off,
   .stencil.live, .rose-traveller), gallery.js (.gallery.is-pinned, .live),
   lineup.js (.wall.is-in, .suspect.is-attended), sections.js (.ticker.is-on,
   .colophon__walk.is-walking/.is-done, .article__num), main.js (html[data-lite]).
   ========================================================================== */

/* ---- before the page is ready: the cover and the chrome wait for hero.js (no flash of the end state
   on repeat visits; on first visits the loader curtain covers everything anyway) ---------------- */
html.js:not(.is-ready) .cover__stage,
html.js:not(.is-ready) .topbar { opacity: 0; }

/* ---- the width axis (brief §8.1): velocity compresses only the .live display elements ---------- */
.display.live {
  font-variation-settings: "wdth" var(--wdth, 100);
}

/* lite mode (frame guard tripped, §8.4): the axis is static */
html[data-lite] .display.live { font-variation-settings: "wdth" var(--wdth, 100); }

/* Archivo missing (§6.4): the index titles use tracking instead of width */
.index.no-wdth .index__title { letter-spacing: -0.05em; }

/* ---- hero: the studio's key art panning inside the letters ------------------------------------------------ */
@keyframes drift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(var(--drift-loop, -50%), 0, 0); }
}
@keyframes drift-pan {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(var(--drift-span, -40%), 0, 0); }
}
.drift__track {
  animation: drift-pan var(--drift-dur, 60s) ease-in-out infinite alternate;
  animation-play-state: paused;
}
.cover.is-live .drift__track { animation-play-state: running; }
.cover.is-off .drift__track { animation-play-state: paused; }     /* the pin has released (§8.4) */
.cover.is-pinned .drift__track { will-change: transform; }
/* the letter's drift: one set only, so it pans back and forth instead of looping */
.word-drift .drift__track {
  animation: drift-pan var(--drift-dur, 120s) ease-in-out infinite alternate;
  animation-play-state: paused;
}
.letter.is-live .word-drift .drift__track { animation-play-state: running; }

/* the loader curtain owned by hero.js: the curtain is a child so the rose can travel above it */
.loader.is-owned { background: transparent; pointer-events: none; }
.loader__curtain { position: absolute; inset: 0; background: var(--ink); }
/* the rose that travels (loader → hero slot → index plate six); hidden unless hero.js shows it */
.rose-traveller {
  position: fixed;
  left: 0; top: 0;
  z-index: 45;
  width: 160px; height: 160px;
  pointer-events: none;
  visibility: hidden;
  transform-origin: 0 0;
}
.rose-traveller.is-travelling { visibility: visible; }
/* the loader rose draws its outlines in ivory on the ink; it turns red when it blooms */
.rose.is-drawing .petal-outline { stroke: var(--paper); stroke-opacity: .55; }
.rose .petal-outline { transition: stroke 300ms var(--ease-out), stroke-opacity 300ms var(--ease-out); }
.rose .petal-bloom { transform-box: fill-box; }

/* the rose-red stroke copy starts misprinted and slides into register during the press (§6.2) */
.stencil__stroke--rose { transform: translate(var(--mis-rose-x, 0px), var(--mis-rose-y, 0px)); }

/* the scroll cue's line draws down; the seal pulses once every 8s (§6.2) */
.cover__cue-line { transform-origin: 50% 0; }
@keyframes seal-pulse {
  0%   { transform: scale(1); }
  3.75% { transform: scale(1.06); }
  7.5% { transform: scale(1); }
  100% { transform: scale(1); }
}
.cover__seal.is-live { animation: seal-pulse 8s ease-in-out infinite; }

/* the index over the stage: only the plates take the pointer, so the rose keeps its hover (§6.2) */
.index { pointer-events: none; }
.index__plate { pointer-events: auto; }
.index__no, .index__title, .index__row { will-change: auto; }

/* ---- ticker marquee (§4.2): duplicated content, duration set by sections.js from the content width */
@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@keyframes marquee-rev {
  from { transform: translate3d(-50%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
.ticker__track {
  animation: marquee var(--marquee-dur, 60s) linear infinite;
  animation-play-state: paused;
}
.ticker__strip--b .ticker__track { animation-name: marquee-rev; }
.ticker.is-on .ticker__track { animation-play-state: running; will-change: transform; }
/* pill hover: the silhouette wakes into its duotone (the layers fade in over 180ms) */
.pill .char :is(.tone, .rim, .accent, .glow, .detail) { transition: opacity var(--t-micro) var(--ease-expo); }
.pill svg.char.state-silhouette :is(.tone, .rim, .accent, .glow, .detail) { display: block; opacity: 0; }
.pill svg.char.state-duotone :is(.tone, .rim, .glow, .detail) { opacity: 1; }
.pill svg.char.state-duotone .accent--base { opacity: 1; }
.pill svg.char .ink, .pill svg.char .ink * { transition: fill var(--t-micro) var(--ease-expo), stroke var(--t-micro) var(--ease-expo); }
.pill svg.char { --mis-x: 0px; --mis-y: 0px; }

/* ---- gallery (§4.3) ------------------------------------------------------------------------- */
.gallery.is-pinned .gallery__track { will-change: transform; }
.spread__title { --wdth: 62; }                       /* titles rest compressed; the scrub widens the centred one */
html[data-lite] .spread__char .accent--print { transition: transform .3s var(--ease-expo); }

/* ---- lineup (§4.5): attention ------------------------------------------------------------------- */
.wall.is-in .suspect .char .accent { transition: opacity var(--t-micro) var(--ease-expo); }
.wall.is-in .suspect:not(.is-attended) .char .accent { opacity: .4; }
.wall.is-in .suspect.is-attended .char .accent--print { opacity: .9; }
.suspect__link { transition: transform var(--t-micro) var(--ease-expo); }
.suspect.is-attended .suspect__link { transform: translateY(-6px); }
.wall.is-in .suspect.is-attended .char { --mis-x: 0px; --mis-y: 0px; }

/* ---- letter (§4.6) ---------------------------------------------------------------------------- */
.article__num { overflow: hidden; }
.article__num-inner { display: block; }
.letter__seal { transform-origin: 50% 50%; }
.word-plate .display { display: block; }

/* ---- colophon walk (§4.10) -------------------------------------------------------------------- */
@keyframes walk-sway {
  0%, 100% { transform: rotate(-2deg); }
  50%      { transform: rotate(2deg); }
}
.colophon__walk.is-walking { will-change: transform; }
.colophon__walk.is-walking .colophon__walker { animation: walk-sway 1s ease-in-out infinite; transform-origin: 50% 100%; }
.colophon__walk.is-walking .colophon__walker:nth-child(2n) { animation-delay: -0.5s; }
.colophon__walk.is-walking .colophon__walker:nth-child(3n) { animation-delay: -0.25s; }
.colophon__walk.is-done { visibility: hidden; }

/* ==========================================================================
   REDUCED MOTION (brief §8.5): no loader, no pins, no scrubs, final states everywhere
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .drift__track, .word-drift .drift__track, .ticker__track, .colophon__walker, .cover__seal { animation: none !important; }
  .cover__cue-line, .rule, .wall__floor, .gallery__progress-bar { transform: none !important; }
  .suspect__link, .pill .char *, .wall.is-in .suspect .char .accent, .rose .petal-outline { transition: none !important; }

  /* cover: no pin; the index is a static grid right after the cover */
  html.js .cover { height: auto; min-height: 0; }
  html.js .cover__stage { position: relative; height: 100svh; min-height: 480px; }
  html.js .index { position: relative; inset: auto; height: 100svh; bottom: auto; }
  html.js .index .index__col { clip-path: none !important; }
  .rose-traveller { display: none; }

  /* ticker: static, scrollable by hand and keyboard */
  .ticker__strip { overflow-x: auto; scrollbar-width: none; }
  .ticker__strip::-webkit-scrollbar { display: none; }

  /* gallery: vertical, never pinned */
  .gallery__stage { height: auto; overflow: visible; }
  .gallery__track { display: block; width: 100%; height: auto; transform: none !important; }
  .gallery__progress, .gallery__counter { display: none; }
  .spread { min-height: 100svh; height: auto; border-top: var(--hairline) solid var(--line); }
  .spread__title { --wdth: 100; }

  /* letter: no sticky pin; the three words become plates between the articles (as on the phone) */
  .letter__split { min-height: 0; display: block; }
  .letter__words { display: none; }
  .letter__body { gap: var(--space-6); padding-block: 0; }
  .word-plate {
    display: block;
    padding: var(--space-5) 0;
    border-top: var(--hairline) solid var(--line);
    border-bottom: var(--hairline) solid var(--line);
    color: var(--paper);
    line-height: 1;
    overflow: hidden;
  }
  .signature__path { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .colophon__walk { transform: none !important; }
}
