Skip to content

A11y: colour-contrast sweep — the gate's allowlist is now empty - #138

Merged
AdamXweb merged 2 commits into
mainfrom
fix/contrast-sweep
Jul 28, 2026
Merged

A11y: colour-contrast sweep — the gate's allowlist is now empty#138
AdamXweb merged 2 commits into
mainfrom
fix/contrast-sweep

Conversation

@adamXbot

Copy link
Copy Markdown
Collaborator

Summary

Fixes every colour-contrast suppression the a11y gate carried, driven by axe's own measured colour pairs (probed on all five scanned surfaces rather than guessed):

  • Light-theme --blue: #0071e3#0066cc — clears the active detail tab and footer links as text on tinted surfaces (4.2 → 5.0) and raises white-on-blue button labels (coachmark Next, task-journey CTA) to 5.6.
  • Floating pills (SiteInfoHint, kbd-hint): resting opacity 0.75 → 1 — the container opacity diluted the already-muted --text-2 links to ~3.1:1; the translucent color-mix background + blur keep the quiet look without the failure.
  • task-list.css: six var(--text-secondary, rgba(…, 0.85))var(--text-2, #6c6c80)--text-secondary is not a defined token anywhere, so the ~3.0:1 translucent fallback always fired. (Two were axe-flagged; the other four are the same defect in states the scans happened not to render — the source of the gate's TaskList state-flakiness.)
  • .home-layout-footer-secondary: drop the 0.85 opacity (3.9 → 5.4). .home-section-count: full --text on its tinted pill.
  • .detail-a11y-chip: theme-aware foreground (color-mix of --blue toward --text — darker in light mode, lighter in dark; 2.65 → ~4.9 on the grey hero surface), resting tint 18% → 12%, count pill on --text.
  • .nav-drawer-link + .count-badge: full-strength --text — the drawer is a translucent liquid-glass surface over arbitrary content, where muted text cannot guarantee 4.5:1 on every blend.

Gate changes

All contrast(…) allowlist entries, the helper, and the reason string are deleted — the a11y gate now runs with a completely empty allowlist. The dashboard and mobile-nav scans gain a 600ms settle so axe stops measuring the coachmark/drawer entrance animations mid-fade — the two previously state-dependent flags turn out to have been exactly that.

Verification

  • Standalone axe probe: zero contrast violations across all five surfaces post-fix.
  • a11y spec run twice back-to-back: identical, all green.
  • Full Playwright suite: 34 passed; 441 unit tests; typecheck + lint clean.
  • Dark theme: the changed selectors either use theme-aware tokens (--blue, --text) or improve in both themes; dark mode remains unmeasured by the gate (it scans the default colour scheme).

🤖 Generated with Claude Code

Fixes every colour-contrast suppression the a11y gate carried, using
axe's own measured pairs (probed on all five scanned surfaces):

- light-theme --blue: #0071e3 -> #0066cc. Clears the active detail
  tab and footer links as text on tinted surfaces (4.2 -> 5.0) and
  raises white-on-blue button labels to 5.6 (coachmark, task-journey).
- floating pills (SiteInfoHint, kbd-hint): resting opacity 0.75 -> 1 —
  it diluted the already-muted --text-2 links to ~3.1:1; the
  translucent color-mix background + blur keep the quiet look.
- task-list.css: six usages of var(--text-secondary, rgba(...,0.85))
  replaced with var(--text-2, #6c6c80) — --text-secondary is not a
  defined token, so the ~3.0:1 translucent fallback always fired.
- .home-layout-footer-secondary: drop the 0.85 opacity (3.9 -> 5.4).
- .home-section-count: full --text on its tinted pill (3.9 -> 7+).
- .detail-a11y-chip: theme-aware fg (color-mix of --blue toward
  --text; 2.65 -> ~4.9 on the grey hero surface), resting tint
  18% -> 12%, count pill uses --text on an 18% tint — compliant in
  both themes.
- .nav-drawer-link + .count-badge: full-strength --text — the drawer
  is a translucent liquid-glass surface over arbitrary content, where
  muted text cannot guarantee 4.5:1 on every blend.

Spec changes: all contrast() allowlist entries, the helper, and
R_CONTRAST are deleted — the gate now runs with an EMPTY allowlist.
The dashboard and mobile-nav scans gain a 600ms settle so axe stops
measuring the coachmark/drawer entrance animations mid-fade (the two
previously-flaky state-dependent flags were exactly that).

Verified with an axe probe (zero contrast violations on all five
surfaces), the a11y spec twice back-to-back (identical, green), the
full Playwright suite (34 passed), and 441 unit tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The new PostCSS advisory (path traversal via sourceMappingURL
auto-loading, disclosing arbitrary .map files; fixed in 8.5.18) fails
`pnpm audit --prod`, which gates the `quality` job on every branch AND
main's Docker publish — so main and all four open PRs went red at once
without anyone changing code.

The existing override was already `^8.5.12`, but a caret is not a
floor that moves: the committed lockfile had resolved 8.5.17, which is
vulnerable. Raising the override to `^8.5.18` and regenerating pulls
8.5.23. Same pattern, and same file, as the sharp and @babel/core
entries — the header comment now records why the caret alone wasn't
enough, since this will recur.

Verified: `pnpm audit --prod` reports no known vulnerabilities,
typecheck clean, 441 unit tests pass, and a full production build
emits CSS correctly (postcss is the stylesheet pipeline, so the build
is the real canary here, not the audit).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@adamXbot

Copy link
Copy Markdown
Collaborator Author

Cherry-picked the postcss advisory fix onto this branch so it goes green independently of merge order — see #141 for the full diagnosis.

Short version: a new PostCSS advisory (GHSA-r28c-9q8g-f849, fixed in 8.5.18) turned the quality job red on every open PR and on main's Docker publish, with nobody having changed code. The existing ^8.5.12 override wasn't enough — a caret is not a floor that moves, and the lockfile had resolved the vulnerable 8.5.17.

If #141 merges first, this commit drops out cleanly on rebase (identical patch).

🤖 Generated with Claude Code

@AdamXweb
AdamXweb merged commit 91fd260 into main Jul 28, 2026
16 checks passed
@AdamXweb
AdamXweb deleted the fix/contrast-sweep branch July 28, 2026 05:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants