For users with vestibular disorders, a parallax hero is not delightful—it is nausea. That is why prefers-reduced-motion exists. But the common implementation—one media query that nukes every animation to zero—misreads the request. Users asked for reduced motion, not a frozen interface. Feedback animations are functional: the button press, the toast sliding in, the state change confirmation. Remove those and the reduced-motion experience is not calmer—it is broken.

Triage, not blanket removal

Sort your animations into three bins. Kill: parallax, scroll-scrubbed movement, auto-playing carousels, large translations—anything that moves content the user did not ask to move. Swap: entrances and exits—replace slides and zooms with plain opacity crossfades; the information (something appeared) survives without the travel. Keep: tiny, user-triggered feedback—color shifts, focus rings, sub-100ms presses.

/* Motion is the enhancement, stillness the default */
.card { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  .card {
    animation: slide-up .5s ease both;
    animation-timeline: view();
  }
}

Note the inversion: gate the fancy path behind no-preference, instead of patching it out afterwards. The reduced experience becomes your baseline—which also means it can never break by omission when someone adds a new animation and forgets the override.

“Reduced motion is a request for consideration, not a request for less craft.”

Systematise it

Route all durations and distances through custom properties—--motion-duration, --motion-distance—and the media query becomes three lines that retune the whole site: distances to zero, durations to near-instant, crossfades intact. In JavaScript, read matchMedia once and pass it to your animation calls. One decision, enforced everywhere—accessibility as architecture, not apology.