fix(decnet_web/Layout): theme swap animation no longer flashes opposite mode

Growing the NEW theme layer from circle(0) outward leaves a
one-frame gap where the new pseudo is fully opaque at full size
(the default state) before the clip-path animation registers.
Result: a flash of the destination theme right before the
reveal starts.

Inverted the layering and animation direction:
 - NEW theme snapshot sits on the bottom (z-index 0), static
 - OLD theme snapshot sits on top (z-index 1), shrinks via
   clip-path from circle(N) at click point down to circle(0)

The new layer is now hidden behind the old one until the old
shrinks away — no flash possible because the new layer was
never visible before the animation. Same 520ms duration, same
ease curve, same direction-of-travel from the user's POV
(circle expanding from cursor).
This commit is contained in:
2026-05-09 04:14:54 -04:00
parent 438a6e3e45
commit a81ea3f973
2 changed files with 20 additions and 7 deletions

View File

@@ -340,18 +340,26 @@ input:focus {
/* ── Theme transition ───────────────────────────
* Disables the default cross-fade so the JS-driven
* circle clip-path in useThemeToggle.ts owns the
* reveal entirely. The new theme grows from the
* click point; the old theme stays put and is
* uncovered by the expanding circle. */
* reveal entirely.
*
* Layering: the NEW theme snapshot sits behind, the
* OLD theme snapshot sits on top. The JS animation
* shrinks the old layer's clip-path from the
* viewport-covering circle down to circle(0) at the
* click point — burning away to reveal the new
* theme underneath. This avoids the one-frame flash
* you'd get by growing the new layer (where the
* default fully-opaque pseudo is visible for a tick
* before the clip-path animation registers). */
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-old(root) {
::view-transition-new(root) {
z-index: 0;
}
::view-transition-new(root) {
::view-transition-old(root) {
z-index: 1;
}