The blunt instrument, which kills every transition and animation on the page:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Near-zero rather than none, so animationend and transitionend events still fire and code waiting on them doesn't hang.
In JavaScript, check before you start anything that moves:
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches
The logo shuffle on this site skips itself when that is true.