Skip to content

fix(auth): darken muted sign-in text to meet WCAG AA - #232

Merged
aspiers merged 4 commits into
mainfrom
fix/muted-foreground-contrast
Aug 4, 2026
Merged

fix(auth): darken muted sign-in text to meet WCAG AA#232
aspiers merged 4 commits into
mainfrom
fix/muted-foreground-contrast

Conversation

@aspiers

@aspiers aspiers commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

What

Changes --muted-foreground on the sign-in page from #999 to #666, and routes .divider through that variable instead of its own hard-coded #999.

Why

--muted-foreground carries the 13px terms line, the "Recover with backup email" link, the "or continue with" / "or use email" separators, and the "powered by Certified" footer. Measured against the two backgrounds those elements actually sit on:

card #F8F8F8 page #E8E8E8
#999 (current) 2.68:1 ❌ 2.33:1 ❌
#6b6b6b 5.02:1 ✅ 4.35:1 ❌
#666 (this PR) 5.41:1 ✅ 4.69:1 ✅

Both current values fall far below the 4.5:1 WCAG AA minimum for normal-size text — and below even the 3.0:1 large-text threshold, which does not apply at 13px anyway.

Screenshots

Both are real Railway preview deployments, not local mocks. The OTP step is shown so three consumers of the variable are in frame at once.

Before: muted text at #999 — washed out against the card, and worse against the page background behind the footer.

Before: low-contrast muted text

After: the same elements at #666, clearing AA on both backgrounds.

After: muted text meets WCAG AA

Computed colours at capture time confirm the swap reached every consumer: rgb(153,153,153) before, rgb(102,102,102) after, for .terms, .recovery-link and .powered-by alike.

Why #666 and not #6b6b6b

#6b6b6b was the value proposed alongside the spam-folder hint in #221, but it clears AA only against the card. .powered-by lives in .page-wrap outside .container, so it renders against the page background — visible in the screenshots above as the lighter band below the card — where #6b6b6b reaches just 4.35:1 and still fails at 13px. #666 passes on both and is a conventional shorthand.

The .divider follow-up

Copilot caught that .divider ("or continue with", "or use email") hard-coded color: #999 at 13px rather than using the variable, so darkening --muted-foreground would have left it behind at 2.68:1 — the same defect, in the one place that had opted out of the mechanism being fixed. Fixed in 6ed3d05.

Side effect worth recording: the divider now honours a branding.css override of --muted-foreground, which it previously ignored. Noted in the changeset's operator section. It does not appear in the screenshots because dividers only render when social providers are configured.

Provenance

Extracted from #221, where it rode along as an undocumented global change justified by a hint element that PR was adding. That hint is superseded by a resend-time message in #220, so the original motivation is gone — but the contrast defect predates #221 and stands on its own.

Testing

format, lint, typecheck all pass; 1084 unit tests pass. Contrast ratios computed with the WCAG 2.x relative-luminance formula.

🤖 Generated with Claude Code

--muted-foreground was #999, which carries the 13px terms line, the
"Recover with backup email" link, and the "powered by Certified"
footer. Measured against the two backgrounds those actually sit on:

  #999 on #F8F8F8 (card)  2.68:1
  #999 on #E8E8E8 (page)  2.33:1

Both are far below the 4.5:1 WCAG AA minimum for normal-size text,
and below even the 3.0:1 large-text threshold that does not apply at
13px anyway.

Use #666 (5.41:1 and 4.69:1). #6b6b6b was the value originally
proposed alongside the spam-folder hint in #221, but it clears AA
only on the card: .powered-by lives in .page-wrap outside
.container, so it renders on the page background where #6b6b6b
reaches just 4.35:1 and still fails. #666 passes on both, and is a
conventional shorthand.

Extracted from #221, where it rode along as an undocumented global
change. The hint that motivated it is gone — superseded by the
resend-time message — but the contrast defect predates that PR and
stands on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 3, 2026 19:19
@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9b6b1f6

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
epds-demo Ready Ready Preview Aug 4, 2026 1:34pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@aspiers, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 75421e40-8815-4391-9e3d-171451477ead

📥 Commits

Reviewing files that changed from the base of the PR and between a42d20a and 9b6b1f6.

⛔ Files ignored due to path filters (2)
  • docs/screenshots/pr-232-before-low-contrast-muted-text.png is excluded by !**/*.png
  • docs/screenshots/pr-232-muted-text-contrast.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • .changeset/muted-text-contrast-on-sign-in.md
  • packages/auth-service/src/routes/login-page.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@railway-app

railway-app Bot commented Aug 3, 2026

Copy link
Copy Markdown

🚅 Deployed to the ePDS-pr-232 environment in ePDS

Service Status Web Updated (UTC)
@certified-app/auth-service ✅ Success (View Logs) Web Aug 3, 2026 at 7:27 pm
@certified-app/demo untrusted ✅ Success (View Logs) Web Aug 3, 2026 at 7:22 pm
@certified-app/demo ✅ Success (View Logs) Web Aug 3, 2026 at 7:22 pm
@certified-app/pds-core ✅ Success (View Logs) Web Aug 3, 2026 at 7:21 pm

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the auth-service sign-in page’s “muted” text color token to improve readability and meet WCAG AA contrast for small (13px) text on both the card and page backgrounds, and documents the user/operator impact via a changeset.

Changes:

  • Darken --muted-foreground on the sign-in page from #999 to #666.
  • Add a changeset describing the accessibility/readability improvement and the operator-facing CSS variable change.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/auth-service/src/routes/login-page.ts Updates the inline CSS --muted-foreground variable used by small muted UI text on the sign-in page.
.changeset/muted-text-contrast-on-sign-in.md Adds release notes describing the end-user contrast improvement and operator guidance if overriding branding CSS.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/auth-service/src/routes/login-page.ts
@coveralls-official

coveralls-official Bot commented Aug 3, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 30914465432

Coverage remained the same at 57.672%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 3098
Covered Lines: 1782
Line Coverage: 57.52%
Relevant Branches: 1927
Covered Branches: 1116
Branch Coverage: 57.91%
Branches in Coverage %: Yes
Coverage Strength: 9.45 hits per line

💛 - Coveralls

.divider ("or continue with", "or use email") hard-coded color: #999
at 13px instead of using the variable, so darkening
--muted-foreground left it behind at 2.68:1 — the same defect this
branch exists to fix, in the one place that had opted out of the
variable.

Point it at var(--muted-foreground). Side effect worth noting: the
divider now honours a branding.css override of --muted-foreground,
which it previously ignored.

Caught by Copilot in review of #232.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 3, 2026 19:25
@aspiers

aspiers commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

the 13px .divider text is still hard-coded to #999

Good catch — fixed in 6ed3d05.

.divider ("or continue with", "or use email") opted out of the variable and hard-coded color: #999 at 13px, so darkening --muted-foreground left it behind at 2.68:1 against the card. That is exactly the defect this branch exists to fix, in the one place that had opted out of the mechanism being fixed. Both dividers render inside .container, so the card ratio is the relevant one.

It now uses var(--muted-foreground). One side effect worth recording: the divider will now honour a branding.css override of --muted-foreground, which it previously ignored — noted in the changeset's operator section.

(reply generated by Claude Opus 5 via Claude Code)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@railway-app
railway-app Bot temporarily deployed to ePDS / ePDS-pr-232 August 3, 2026 19:27 Destroyed
Both shots are of real Railway preview deployments rather than a
local mock: the "before" is PR #229's preview, which still serves
--muted-foreground: #999, and the "after" is this branch's own
preview at #666.

Captured on the OTP step so three of the variable's consumers are
in frame at once — the terms line, the "Recover with backup email"
link, and the "Powered by Certified" footer, the last of which sits
on the page background rather than the card and is the reason #666
was needed over #6b6b6b.

Computed colours at capture time confirm the swap reached every
consumer: rgb(153,153,153) before, rgb(102,102,102) after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 4 changed files in this pull request and generated no new comments.

Comment thread .changeset/muted-text-contrast-on-sign-in.md Outdated
The changeset filed the --muted-foreground override advice under
Operators, but branding.css is not an operator surface: it is a field
in the client's own client-metadata.json, and docs/configuration.md,
docs/tutorial.md and every prior CHANGELOG entry that mentions it
address client app developers.

An operator's only involvement is gating which client_ids may inject
CSS at all, via PDS_OAUTH_TRUSTED_CLIENTS — they never author the
file, so the adaptation instruction was pointed at the wrong reader.

Reattribute to Client app developers and reword accordingly ("your
override" rather than a third party's). Also note explicitly that a
value chosen to sit alongside the old #999 may itself be below AA,
which is the actionable part for anyone who did set it.

Raised by @aspiers in review of #232.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 4, 2026 13:34
@sonarqubecloud

sonarqubecloud Bot commented Aug 4, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (1)

.changeset/muted-text-contrast-on-sign-in.md:11

  • PR description says the divider side effect is noted in the changeset’s Operators section, but this changeset only lists “End users, Client app developers” in Affects: and has no Operators section. Either add Operators to the changeset (and document the divider/branding override impact there) or update the PR description so the release notes and PR narrative agree.
**Affects:** End users, Client app developers

**End users:** the 13px grey text — the terms line, the "Recover with backup email" link, the "or continue with" / "or use email" separators, and the "powered by Certified" footer — was too light to meet the WCAG AA contrast minimum against either the card or the page background behind it. It is now dark enough to pass on both.

**Client app developers:** the `--muted-foreground` custom property on the sign-in page changes from `#999` to `#666`. If your `branding.css` sets it, check your value clears 4.5:1 against both `#F8F8F8` (the card) and `#E8E8E8` (the page) — the old default reached only 2.68:1 and 2.33:1 respectively, so a value chosen to sit alongside it may be equally low. The separator text between the social and email sign-in options now follows `--muted-foreground` too, where it previously ignored your override and stayed grey.

@aspiers
aspiers merged commit d2736c3 into main Aug 4, 2026
21 checks passed
@aspiers
aspiers deleted the fix/muted-foreground-contrast branch August 4, 2026 13:41
@railway-app
railway-app Bot temporarily deployed to ePDS / ePDS-pr-232 August 4, 2026 13:41 Destroyed
aspiers added a commit that referenced this pull request Aug 4, 2026
Screenshots for a pull request are review ephemera. They have no value
to the codebase, they are binaries that git keeps forever, and GitHub
already hosts images attached to a PR body for free.

f4ff99f introduced docs/screenshots/ for #232 and it holds nothing but
those two files, so removing them takes the directory with it. The
three added for #220 were dropped from that branch before merge.

The blobs stay reachable in history; purging them would mean rewriting
main, which is not worth it for ~100KB.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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