/* Radial reveal on theme swap (Chrome/Edge — falls back instantly elsewhere) */
@supports (view-transition-name: a) {
  html.vt-theme-swap::view-transition-old(root),
  html.vt-theme-swap::view-transition-new(root){
    animation: none;
    mix-blend-mode: normal;
  }
  /* The NEW layer is live content — repainting it per frame cost ~88ms/frame. It now sits
     still underneath while the OLD layer (an already-rasterised texture) carries the motion:
     two mask layers composited with subtract cut a growing circular hole out of the old
     theme, revealing the new theme beneath it. */
  html.vt-theme-swap::view-transition-new(root){
    z-index: 1;
    animation: none !important;
  }
  html.vt-theme-swap::view-transition-old(root){
    z-index: 2;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    animation: jc-theme-hole 1000ms linear both !important;
  }
  /* The snapshot pair must not cross-fade — that fade is the flicker seen mid-sweep. */
  html.vt-theme-swap::view-transition-image-pair(root){
    isolation: auto;
  }
  /* Chrome also runs its OWN 250ms animation on the group. It finished a third of the way
     through the 620ms reveal, and that discontinuity is the mid-sweep glitch. The group
     must hold still and let the clip-path reveal be the only motion. */
  html.vt-theme-swap::view-transition-group(root){
    animation: none !important;
  }
}
@keyframes jc-theme-reveal {
  from { clip-path: circle(0 at var(--vt-x, 50%) var(--vt-y, 50%)); }
  to   { clip-path: circle(var(--vt-r, 150vmax) at var(--vt-x, 50%) var(--vt-y, 50%)); }
}
