a11y: fix Welcome/Home dashboard contrast for WCAG AA (#565)
User description
Status: root cause found and fixed, evidence attached
Fixes #565.
Root cause
index.css's @media (prefers-reduced-motion: reduce) override for .aurora-blob (continuous 25s background float) and .animate-in (the Dashboard's staggered card fade-in) was declared before those classes' own unconditional base rules. With equal selector specificity and no cascade layers in this file, CSS resolves ties by source order — so the later, unconditional base rules always won. Reduced motion never actually froze either animation, for any user, including those who explicitly requested it.
This matches the original issue's own observation that "the exact failing nodes vary between retries": axe was sampling a page whose background was still perpetually animating (Aurora) and whose Dashboard cards were still mid-fade, producing different composited colors on every scan. It also explains why the flat semantic-token pairs in index.css were already correctly verified AA-compliant on their own — the defect was never in a static color value.
Fix
- Reordered the
@media (prefers-reduced-motion: reduce)block to after both base rules, so it actually wins the cascade as originally intended. - Added a deterministic Light+Sepia and Dark+Sepia Dashboard axe test (the exact combination from the historical report), plus a normal-motion, fully-settled-state test, so this can't silently regress again.
- Folded in a separate, authorized product change: default
appearancePresetswitched fromsepiatodefaultfor new sessions (explicit Sepia selections are preserved), with matching persisted-settings migration and updated unit tests.
Evidence
- Before the fix: CI's Light+Sepia and Dark+Sepia Dashboard axe scans failed with
color-contrastviolations whose fgColor/bgColor/contrastRatio swung significantly between retries of the identical, static (zero-value) project state — e.g. the "Worlds" stat label measured 2.38:1 in one run and 1.71:1 in another for the same DOM node. - After the fix: the same tests, plus a new normal-motion settled-state scan, pass deterministically on exact-head CI (
bf03c783), alongside a full green run (CI Success, CodeQL, Browser Quality/VRT+Lighthouse). - The first commit on this branch is unrelated housekeeping (CLAUDE.md doctor-trim, folded in per instruction).
Summary by Sourcery
Stabilize dashboard accessibility behavior and standardize the default appearance preset.
Bug Fixes:
- Ensure reduced-motion preferences reliably freeze Aurora and dashboard entrance animations, preventing transient visual states from causing accessibility contrast violations.
Enhancements:
- Make the standard appearance preset the default for new sessions and migrate invalid or removed legacy presets while preserving explicit Sepia selections.
- Improve dashboard accessibility coverage across light and dark Sepia themes and after normal-motion animations settle.
Documentation:
- Update design-system guidance to document the supported Default and Sepia appearance presets.
Tests:
- Update settings migration tests for the new default and add deterministic accessibility checks for loaded dashboards across appearance, theme, and motion states.
Chores:
- Simplify the repository directory map in CLAUDE.md.
Summary by cubic
Makes reduced motion actually freeze the Aurora background and dashboard card animations so the Welcome/Home dashboard renders statically, resolving the flaky contrast violations from #565. Also switches the default appearance preset from Sepia to standard default for new sessions.
Behavior changes
- The
prefers-reduced-motionoverride now wins the cascade, so.aurora-bloband.animate-instop animating when reduced motion is requested. - New sessions start on
default; legacy invalid stored values migrate todefault, and explicitsepiais preserved. - A11y tests explicitly select Writer's Sepia in light and dark schemes, wait for the lazy-loaded Dashboard to mount before scanning, and verify the fully-settled normal-motion state passes axe after fade-ins complete.
Migration
- VRT
writer.pngbaseline was regenerated from the CI-captured render; the home/characters/settings baselines passed unchanged.
Summary by CodeRabbit
-
Appearance
- The application now uses the Default appearance preset for new and previously unset settings.
- Existing Writer’s Sepia selections remain supported and can be chosen explicitly.
- Invalid or unrecognized saved appearance values now fall back to the Default preset.
- Fantasy and romance appearance options are no longer documented as supported themes.
-
Accessibility
- Improved light and dark Writer’s Sepia coverage across settings and dashboard views.
- Reduced-motion preferences now suppress Aurora animation while keeping content visible.
CodeAnt-AI Description
Use the standard appearance by default and verify dashboard accessibility across themes
What Changed
- New sessions and invalid or removed saved presets now use the standard appearance instead of Writer’s Sepia, while explicit Sepia selections remain unchanged
- Accessibility checks now cover both light and dark Sepia dashboards after the dashboard content has fully loaded
- Reduced-motion preferences now reliably stop decorative and entrance animations
- Design-system documentation now lists only the supported appearance presets
- Repository guidance and settings tests were updated to reflect the new default and preset migration behavior
Impact
✅ Standard appearance for new sessions
✅ Reliable reduced-motion behavior
✅ Verified light and dark Sepia dashboards
💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
@codeant-ai ask: Your question here
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
@codeant-ai ask: Can you suggest a safer alternative to storing this secret?
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
@codeant-ai: Your feedback here
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
@codeant-ai: Do not flag unused imports.
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
@codeant-ai: review
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.