Repository navigation
A11Y-001: the light theme's raw palette text is readable - #991
Conversation
The app writes Tailwind's light palette shades straight into class names, about 1,400 times (text-emerald-400, text-amber-300, hover:text-rose-300...). They were picked against the dark default; in the light theme they read at 1.2 to 2.8:1. The semantic tokens were darkened for light mode earlier; these never were. In .light, each hue's 200/300/400 shade and its hover and group-hover forms take the hue's lightest darker shade that keeps 4.5:1 on white, --bg, --surface and the hue's own 500/20 chip tint. Slash variants keep their alpha. The rule is the signed-in app's: marketing pages (which draw dark app screens in device mock-ups), forced-dark subtrees and .keep-dark-palette surfaces keep the original shades. A test computes every rule's ratios from the CSS and fails when a class the source uses has no rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
A11Y-001 / DARK-DISPLAY-PALETTE at120ec8e08f6392f51ae01272cfe3ea2967327f4e: source review finds a conditional /display regression outside the initial light-page samples. DisplayShell has no .dark/.keep-dark-palette boundary, but display-grid.tsx:718–738 uses a dark #0b1020/ambient/photo presentation. Its unavailable-data/timezone status text-amber-200 at778–780 is caught by the new global amber remap; edit-mode text-rose-300 delete control at854–860 sits on bg-black/75 and is caught too. CSS arithmetic predicts amber contrast2.67:1 instead of15.20:1 on #0b1020, and rose roughly1.7:1 instead of5.7:1 on the scrim over a light background. These are source-derived figures, not measured browser results. Bounded next task for this PR owner: protect intentionally dark display content with an appropriately scoped boundary and add real computed-style coverage of these conditional warning/edit states, alongside light/dark/excluded-page controls. Preserve #985's responsive assistant scroll padding during composition. Do not describe all /display states as unchanged until checked. Test qualification: the current unit test is source/formula-only, full-alpha RGB on synthetic grounds; it cannot prove computed cascade, alpha compositing, interactions or exclusion inheritance. Also review marker-bearing elements themselves (the exclusion currently targets descendants), and base/hover specificity: combining all arms in :is() gives base rules the maximum hover specificity. No concrete current cross-hue interaction regression is asserted, but include controls before claiming general variant coverage. Keep broad A11Y-001 open, retain exact-head test evidence and separate candidate from main. No merge/deploy or production configuration changes. |
…-correct rules Review on 120ec8e found three things, all real: - The wall display (#0b1020 backdrop) and Kitchen Mode (#07070d, full screen) stay dark in the light theme, with no boundary: the display's edit-mode delete control (rose-300) and status line (amber-200), and Kitchen Mode's amber/emerald text, were remapped. Both roots now carry .keep-dark-palette. - The exclusion matched descendants only; it now matches the marked (or dark, or marketing) element itself too. - Base and hover forms shared one :is(), so a base rule carried the hover arm's specificity and beat e.g. hover:text-white. Each form is now its own rule: a base rule has exactly its Tailwind class's specificity (variants, which Tailwind appends later, still win); a hover rule has one class more than the variant it replaces. tests/e2e/light-theme-palette-in-the-browser.spec.ts checks the computed cascade in Chromium: base, hover, group-hover and slash forms; hover:text-white still winning; marked element, marked/dark/marketing ancestors; the dark theme; an ordinary app page; the display's real edit mode (and, removing the boundary from the live root, the regression it prevents); Kitchen Mode with a due reminder. The unit test now also pins each rule's specificity. The new authenticated suite is excluded from CI failure evidence like the others. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
|
Re 6098380704: all three are real, and all three are addressed in 1. Dark presentations.
2. The marked element itself. The exclusion is now 3. Specificity. Each form is now its own rule:
Computed-style coverage (
Qualification. The unit test is formula-level by design. The browser spec is what proves the cascade, alpha and exclusion inheritance. Interactions beyond hover and group-hover (focus, aria-, data- variants) are not exercised; they are higher-specificity variants that Tailwind appends later, so they win by construction. The light-theme axe and computed-colour figures in the PR body are from Validation at
A11Y-001 stays open. Generated by Claude Code |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
A11Y-001, the light-theme half of the authenticated sweep from #990.
The defect
The app writes Tailwind's light palette shades straight into class names, about 1,400 times in 257 files:
text-emerald-400224×,text-amber-400195×,text-rose-400118×, and so on, plus over 120hover:andgroup-hover:forms. They were picked against the dark default theme. The light theme (a user toggle, andsystemon a light OS) darkened the semantic tokens earlier, but never these classes. On a light surface they read at 1.2 to 2.8:1, against WCAG's 4.5:1 for text and 3:1 for large text and icons. Examples:The fix
One generated block in
app/globals.css, in.lightonly:hover:andgroup-hover:forms, takes that hue's darker shade: the lightest one that keeps 4.5:1 on white, on--bg, on--surfaceand on the hue's own500/20chip tint. That is 800 for the light hues (emerald, amber, yellow, sky, …) and 700 for the darker ones (blue, rose, red, violet, …).text-emerald-300/80) keep their alpha.text-opacity-*still applies.The rule covers the signed-in app only. It does not apply on marketing pages (
.marketing-theme), whose device mock-ups draw dark app screens even in the light theme. There, 22 elements would have dropped from 5.3–13.4:1 to 1.6–2.8:1. It also skips forced-darksubtrees and any surface marked.keep-dark-palette. No measured surface needs that marker yet; it is the escape hatch.tests/light-theme-palette-text-is-readable.test.ts:Measured
All 246 signed-in, non-admin routes in a disposable Plus household, light theme, plus the 15 public routes. The "after" figures are from a production build of this branch.
maincolor-contrast, desktop 1280color-contrast, 390 px/displayfalse positive below)mainWhat is left is not in this rule's scope, and is the next tranche:
success/warning/danger/mutedtext on its own tinted chip, 4.2–4.4:1 (46 of the 60 desktop nodes, mostly the social-accounts and sync status chips);text-emerald-600on an emerald tint, 3.3:1);style="color:#fbbf24";On
/displayat 390 px, axe reports 40 nodes at 1.04:1, the same onmainand this branch. That is an axe false positive, not a defect. The display paints its own dark backdrop as a fixed-z-10layer, and the body's light background propagates to the canvas beneath that layer. axe takes the body's colour as the backdrop. A screenshot ofmainat 390×844 in the light theme shows the dark gradient with readable white text.Validation: the full unit suite passes (30,685), tsc 0, and eslint on the new test is clean. No component, configuration or dependency change.
🤖 Generated with Claude Code
https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
Generated by Claude Code