Resolves #14779
Ships the motion-contract SUBSTRATE under the signed disposition on the ticket (the #14929-owner ratification): #14779 owns the contract — this PR lands its load-bearing half, the piece every motion mechanism and every assertion surface consumes. The choreography transitions themselves (rail slide, splitter ease, tab morph, arrival settle) become CONSUMERS of this substrate — per the disposition they ride follow-up leaves/ranges, and the FLIP addon amends to consumer on its own branch (the #14929 owner's recorded ledger).
Evidence: L2 (six deterministic unit specs on the signal lifecycle + the token set is review-checkable SCSS) → L2 required (the substrate is pure projection-tier contract — class-toggle bookkeeping + theme tokens; nothing renders differently until consumers arrive, so live-motion evidence belongs to the consumer leaves). Residual: none for the substrate; consumer wiring evidence lands with each consumer.
AC map (against the ticket's disposition-scoped contract)
--dock-transition-* tokens as the ONLY duration/easing source → --dock-transition-duration: 260ms (the Demo-A design language's standard-decelerate midpoint as the token VALUE, never a call-site literal) + --dock-transition-easing, scoped on .neo-dashboard (the dashboard Container baseCls — reaches every dock surface).
- Token-layer
prefers-reduced-motion collapse → the media query zeroes the duration token in ONE place; no per-call-site checks anywhere, by construction.
dock-animating observability → Neo.dashboard.DockMotionSignal owns the neo-dashboard-dock-animating lifecycle: counted not boolean (concurrent motions nest; 0→1 adds, 1→0 removes), fail-safe force-clear (a lost leave can never wedge the signal — animation errors must never stall consumers), destroy-safe in both directions INCLUDING inside the fail-safe (the DOM-corpse defect family), unbalanced-leave tolerant (teardown paths call unconditionally). observe_motion e2e assertions and tour step-gating consume exactly this class.
- Zero motion state in documents/previews/persistence → nothing here touches a dock document; pure projection tier (review-checkable).
- Cross-family review → requested.
Deltas
resources/scss/src/dashboard/Container.scss — the token set + reduced-motion collapse on .neo-dashboard
src/dashboard/DockMotionSignal.mjs (new) — the signal lifecycle owner (core.Base sibling convention, static surface, injectable timers per the DockRevealStateMachine precedent)
test/playwright/unit/dashboard/DockMotionSignal.spec.mjs (new) — six specs: nesting, fail-safe force-clear + reuse, backstop re-arm, destroyed-component no-ops incl. corpse-safe fail-safe, unbalanced leaves, mid-flight destroy + leave
Test Evidence
npm run test-unit -- test/playwright/unit/dashboard/ --workers=1
202 passed
Post-Merge Validation
Process note: authored during the operator-granted temporary Fable 5 window.
Authored by Grace (Claude Fable 5, Claude Code). Session ef6b9a4a-54ec-4afb-8438-f89a3ee46ad2
Resolves #14779
Ships the motion-contract SUBSTRATE under the signed disposition on the ticket (the #14929-owner ratification): #14779 owns the contract — this PR lands its load-bearing half, the piece every motion mechanism and every assertion surface consumes. The choreography transitions themselves (rail slide, splitter ease, tab morph, arrival settle) become CONSUMERS of this substrate — per the disposition they ride follow-up leaves/ranges, and the FLIP addon amends to consumer on its own branch (the #14929 owner's recorded ledger).
Evidence: L2 (six deterministic unit specs on the signal lifecycle + the token set is review-checkable SCSS) → L2 required (the substrate is pure projection-tier contract — class-toggle bookkeeping + theme tokens; nothing renders differently until consumers arrive, so live-motion evidence belongs to the consumer leaves). Residual: none for the substrate; consumer wiring evidence lands with each consumer.
AC map (against the ticket's disposition-scoped contract)
--dock-transition-*tokens as the ONLY duration/easing source →--dock-transition-duration: 260ms(the Demo-A design language's standard-decelerate midpoint as the token VALUE, never a call-site literal) +--dock-transition-easing, scoped on.neo-dashboard(the dashboard Container baseCls — reaches every dock surface).prefers-reduced-motioncollapse → the media query zeroes the duration token in ONE place; no per-call-site checks anywhere, by construction.dock-animatingobservability →Neo.dashboard.DockMotionSignalowns theneo-dashboard-dock-animatinglifecycle: counted not boolean (concurrent motions nest; 0→1 adds, 1→0 removes), fail-safe force-clear (a lostleavecan never wedge the signal — animation errors must never stall consumers), destroy-safe in both directions INCLUDING inside the fail-safe (the DOM-corpse defect family), unbalanced-leave tolerant (teardown paths call unconditionally).observe_motione2e assertions and tour step-gating consume exactly this class.Deltas
resources/scss/src/dashboard/Container.scss— the token set + reduced-motion collapse on.neo-dashboardsrc/dashboard/DockMotionSignal.mjs(new) — the signal lifecycle owner (core.Base sibling convention, static surface, injectable timers per the DockRevealStateMachine precedent)test/playwright/unit/dashboard/DockMotionSignal.spec.mjs(new) — six specs: nesting, fail-safe force-clear + reuse, backstop re-arm, destroyed-component no-ops incl. corpse-safe fail-safe, unbalanced leaves, mid-flight destroy + leaveTest Evidence
Post-Merge Validation
DockMotionSignal(the owner's recorded ledger).observe_motionspecs againstneo-dashboard-dock-animating.Process note: authored during the operator-granted temporary Fable 5 window.
Authored by Grace (Claude Fable 5, Claude Code). Session ef6b9a4a-54ec-4afb-8438-f89a3ee46ad2