Hot Pink Passes WCAG. That's the Problem.

WCAG's contrast formula was built for 1999 display calibration, not legibility. Hot pink on near-black scores 6.6:1 and passes — and isn't readable. OKCA closes the gap at the algorithm layer with chroma compression, polarity-aware scaling, and a zero-false-pass invariant — proven on the grey axis and verified across 1,249 production pairs and the sRGB gamut.

Accessibility WCAG-Compliance Standards-Governance Inclusive-Design Design-Strategy Systems-Integration Principal-Level Case-Study Open-Source Portfolio

A 1990s-style color calibration card centered on a deep navy field, with a single saturated hot-pink test patch at its visual center surrounded by muted reference patches in amber, burgundy, azure, cream, and teal — placing the post's exemplar failing color (hot pink) inside the kind of display-calibration instrument WCAG's contrast formula was originally designed for, not the legibility test it has come to serve as today.

Updated 2026-06-09.[1]

Executive Summary

WCAG 2.x's contrast formula was specified in 1999 for display calibration, not legibility. The math is achromatic and symmetric — properties that produce documented false passes for saturated chromatic text and erase the polarity distinctions designers treat as meaningful. Hot pink on near-black scores 6.6:1, a comfortable AA pass that isn't readable.

OKCA closes that gap at the algorithm layer. The interface stays intact (same 1–21 scale, same 4.5 and 7.0 thresholds), but the math underneath swaps in OKLCH L as the luminance input, applies a chroma-weighted penalty to the lighter element, and scales the final ratio asymmetrically by polarity. Hot pink on near-black drops to 3.7; the same-luminance neutral grey still passes.

OKCA is constrained by an FP = 0 invariant: it never approves a pair WCAG would reject — by construction on the grey axis, and verified across the sRGB gamut for chromatic colors. A 1,249-pair probe across light-on-dark, dark-on-light, and three production design systems (Tailwind, GOV.UK, USWDS) returns zero false passes and 111 intentional disagreements, all in the marginal zone where WCAG's 4.5 boundary is widely treated as too permissive. OKCA is on npm as @pawn002/okca, MIT-licensed.


The Gap

#ff69b4 on #1a1a1a scores 6.6:1 under WCAG 2.x, a comfortable AA pass. Anyone who has run a real audit will tell you it isn't readable for users with moderate contrast sensitivity loss. The math passes; the experience doesn't.

The gap isn't a bug. The formula is doing exactly what it was specified to do. The problem is that it was never designed to predict legibility. It was designed for display calibration in 1999, and twenty-five years later it underwrites nearly every accessibility ratio reported on the web.

I built OKCA to close the gap.

I've spent over a decade building accessibility tooling inside a special corner of the federal government. Contrast Chaser, a browser tool I built, picked up grassroots adoption there. OKCA comes from the same problem space: designers and accessibility engineers running into pairs that pass WCAG but don't work in production. The difference is that OKCA attacks it at the algorithm layer rather than the tooling layer.

What WCAG Is Computing

WCAG's contrast formula is a luminance ratio:

ratio=Y1+0.05Y2+0.05\text{ratio} = \frac{Y_1 + 0.05}{Y_2 + 0.05}

The luminance values YY come from linearised sRGB per IEC 61966-2-1, the 1999 display-calibration spec. Two consequences fall out, and both are well documented.

The formula is achromatic. Any two foreground colors at the same YY produce identical ratios regardless of hue or saturation. The neutral grey that matches hot pink's luminance is #9f9f9f (Y0.347Y \approx 0.347); on #1a1a1a it scores the same 6.6:1. Practitioners don't treat the two pairs the same way. The formula can't tell them apart.

It's also symmetric. ratio(A on B) = ratio(B on A), so light-on-dark and dark-on-light score identically. But designers treat polarity as a meaningful input. Light mode and dark mode are different decisions, not interchangeable, and the formula discards that distinction.

One failure produces false passes for chromatic text. The other hides asymmetry that practitioners end up encoding by hand.

What OKCA Does Instead

OKCA changes the math underneath and leaves WCAG's interface intact: same scale ([1, 21]), same AA threshold (4.5), same AAA threshold (7.0). Designers don't have to relearn the numbers.

OKLCH L as the luminance input. OKCA reads the L channel from OKLCH, the perceptually uniform lightness from the Oklab color space. For neutral greys, L3YWCAGL^3 \approx Y_{\text{WCAG}} holds to floating-point precision; the cube root inverts the perceptual transform back to linear luminance. So on the achromatic axis, OKCA and WCAG are reading the same numbers, just in a representation a designer can see directly in any modern color picker.

Chroma compression on the lighter element. This is where the false-pass problem gets fixed. The lighter element's lightness is penalised by a chroma-weighted power exponent: more saturation, larger penalty.[2] The exponent runs from 1.0 at fully achromatic up to 1.5 at fully saturated. Hot pink has Oklab chroma around 0.197, saturated enough to receive the full penalty. Its effective luminance proxy drops, the raw ratio falls with it, and OKCA scores hot pink on near-black at 3.7. Below AA. The same-luminance grey scores 5.4 and passes. The math now distinguishes what practitioners always could.

Polarity-aware scaling. OKCA's final step applies a power curve that differs by polarity: light-on-dark caps at 21, dark-on-light at 20. Same shape, different ceiling. White on black scores 21.0; black on white scores 20.0. White on #767676, the canonical WCAG AA boundary grey, scores 3.5 light-on-dark and 3.3 dark-on-light. Both fail AA. That matches how the pair gets treated in practice.

The FP = 0 Invariant

A contrast algorithm intended for accessibility decisions has one hard constraint: it must never approve a pair that WCAG would reject. The reason is asymmetry. A false pass ships inaccessible text to production. A false failure just nudges a designer toward a safer choice.

OKCA holds FP = 0: it never scores a pair above its WCAG ratio. On the grey axis this is exact by construction — the OKLCH proxy equals WCAG luminance, chroma compression only lowers the lighter element, and polarity scaling only lowers the ratio. Off the grey axis it's subtler: the proxy isn't WCAG luminance (greens, for instance, undershoot it), so for some chromatic pairs the raw ratio can edge above WCAG — and the polarity step is what pulls every score back under, with room to spare. Across the full sRGB gamut (the grey grid plus ~1.2M random and structured pairs, both polarities) OKCA never lands above WCAG. So FP = 0 is proven on the grey axis and verified across the gamut — a property I hold the algorithm to, not a closed-form theorem for literally every input. The analysis is in the design doc.

In practice: across the sRGB gamut, a designer who trusts the OKCA number won't accidentally ship text that WCAG would reject.

What the Probe Data Shows

The FP = 0 property rules out unsafe outputs. It doesn't show OKCA's numbers are calibrated — an algorithm that scored every pair at 1.0 would also satisfy FP = 0. The probe work tests calibration: does OKCA agree with WCAG where WCAG is right, and disagree only where practitioners would?

Three test batteries, 1,249 pairs total:

Battery Pairs False passes WCAG disagreements
Light-on-dark 53 0
Dark-on-light 54 0
Design systems 1,142 0 111
Total 1,249 0 111

The design systems battery pulls documented foreground/background pairs from Tailwind CSS v3.4 (46 disagreements), the GOV.UK Design System (15), and USWDS v3.x (50). These are production palettes maintained by teams that take accessibility seriously.

All 111 disagreements sit in the marginal zone, where OKCA scores below 4.5 and WCAG scores at or above it. They're intentional. WCAG's 4.5 boundary is widely treated as too permissive in production; white on #767676 clears the bar by definition, but in practice most teams avoid it. OKCA encodes that judgment into the math rather than leaving it to the designer's gut. Full enumeration with hex values is in WCAG_DISAGREEMENTS.md in the repo.

Zero false passes across 1,249 pairs. The 111 disagreements come with the math.

What OKCA Does Not Do

OKCA is just a contrast algorithm. It deliberately doesn't:

  • Model font size or weight. OKCA outputs a single ratio per pair. Size-dependent thresholds (WCAG AA's 3 for large text, 4.5 for normal) are the caller's responsibility.
  • Patch WCAG's green-channel weighting. Chroma compression is rotationally symmetric in a/b space. Hue-varying outcomes come from different hues reaching different chroma values at similar lightness, not from OKCA targeting specific hues.
  • Replace perceptual judgment. A pair that scores 4.5 clears the threshold but may still be harsh, too low-contrast in context, or wrong for the brand. The number is a floor, not a recommendation.

What's Next

OKCA is on npm as @pawn002/okca, MIT-licensed. The repo is pawn002/okca. The design document, including the FP = 0 analysis (by-construction on the grey axis plus gamut verification), is at docs/OKCA_DESIGN.md.

Try it in one line. No install required — npx klar-cli contrast "#ff69b4" "#1a1a1a" prints Contrast (OKCA): 3.7, the same hot-pink-on-near-black pair from the opening. klar is an MIT CLI that uses OKCA for its contrast engine.

OKCA is one independent attempt to close WCAG 2.x's contrast gaps. It is clean-room work, derived from public specifications, and accepts hex codes and CSS oklch()/oklab() natively.

If you maintain a design system, run your palette through it. If you find an sRGB pair OKCA scores higher than WCAG, that's a false pass. Open an issue. It would be a bug, and I'd want to know about it — it's a property I verify, not a theorem I assume, so the edge cases are exactly what I want.


  1. I've tightened how this post states the FP = 0 guarantee. A thorough gamut stress-test of the invariant — run after this post and the package were already published — showed the original framing ("enforced mathematically… unconditional for every input") overstated it: FP = 0 is provable by construction on the achromatic (grey) axis, but for chromatic colors it's a calibration property verified across the sRGB gamut, not a closed-form theorem. The zero-false-pass result itself is unchanged — the shipped algorithm still returns no false passes across every test (~1.2M evaluations); what changed is only the claim about why it holds. Original wording available on request. ↩︎

  2. Throughout this post I use "saturation" in the everyday sense, meaning how strong or colorful a hue appears to a viewer. OKCA's math operates on Oklab chroma, the absolute distance from neutral in a/b space. The two terms are closely related but not formally identical. ↩︎