Back to blog
EngineeringJun 26, 2026· min read

Dark-Mode WCAG AA Contrast Audit: Four Violations Found, TDD Guardrails Shipped

We audited all six Aurora design tokens against SC 2.0's three dark background surfaces and found four WCAG AA violations. Here's what we caught, how we're enforcing it with TDD, and what's next for accessibility automation.

We shipped a comprehensive WCAG AA contrast audit for Strug City 2.0's dark-mode design system. The audit covered all six Aurora color tokens (green, teal, blue, purple, pink, cyan) tested against three dark background surfaces defined in our globals.css. We used static analysis—no dev server required—to measure contrast ratios using the WCAG relative luminance formula.

What We Found

Four WCAG AA failures emerged from the audit, all in component source files:

  • FAIL-1: ProductCard Beta/Alpha/Research status badges using aurora-purple at 4.11:1 (need 4.5:1). The 10px mono font is normal text, requiring the higher threshold.
  • FAIL-2: ProductCard tag chips using aurora-blue (3.67:1), aurora-purple (3.82:1), and aurora-pink (3.44:1). All three pass the 3:1 UI component threshold but fail the 4.5:1 text requirement. These are 12px text labels, not graphical objects.
  • FAIL-3: BuiltOnAntiStrug CTA button purple variant at 4.12:1. The component appears on every product page (Sabine, Strug Works, Poppin, Sports), making this a high-visibility issue.
  • FAIL-4: aurora-purple label text on bg-surface at 4.49:1—a borderline miss by 0.01. Affects BuiltOnAntiStrug 'Built On' labels and ArchitectureRow proof-point labels when using purple accent.

The good news: aurora-green, aurora-teal, and aurora-cyan pass on all surfaces with contrast ratios ranging from 9.87:1 to 15.69:1. All utility text colors (primary, secondary, muted) passed, as did Navbar, Footer, HomeHero CTAs, and ProductCard GA/In Development badges.

How We Audited

We built a Python script (scripts/contrast-audit.py) implementing the WCAG relative luminance formula. The script computes exact contrast ratios for every token against every background surface, handles alpha-compositing for reduced-opacity variants (like text-aurora-green/90 or bg-card/60), and validates against WCAG AA thresholds: 4.5:1 for normal text, 3.0:1 for large text or UI components.

The audit was pure static analysis. We read component source files directly, identified every text usage of Aurora tokens and utility colors, computed luminance values for all three dark backgrounds (body #060611, surface #0f0f1a, card #161625), and calculated contrast ratios for each token-background pair. No dev server, no browser screenshots—just math.

TDD Enforcement

We created test_contrast_audit_audit.py with 18 test cases enforcing three critical guardrails:

  • Alpha compositing must use round(), not int(). When compositing rgba(22, 22, 37, 0.6) on rgb(6, 6, 17), int(15.6) = 15 but round(15.6) = 16. That one-unit difference affects borderline contrast calculations. Five test cases enforce correct rounding on all three RGB channels.
  • Hex input validation rejects malformed colors. The script must raise ValueError on 3-digit shorthand (#fff), wrong-length strings (#12345), and non-hex characters (#gggggg). Silent corruption is worse than a crash.
  • Alpha values outside [0, 1] must raise ValueError. alpha=1.5 produces RGB channels > 255; alpha=-0.2 produces negative channels. Both are invalid and must be caught.

The test suite also verifies WCAG formula correctness: black on white = 21:1, identical colors = 1:1, and aurora-purple on surface = 4.49:1 (confirming FAIL-4). One test even enforces code style—'import math' is unused and must be removed.

What's Next

We have a clear remediation path documented in the audit. FAIL-1 and FAIL-3 are high priority—both involve customer-facing product surfaces. The fixes are low-effort: add higher-contrast purple variants for badge text or increase font weight. FAIL-2 requires dropping the /10 background tint from ProductCard tag chips and using border-only styling. FAIL-4 is borderline (missed by 0.01) and can be fixed by lightening aurora-purple by three RGB units.

The broader opportunity is automation. This audit was manual static analysis—we read component files and computed ratios by hand. The script and test suite prove we can automate this. The next step is integrating contrast ratio validation into CI so every new Aurora token usage is checked before merge.

We're also considering a pre-commit hook that runs contrast-audit.py and flags violations at dev time. Catching WCAG failures in the editor is better than catching them in PR review. The tooling is already built—we just need to wire it into the development workflow.

This audit identified real issues and gave us the tools to prevent new ones. WCAG compliance isn't a checklist item—it's a design constraint enforced by math. We're shipping accessible interfaces by making contrast failures impossible to merge.