From 33dcf39adf513806dde257d94d2d45dd7e9e9d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 18 Jun 2026 17:48:41 +0200 Subject: [PATCH] fix(a11y): hold revealed state under the reduced-motion backstop The global prefers-reduced-motion catch-all collapsed every animation to near-zero duration but left animation-fill-mode at its default, so an entrance animation whose element rests at opacity:0 and only reveals through its keyframe snapped back to the hidden base style once the near-instant animation completed. Under reduced motion that left charts and list rows permanently invisible. Pin animation-fill-mode:forwards and zero the stagger delay so the shortened reveal holds its final visible frame and paints immediately. Per-component blocks that set animation:none are unaffected (no animation to fill). --- src/app/globals.css | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/globals.css b/src/app/globals.css index e7892e703..73a7dd6d9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -896,13 +896,24 @@ * for reduced motion. The per-component blocks above stay — they carry * tailored static fallbacks (static dots, full-height bars). This is the * floor, not a replacement. Near-zero (not 0) keeps JS animation-end / - * transition-end listeners firing so state machines don't stall. */ + * transition-end listeners firing so state machines don't stall. + * + * `animation-fill-mode: forwards` + `animation-delay: 0ms` are load-bearing: + * several entrance animations rest at `opacity: 0` and only become visible + * through their reveal keyframe. Without holding the end state (and without + * zeroing the stagger delay) the near-zero animation completes and the + * element snaps back to its hidden base style — leaving charts and list + * rows permanently invisible under reduced motion. Forwards pins the final + * (revealed) frame; zero delay reveals immediately. Per-component blocks + * above that set `animation: none` are unaffected (no animation to fill). */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; + animation-fill-mode: forwards !important; + animation-delay: 0ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }