/*
 * scroll-scrub-video.css — fixed styles + all degradation states (LIVE-SEEK variant)
 * Provenance: research/prompts/neural-interface.md
 *   #video-layer (position:fixed inset:0 z-index:1 background:#000; L54-60),
 *   #video-layer video (object-fit:cover; opacity:0; will-change:transform,filter,opacity; L61-68),
 *   #bottom-blur progressive blur band (L70-81).
 *
 * The root is the scrub scene. For the scroll driver the consumer gives the PAGE its
 * scroll runway (tall content / a 500vh sticky section — atlas invariant) and the
 * video layer is a fixed backdrop. Copy/choreography targets are marked with
 * data-scrub-hero / data-scrub-desc / data-scrub-cinematic / data-scrub-reveal.
 */

.ssv-root {
  position: relative;
  width: 100%;
}

/* Video layer: fixed full-viewport backdrop behind content (NI #video-layer L54-60). */
.ssv-video-layer {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  z-index: 1;
  background: #000; /* stand-in bg while video loads — NI L58 */
  user-select: none;
  pointer-events: none;
}

/* The scrubbed video (NI #video-layer video L61-68). opacity:0 until entrance lifts it. */
.ssv-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  opacity: 0;
  will-change: transform, filter, opacity;
  display: block;
}

/* Progressive bottom blur band (NI #bottom-blur L70-81) — keeps bottom-left copy legible
   as the video's final third is heavily blurred. Optional: add <div class="ssv-bottom-blur">. */
.ssv-bottom-blur {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 150px;
  z-index: 30;
  pointer-events: none;
  user-select: none;
  background: linear-gradient(to bottom, transparent, #000);
  -webkit-mask-image: linear-gradient(to top, #000 50%, transparent);
  mask-image: linear-gradient(to top, #000 50%, transparent);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

/* Cinematic paragraph needs a 3D context on its parent (NI #cinematic-section L249-254). */
[data-scrub-cinematic] {
  transform-style: preserve-3d;
  will-change: transform, opacity;
}

/* In-view reveal default (NI #stats-section L269-278): hidden until JS adds .ssv-revealed. */
[data-scrub-reveal] {
  opacity: 0;
  transform: translateY(40px) scale(0.98);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
[data-scrub-reveal].ssv-revealed {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* ---------------- Degradation states (contract) ---------------- */

/* prefers-reduced-motion: no scrub choreography. JS pins the video at a resting frame,
   opacity:1, and forces all copy/reveals visible. CSS backstops the video opacity + kills
   entrance transform/blur so a static frame + copy at rest is shown. */
@media (prefers-reduced-motion: reduce) {
  .ssv-video {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
  }
  [data-scrub-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  [data-scrub-hero],
  [data-scrub-desc],
  [data-scrub-cinematic] {
    opacity: 1 !important;
    transform: none !important;
  }
}
.ssv-root.ssv-reduced .ssv-video { opacity: 1; }

/* no-JS: JS never runs, so the <video> stays at opacity:0 by the base rule and would be
   invisible. Consumers MUST add class="no-js" to <html> and remove it in an inline
   bootstrap; while present we show the video (poster / first frame) as the static hero. */
.no-js .ssv-video { opacity: 1 !important; filter: none !important; transform: none !important; }
.no-js [data-scrub-reveal] { opacity: 1 !important; transform: none !important; }

/* Touch / no-pointer: the MOUSE driver has no input; JS falls back to a slow ambient
   autoplay loop and adds .ssv-touch-autoplay. The SCROLL driver is unaffected (scroll
   works on touch; Lenis is desktop-gated by the consuming page, not this primitive). */
.ssv-root.ssv-touch-autoplay .ssv-video { opacity: 1; }

/* Fallback background if the video never paints (asset missing / network fails): a
   neutral dark field so copy layered above still reads. Sits behind the video layer. */
.ssv-video-layer::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(120% 120% at 50% 30%, #14141a 0%, #0a0a0a 60%, #050507 100%);
}

/* Mobile: NI collapses the desktop-only pieces; the scrub itself is unchanged.
   Consumers own their content grid — this primitive only guarantees the video layer. */
@media (max-width: 639px) {
  .ssv-bottom-blur { height: 120px; }
}

/* layerMode 'contained' — the layer rides sticky INSIDE the band instead of
   fixed over the page. Zero blast radius: no cover rules needed on the host
   page (born 2026-07-02 after the fixed layer's cover CSS collided with the
   live site's pen-intro machinery). Negative bottom margin removes the sticky
   element's layout footprint so the stage content overlays it. */
.ssv-video-layer.ssv-contained {
  position: sticky;
  /* ORDER MATTERS: inset is the top/right/bottom/left shorthand — it must come
     BEFORE top, or it resets top to auto and the sticky never sticks (the
     2026-07-02 black-void bug: the layer scrolled away with the band). */
  inset: auto;
  top: 0;
  width: 100%;
  height: 100vh;
  margin-bottom: -100vh;
}
