Four transition declarations in the whole of src/, across roughly 225 style rules:
checklist-editor.component.scss transition: width 120ms ease-out
placeholder-panel.component.scss transition: transform 120ms ease
_mixins.scss (two, inside one mixin)
So: no transition on a card's hover, none on the action pill appearing, none on a menu or a dialog opening, none on the selection bar arriving, none on the undo banner, none on a chip becoming active. Every state change is a hard cut.
It is not a defect — everything works, and it is fast. It is the difference a reader registers between "quick" and "finished", and it is the cheapest of the ten points to buy.
Shape
Two or three durations as custom properties, and a short list of places:
--motion-fast: 120ms for what follows the pointer — hover fills, the card's action pill, chip states, the rail's rows.
--motion: 160ms for what enters — menus, dialogs, the selection bar, the undo banner, the status toast.
transform and opacity only. A transition on height, width or a colour on a list of cards is what makes a canvas feel heavy, and the canvas renders every note with no virtualisation.
⚠️ prefers-reduced-motion is currently handled in one place, because there was almost nothing to handle. Adding motion means a single global block that reduces every one of these to 0ms, written in the same pass rather than after.
⚠️ The action pill is opacity: 0 until hover, and its opacity declaration has to stay after @include unstyled-control — the mixin expands to all: unset, which resets it. A transition added above the mixin is silently dropped.
⚠️ note-card.component.spec.ts and two e2e specs read boxes while the buttons are at opacity: 0, which works because opacity does not affect layout. A transition on transform would, so keep the pill's entrance to opacity.
Done when
Hover, menus, dialogs and the transient bars ease rather than cut, reduced motion turns all of it off in one rule, and the canvas is no slower to scroll than it is today.
Four
transitiondeclarations in the whole ofsrc/, across roughly 225 style rules:So: no transition on a card's hover, none on the action pill appearing, none on a menu or a dialog opening, none on the selection bar arriving, none on the undo banner, none on a chip becoming active. Every state change is a hard cut.
It is not a defect — everything works, and it is fast. It is the difference a reader registers between "quick" and "finished", and it is the cheapest of the ten points to buy.
Shape
Two or three durations as custom properties, and a short list of places:
--motion-fast: 120msfor what follows the pointer — hover fills, the card's action pill, chip states, the rail's rows.--motion: 160msfor what enters — menus, dialogs, the selection bar, the undo banner, the status toast.transformandopacityonly. A transition onheight,widthor a colour on a list of cards is what makes a canvas feel heavy, and the canvas renders every note with no virtualisation.prefers-reduced-motionis currently handled in one place, because there was almost nothing to handle. Adding motion means a single global block that reduces every one of these to0ms, written in the same pass rather than after.opacity: 0until hover, and itsopacitydeclaration has to stay after@include unstyled-control— the mixin expands toall: unset, which resets it. A transition added above the mixin is silently dropped.note-card.component.spec.tsand two e2e specs read boxes while the buttons are atopacity: 0, which works because opacity does not affect layout. A transition ontransformwould, so keep the pill's entrance to opacity.Done when
Hover, menus, dialogs and the transient bars ease rather than cut, reduced motion turns all of it off in one rule, and the canvas is no slower to scroll than it is today.