/* bgvideo.css — background video layers.
 *
 * Two shapes, one element. `.bgv` is always an absolutely-positioned layer that
 * fills its nearest positioned ancestor:
 *
 *   .frame > .bgv          the hero — fills the framed square, sits over the
 *                          still and over hero.js's procedural layers
 *   section > .bgv-section full-bleed behind a section's content, under a scrim
 *
 * ── The rule that governs all of this ────────────────────────────────────────
 * The page must be finished BEFORE the video arrives, and stay finished if it
 * never does. Every .bgv sits on top of a still that is already correct. The
 * video fades in over it and fades out with it. Nothing reflows, nothing moves,
 * no space is reserved for it, and no text ever depends on it for contrast —
 * the scrim below does that job whether or not a single frame ever decodes.
 */

.bgv {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;      /* never steal a click, never take focus */
  z-index: 1;
}

.bgv-el {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  /* Slow. A background that announces itself has failed at being a background;
     1.2s reads as the image "settling" rather than as a video starting. */
  transition: opacity 1.2s ease;
  /* Promote once, up front. Without this Safari composites the fade on the CPU
     and drops frames in the rest of the page while it runs. */
  will-change: opacity;
  transform: translateZ(0);
  backface-visibility: hidden;
}

.bgv.is-playing .bgv-el { opacity: 1; }

/* ── Hero ────────────────────────────────────────────────────────────────────
   Sits above hero.js's bloom/signal/motes layers. Those are derived from the
   same still and are exactly redundant once real footage is playing — bgvideo.js
   also pauses that animation so we are not paying rAF for hidden pixels. */
.frame .bgv { z-index: 3; border-radius: inherit; }
.frame .bgv-el { border-radius: inherit; }

/* ── The hero's own full-bleed backdrop ──────────────────────────────────────
   NOT the same thing as `.frame .bgv` above. That one is the cell footage INSIDE
   the hero's framed square. This is atmosphere behind the ENTIRE hero section.

   Why this is not just `.bgv-section`:
   the hero already stacks three decorative layers — .hero-canvas, two .glow
   blobs and .grid-lines — and every one of them sits at `z-index: var(--z-bg)`,
   which is 0. The section pattern puts a scrim at z-index 1, so applying it here
   would paint over all three; in light theme that scrim is
   rgba(246,247,249,0.78-0.92), a near-opaque white sheet across the hero's whole
   atmosphere. So there is no scrim here at all.

   Instead the video is the FLOOR: `z-index: 0` and FIRST in the markup, so with
   equal z-index the painting order puts it beneath the canvas, the glows and the
   grid, all of which keep working exactly as they did. The copy is untouched at
   `z-index: var(--z-content)` = 10, so legibility is a property of the existing
   layout and does not depend on this file or on the video ever loading.

   The opacities are lower than the section pattern's because this sits behind
   two other decorative layers rather than alone, and because the hero is the one
   place on the site where the words have to win. Light theme is much lower
   again: the footage is near-black, and on a near-white page anything higher
   reads as a smudge rather than as depth. */
.bgv-hero { z-index: 0; }
.bgv-hero .bgv-el { opacity: 0; }
.bgv-hero.is-playing .bgv-el { opacity: 0.32; }
:root[data-theme="light"] .bgv-hero.is-playing .bgv-el { opacity: 0.09; }

/* ── Section backgrounds ─────────────────────────────────────────────────────
   The video is the FLOOR of the section, and everything else stacks above it. */
.bgv-section { z-index: 0; }
.bgv-section .bgv-el { opacity: 0; }
.bgv-section.is-playing .bgv-el {
  /* Never full strength behind text. This is the single number that decides
     whether the section reads as "a page with atmosphere" or "a video with
     words on it" — the brand wants the former. */
  opacity: 0.28;
}

/* The scrim. Present whether or not video ever plays, so contrast is a
   property of the layout rather than a property of the network. Sits between
   the video and the content. */
.has-bgv { position: relative; isolation: isolate; }
.has-bgv > .bgv-section + * ,
.has-bgv > :not(.bgv-section) { position: relative; z-index: 2; }

.has-bgv::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(to bottom,
      rgba(var(--ink-rgb), 0.92) 0%,
      rgba(var(--ink-rgb), 0.78) 38%,
      rgba(var(--ink-rgb), 0.88) 100%);
}

/* Light theme needs a heavier veil than dark: dark text on bright footage is a
   far worse contrast case than light text on dark footage, because the video's
   own highlights blow through a thin scrim. */
:root[data-theme="light"] .has-bgv::before {
  background:
    linear-gradient(to bottom,
      rgba(var(--ink-rgb), 0.95) 0%,
      rgba(var(--ink-rgb), 0.88) 38%,
      rgba(var(--ink-rgb), 0.94) 100%);
}
:root[data-theme="light"] .bgv-section.is-playing .bgv-el { opacity: 0.20; }

/* ── Motion preference ───────────────────────────────────────────────────────
   bgvideo.js already refuses to construct a <video> at all under reduce, so
   this is a backstop for the case where the preference changes after the
   element exists and before the JS listener tears it down. Belt and braces:
   the cost of getting this wrong is making someone feel ill. */
@media (prefers-reduced-motion: reduce) {
  .bgv-el { display: none !important; }
  .bgv.is-playing .bgv-el { opacity: 0 !important; }
}

/* ── Print ───────────────────────────────────────────────────────────────────
   A poster frame is meaningless on paper and costs ink. */
@media print {
  .bgv { display: none !important; }
  .has-bgv::before { display: none !important; }
}
