/* ============================================================
   DRIVE — core/motion/motion.css
   ============================================================
   Static support styles for the motion layer (core/motion/*.js).
   Nothing in here animates by itself: every moving part is driven
   by Anime.js from the JS files. This file only provides

     1. the resting/initial states the motion layer starts from,
     2. the overlay building blocks (curtain, veils, hero layer),
     3. the "hand-over" rules that switch the old CSS-only loops
        off while Anime.js is in charge — and switch them back on
        if Anime.js could not be loaded.

   State classes on <html> (set by core/motion/engine.js):
     .dm-on    motion layer is active (Anime.js loaded, motion allowed)
     .dm-off   Anime.js failed to load -> everything falls back to the
               original CSS behaviour, untouched
   Neither class is present when the visitor prefers reduced motion.
   ============================================================ */

/* ── 1. Overlay building blocks ───────────────────────────── */

/* Full-screen curtain used by the "leave" transitions. Transparent by
   itself: each experience animates its own layers inside it. */
.dm-curtain {
  position: fixed;
  inset: 0;
  z-index: 20000;
  overflow: hidden;
  pointer-events: all;   /* swallow clicks while we are leaving */
  background: transparent;
}
.dm-curtain .dm-veil {
  position: absolute;
  inset: 0;
  background: #05070b;
  opacity: 0;
}

/* Ambient layers on the reader pages. Behind the text (z-index -1),
   never interactive. */
.dm-fx {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  contain: layout paint;
}
.dm-fx > * { position: absolute; pointer-events: none; }

/* Ambient layer inside the homepage hero. Sits in the photograph
   layer, i.e. underneath the hero's own readability gradient. */
.dm-hero-fx {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.dm-hero-fx > * { position: absolute; pointer-events: none; }

/* Small mono read-out used by AEGIS (desktop only, see aegis motion.js). */
.dm-readout {
  position: fixed;
  left: 18px;
  bottom: max(14px, env(safe-area-inset-bottom));
  z-index: 1;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: .14em;
  color: var(--muted-dim, rgba(255,255,255,.28));
  pointer-events: none;
  opacity: 0;
  white-space: nowrap;
}
@media (max-width: 900px) { .dm-readout { display: none; } }

/* ── 2. Splash stage (experience pages) ───────────────────────
   While the motion layer is active the splash starts empty and the
   experience's own choreography brings its pieces in. If Anime.js
   never loads, .dm-on is removed and the original splash shows. */
html.dm-on #splash { transition: none; }
html.dm-on #splash .splash-mark,
html.dm-on #splash .splash-sub,
html.dm-on #splash .splash-track,
html.dm-on #splash .splash-status { opacity: 0; }
html.dm-on #splash .splash-scan { opacity: 0; animation: none; }
html.dm-on #splash .splash-mark,
html.dm-on #splash .splash-hum { animation: none; }
html.dm-on #splash .splash-grain { opacity: .05; }
#splash .dm-stage { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
#splash .dm-stage > * { position: absolute; pointer-events: none; }
#splash .splash-inner { z-index: 2; }
#splash .splash-track { transform-origin: 50% 50%; }

/* ── 3. Hand-over from the old CSS-only loops ─────────────────
   The hero used to run one identical 9s light sweep for every
   experience, forever. With the motion layer on, each experience
   gets its own irregular ambient behaviour instead (see the
   hero() blocks in experiences/<id>/motion.js). */
html.dm-on .tile-bg-layer::after { animation: none; opacity: 0; }
html.dm-on .hero-status-dot { animation: none; }
/* The old micro-glitch on every new chapter is replaced by a
   per-experience reveal (chapter() in experiences/<id>/motion.js). */
html.dm-on .chapter.entering { animation: none; }

/* ── 4. Reduced motion ────────────────────────────────────────
   The visitor's OS setting (and the reader's own REDUCE MOTION
   switch, which sets body[data-reduce-motion]) already keeps the
   motion layer off. These rules close the gaps that existed in the
   old CSS-only animations so "reduce" really means reduce. */
@media (prefers-reduced-motion: reduce) {
  .tile-bg-layer::after,
  .hero-status-dot,
  .dot,
  .nav, .footer, .grid { animation: none !important; }
  .s-anim, .st-anim { animation: none !important; opacity: 1 !important; }
  .dm-curtain, .dm-fx, .dm-hero-fx { display: none !important; }
}
body[data-reduce-motion="true"] .dm-fx,
body[data-reduce-motion="true"] .dm-readout { display: none !important; }

/* ── 5. Whole-site motion (core/motion/site.js) ───────────────
   Page arrival: a page reached through an animated exit stays covered by
   this dark veil until site.js lifts it (a real curtain takes over at the
   same colour, so there is no flash). Removed by site.js, by the watchdog,
   or immediately if Anime.js fails to load. */
html.dm-arriving::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 19999;
  background: #05070b;
}

/* Pieces revealed by site.js start hidden ONLY while the motion layer is on.
   Once revealed they carry .dm-in and the rule no longer matches, so their
   normal CSS state applies again. If the layer is off (reduced motion, Anime.js
   missing) none of this applies and everything is simply visible. */
html.dm-on .home-side .qa-card:not(.dm-in),
html.dm-on .experiences-section:not(.dm-in),
html.dm-on .store-section:not(.dm-in),
html.dm-on .s-anim:not(.dm-in),
html.dm-on .s-tier:not(.dm-in),
html.dm-on .s-item:not(.dm-in),
html.dm-on .run404-home:not(.dm-in),
html.dm-on .run404-status:not(.dm-in),
html.dm-on .run404-stage:not(.dm-in),
html.dm-on:not(.no-welcome) .welcome-box > *:not(.dm-in) { opacity: 0; }

/* The old CSS entrance animations of Store and Support are replaced by the
   reveals above while the layer is on. */
html.dm-on .st-anim,
html.dm-on .s-anim { animation: none; opacity: 1; }   /* (they used to fade in through the animation) */

/* Footer status light: irregular pulse driven from site.js instead of the
   perfectly regular CSS loop. */
html.dm-on .footer-status .dot { animation: none; }

/* ── 6. Smoothness ────────────────────────────────────────────
   Everything the motion layer moves is promoted to its own GPU layer while
   it moves, so the browser only has to composite it instead of repainting
   the page each frame. (Only transform/opacity are animated on large areas.) */
#splash .dm-stage > *,
#splash .dm-stage > * > *,
.dm-curtain > *,
.dm-curtain .dm-veil,
html.dm-on #splash .splash-mark,
html.dm-on #splash .splash-sub,
html.dm-on #splash .splash-track,
html.dm-on #splash .splash-status { will-change: transform, opacity; }
#splash .dm-stage, .dm-curtain { backface-visibility: hidden; }

/* Layer for the reader's key moments (choices, unlocks, endings). */
.dm-moment {
  position: fixed;
  inset: 0;
  z-index: 260;
  pointer-events: none;
  overflow: hidden;
}
.dm-moment > * { will-change: transform, opacity; }

/* ── 8. Key words while reading (core/motion/keywords.js) ─────
   A marked word is plain until it reaches the reading zone; then it takes
   the experience's colour. Each experience marks it in its own way. */
.dm-kw {
  transition: color .9s cubic-bezier(.22,.61,.36,1), text-shadow .9s cubic-bezier(.22,.61,.36,1),
              text-decoration-color .9s cubic-bezier(.22,.61,.36,1), background-size .9s cubic-bezier(.22,.61,.36,1);
}
.dm-kw.on { color: var(--reader-accent-text, var(--green)); }
body[data-theme="light"] .dm-kw.on { color: var(--reader-accent-light, var(--reader-accent-text)); }
body[data-high-contrast="true"] .dm-kw.on { font-weight: 600; }

/* SILAS — a faint blue halo, like a light coming up */
body[data-experience="silas"] .dm-kw.on { text-shadow: 0 0 16px rgba(58,110,165,.55); }
/* INMATE 6382 — marked like an item under observation: a fine underline draws in */
body[data-experience="inmate_6382"] .dm-kw {
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
  text-decoration-color: transparent;
}
body[data-experience="inmate_6382"] .dm-kw.on { text-decoration-color: rgba(138,79,255,.55); }
/* ONE LAST DANCE — a warm, soft glow, like a highlight in a photograph */
body[data-experience="one_last_dance"] .dm-kw.on { text-shadow: 0 0 14px rgba(201,154,90,.45); }
/* AEGIS PROTOCOL — a bar is laid under the word, as if it had been flagged in a file */
body[data-experience="aegis_protocol"] .dm-kw {
  background-image: linear-gradient(rgba(179,58,58,.55), rgba(179,58,58,.55));
  background-repeat: no-repeat; background-position: 0 100%; background-size: 0% 2px;
}
body[data-experience="aegis_protocol"] .dm-kw.on { background-size: 100% 2px; }

@media (prefers-reduced-motion: reduce) { .dm-kw { transition: none; } }
body[data-reduce-motion="true"] .dm-kw { transition: none; }
