html, body { margin: 0; height: 100%; background: #0a0011; overflow: hidden; }

  #stage {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100vh;   /* fallback for browsers without dvh */
    height: 100dvh;  /* track the live viewport so the mobile toolbar can't leave a gap */
    z-index: 0;
  }

  /* Two stacked background videos (double-buffered). Only .is-active is visible;
     the other preloads the next background so the swap during a glitch is instant. */
  .bg-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    display: block;
    opacity: 0;
  }
  .bg-video.is-active { opacity: 1; }

  /* Hue-shifted copy of the active video, blended on top. Hidden until a glitch
     burst. Only added by JS on roomy, non-data-saver devices (a 2nd video decode). */
  .glitch-ghost {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    object-fit: cover;
    object-position: center;
    display: block;
    z-index: 1;
    opacity: 0;
    mix-blend-mode: screen;
    pointer-events: none;
    will-change: transform, opacity, filter;
  }

  /* Scanline + neon-tint flash, only visible mid-burst. */
  .glitch-fx {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    z-index: 2;
    opacity: 0;
    pointer-events: none;
    background:
      repeating-linear-gradient(0deg, rgba(0,0,0,0.35) 0 1px, transparent 1px 3px),
      linear-gradient(90deg, rgba(255,43,179,0.22), rgba(38,255,230,0.22));
    will-change: opacity;
  }

  /* Each burst toggles body.glitch on for a few hundred ms; that runs these once.
     steps() gives hard digital cuts rather than a smooth tween. --g-dur is set per
     burst by JS so no two glitches are exactly the same length. */
  body.glitch #stage        { animation: vidGlitch   var(--g-dur, 360ms) steps(1, end) 1; }
  body.glitch .glitch-ghost { animation: ghostGlitch var(--g-dur, 360ms) steps(1, end) 1; }
  body.glitch .glitch-fx    { animation: fxGlitch    var(--g-dur, 360ms) steps(1, end) 1; }

  /* Base stays whole (the slicing happens on the ghost so we never flash to black);
     just a small jitter + colour flash. The scale hides the edge the jitter exposes. */
  @keyframes vidGlitch {
    0%   { transform: none; filter: none; }
    12%  { transform: translate3d(-3px,0,0) scale(1.03); filter: contrast(1.15) saturate(1.5) hue-rotate(8deg); }
    24%  { transform: translate3d(4px,0,0)  scale(1.03); filter: contrast(0.9) saturate(1.2) hue-rotate(-10deg); }
    36%  { transform: translate3d(-2px,0,0) scale(1.02); filter: brightness(1.1); }
    48%, 100% { transform: none; filter: none; }
  }

  @keyframes ghostGlitch {
    0%, 100% { opacity: 0; transform: none; }
    12% { opacity: 0.45; transform: translate3d(6px,0,0);  filter: hue-rotate(130deg)  saturate(3);   clip-path: inset(8% 0 62% 0); }
    24% { opacity: 0.40; transform: translate3d(-6px,0,0); filter: hue-rotate(-130deg) saturate(3);   clip-path: inset(40% 0 30% 0); }
    36% { opacity: 0.30; transform: translate3d(3px,0,0);  filter: hue-rotate(60deg)   saturate(2.5); clip-path: inset(68% 0 6% 0); }
    48% { opacity: 0; }
  }

  @keyframes fxGlitch {
    0%, 100% { opacity: 0; }
    10% { opacity: 0.5; }
    24% { opacity: 0.18; }
    38% { opacity: 0.38; }
    50% { opacity: 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    body.glitch #stage,
    body.glitch .glitch-ghost,
    body.glitch .glitch-fx { animation: none; }
  }

  /* ---- Mobile ---- */
  /* Portrait phones crop the wide video to a narrow centre strip. Bias the crop
     up toward her face/upper body so she sits anchored rather than low in frame.
     Nudge the second number (lower % = show more of the top, pulls her up). */
  @media (max-width: 900px) {
    .bg-video,
    .glitch-ghost { object-position: 50% 36%; }
  }

  @media (max-width: 480px) {
    .bg-video,
    .glitch-ghost { object-position: 50% 32%; }
  }

  /* ---- Sound toggle (bottom-right) ---- */
  #sound-toggle {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 5;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    padding: 0;
    color: #26ffe6;
    background: rgba(10, 0, 17, 0.45);
    border: 1px solid rgba(169, 94, 255, 0.5);
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.55;
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    transition: opacity .2s ease, box-shadow .2s ease, color .2s ease;
  }
  #sound-toggle:hover,
  #sound-toggle:focus-visible {
    opacity: 1;
    box-shadow: 0 0 12px rgba(38, 255, 230, 0.55);
    outline: none;
  }
  #sound-toggle .spk { fill: currentColor; }
  #sound-toggle .wave { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
  #sound-toggle .slash { stroke: currentColor; stroke-width: 2; stroke-linecap: round; display: none; }
  #sound-toggle.muted { color: #ff2bb3; }
  #sound-toggle.muted .wave { opacity: 0.2; }
  #sound-toggle.muted .slash { display: inline; }
  @media (max-width: 480px) {
    #sound-toggle { right: 12px; bottom: 12px; width: 40px; height: 40px; }
  }

  /* ---- Fullscreen toggle (sits just left of the sound toggle) ---- */
  #fs-toggle {
    position: fixed;
    right: 68px;   /* 16 + 44 + 8 = clears the sound toggle */
    bottom: 16px;
    z-index: 5;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    padding: 0;
    color: #26ffe6;
    background: rgba(10, 0, 17, 0.45);
    border: 1px solid rgba(169, 94, 255, 0.5);
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.55;
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    transition: opacity .2s ease, box-shadow .2s ease, color .2s ease;
  }
  #fs-toggle:hover,
  #fs-toggle:focus-visible {
    opacity: 1;
    box-shadow: 0 0 12px rgba(38, 255, 230, 0.55);
    outline: none;
  }
  #fs-toggle .fs-icon { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
  /* When fullscreen is active, swap the corner arrows to the "exit" (inward) glyph. */
  #fs-toggle .fs-exit { display: none; }
  #fs-toggle.is-fullscreen .fs-enter { display: none; }
  #fs-toggle.is-fullscreen .fs-exit { display: inline; }
  @media (max-width: 480px) {
    #fs-toggle { right: 60px; bottom: 12px; width: 40px; height: 40px; }
  }