Skip to content

Keep the reader's colour scheme and motion preference, and refuse a page that drops them #87

Description

@iderex

Depends on #63 and on #66.

The pages served today answer two questions about the reader's own machine, and
nothing in this plan says the generated ones have to:

for p in / /design-system.html; do
  printf "%-40s " "https://flowfin.dev$p"
  curl -sS "https://flowfin.dev$p" \
    | grep -o -i -E 'prefers-color-scheme: *[a-z]+|prefers-reduced-motion: *[a-z-]+|color-scheme: *[a-z ]+' \
    | sort -u | tr '\n' ' '
  echo ""
done
https://flowfin.dev/                     color-scheme:light dark prefers-color-scheme:dark
https://flowfin.dev/design-system.html   prefers-color-scheme: light prefers-reduced-motion: reduce prefers-reduced-motion:no-preference prefers-reduced-motion:reduce

Run 2026-08-08. The page that demonstrates the design system also carries the
motion it demonstrates:

curl -sS https://flowfin.dev/design-system.html \
  | grep -o -i -E '(transition|animation)[a-z-]*:' | sort | uniq -c
      1 animation:
      4 transition:

Run 2026-08-08. Both behaviours exist in what is published now, and the
generator in #4 is the thing that would drop them. Every check in this plan
stays green if it does. The byte budget in #34 counts bytes and would get a
smaller number. The audit in #36 runs at whatever the harness opens with. Its
contrast leg covers the colour vision presets rather than the scheme. #71 loads
a narrow viewport and enlarged text and says nothing about either of these. The
only party who finds out is a reader on a machine set to the other scheme, or
one who asked their system to reduce motion.

Two rules, both decidable by a machine, and neither of them a preference this
issue invents. They are what is published today, kept.

Every produced page follows the reader's colour scheme, and the document says
which schemes it supports so that a browser picks the right default background
and the right form control rendering before any stylesheet has been read.

Every produced page follows a request to reduce motion. Anything that moves sits
inside a query that switches it off. This is not a rule about whether the site
animates. It is a rule that the answer belongs to the reader.

Both legs run in the headless browser #63 pins, over every produced page, under
that browser's emulation of each preference, with the honesty rule the rest of
the plan uses: a browser that cannot start reds the run and never passes it.

The static half is cheaper and catches the ordinary case. A produced page
carrying a motion-bearing declaration that no reduce query switches off reds the
invariant gate in #14, by the same walk over the output that #85 uses for image
dimensions.

Where a value behind either behaviour is a token it comes from the pinned copy
#66 keeps, and nothing here defines one. That is #65's rule rather than a new
one.

Done when

Every produced page declares the schemes it supports and renders under each,
shown by the headless run loading every page under both emulated schemes; every
produced page renders with motion switched off under an emulated request to
reduce it, shown by the same run; a produced page carrying a motion-bearing
declaration outside a reduce query reds the invariant gate and the failure names
the page and the declaration; a browser that is present and cannot start reds
the run; and no colour value behind either behaviour is defined in this tree.

Metadata

Metadata

Assignees

Labels

blocked-on-another-issueWaits on work tracked by another open issue on this board.tests

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions