swarm-ui: page-switch animation (pop entrance + nav underline travel)

Shell's page content now remounts on every navigation and plays a
scale+fade pop-in entrance. The active nav link's underline is now a
single shared element that slides to its new position instead of
snapping, re-colouring to a per-tab accent — a discrete cycle through
the existing base16 chromatic slots, not a continuous hue rotation.
Both are gated on the data-motion/prefers-reduced-motion plumbing
lib/motion-apply.ts already had wired and waiting for a first real
consumer.
This commit is contained in:
iris 2026-08-19 19:16:53 +02:00 committed by mara
commit 6be1bbd4f7
3 changed files with 179 additions and 29 deletions

View file

@ -3,15 +3,14 @@
// when the override is "system" (letting `prefers-reduced-motion`
// alone decide, same as today).
//
// Currently inert: swarm-ui has zero CSS animations as of this file's
// writing (the design guide's "playful whimsy" motion — the matrix-rain
// home background — lives in the dashboard package, not swarm-ui). This
// hook exists because the settings surface itself was scoped to cover
// theme *and* motion together (both named in the same go-ahead), and the
// marginal cost of the storage/attribute plumbing is near zero riding
// alongside the theme override's real wiring — but there is genuinely
// nothing in swarm-ui for `data-motion` to gate yet. The first swarm-ui
// animation's own CSS is what makes this do anything, e.g.:
// Built ahead of swarm-ui having any CSS animation to gate — the
// settings surface itself was scoped to cover theme *and* motion
// together (both named in the same go-ahead), and the marginal cost of
// the storage/attribute plumbing was near zero riding alongside the
// theme override's real wiring. `Shell`'s page-switch animation (the
// nav indicator's slide + the page-body pop) is the first real
// consumer — see `shell/Shell.css`'s file-top comment for the
// three-rule gate shape every animation here follows:
// @media (prefers-reduced-motion: reduce) { ... }
// :root[data-motion='reduce'] { ... same rule ... }
// :root[data-motion='allow'] { /* opt back in despite OS-level reduce */ }