/* ky-wave — the wallpaper-switch wave: cursor-origin circular reveal of the
   incoming plate + wavefront-synced chrome theming. ky/ky-wave.js is the only
   writer of these classes.

   TWO PIECES, TWO CONTRACTS
   -------------------------
   1. .ky-wave-rv — the reveal layer. Mounted by JS inside each .ky-wall zone
      (AFTER the video, BEFORE .ky-wall-tint), so the zone's own duotone /
      wash / scrim / boost stack grades the incoming plate exactly as it
      grades the outgoing one — no treatment snap at commit. Only clip-path
      animates (compositor work); the outgoing wallpaper keeps playing
      underneath, untouched, for the entire reveal. On slide.html the
      treatment layers are opacity:0 by that page's own rule, so the same
      insertion point shows the plate clean there — one code path, both
      pages.

   2. .ky-wavefade — the per-element palette crossfade. JS stamps the theme
      custom properties INLINE on a chrome element the frame the wavefront
      reaches it; this class is what makes the resulting used-value changes
      fade instead of snap. The duration is per-element (--kyw-fade), scaled
      by JS to the time the front takes to traverse that element's box — so
      a word flips in ~180ms while the full-width wordmark grades over
      ~400-550ms and the flip never reads as one global snap.

      DELIBERATELY NOT IN THE LIST: filter. The wordmark's goo/roughen SVG
      filters (#goo-tight, #roughen on .ky-heroname) must never be touched
      or re-triggered by the wave — colour rides through the filter for
      free. transform/opacity are also excluded: the wave changes palette,
      never geometry, and hijacking those would fight every entrance and
      hover animation on the page. */

/* ---- the reveal layer ---------------------------------------------------- */
.ky-wave-rv {
  position: absolute;
  inset: 0;
  pointer-events: none;
  will-change: clip-path;
  contain: paint;
}

/* The picture lives on an inner element on purpose: clip-path resolves in
   the element's own box and is then carried by its transform, so a scale on
   the SAME node would drag the circle's centre off the cursor and inflate
   its radius. Outer clips, inner scales — by exactly the 1.06 that
   .ky-wall-still carries (and that the still's breath animation restarts
   from), so the framing at handoff is the same picture at the same size. */
.ky-wave-rv-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transform: scale(1.06);
}

/* The live video rides in the same layer and fades over its own poster the
   moment it can paint; if it never can, the poster is already there and
   nothing is missing. No transform, matching .ky-wall-vid. */
.ky-wave-rv-vid {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.4s linear;
}
.ky-wave-rv-vid.on { opacity: 1; }

/* ---- the per-element palette crossfade ----------------------------------- */
/* Inline custom-property stamps change USED values (color, backgrounds,
   shadows) instantly; this transition is what turns each flip into a fade.
   Descendants are included because chrome is registered at container level
   (#ky-music, #ky-cal, header nav ul) and the tokens resolve on the leaves.
   --kyw-fade is set inline per element by the tracker; 180ms is the floor
   for anything that flips without a measured traversal (late chrome caught
   by the commit retint).

   Specificity note: `.ky-wavefade *` is (0,1,0) — the same as a Tailwind
   utility on the leaf — and this sheet loads after the Next bundle, so the
   wave's transition wins for exactly the fade window and hands back the
   element's own transitions when JS removes the class after the fade
   completes. That momentary override is the accepted cost; a hover started
   mid-wave animates on the wave's clock for ~200ms, nothing worse. */
.ky-wavefade,
.ky-wavefade *,
.ky-wavefade *::before,
.ky-wavefade *::after {
  transition-property: color, background-color, border-color, outline-color,
    text-decoration-color, text-shadow, box-shadow, fill, stroke, caret-color;
  transition-duration: var(--kyw-fade, 180ms);
  transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: 0ms;
}

/* ---- reduced motion ------------------------------------------------------ */
/* JS never mounts a layer or stamps a fade under this query (it takes the
   instant-swap path); this is the belt-and-braces half, so a stale layer or
   class can never animate for a visitor who asked for stillness. */
@media (prefers-reduced-motion: reduce) {
  .ky-wave-rv { display: none !important; }
  .ky-wavefade,
  .ky-wavefade *,
  .ky-wavefade *::before,
  .ky-wavefade *::after {
    transition: none !important;
  }
}
