Contrast
Masking and contrast are the same axis pointing opposite ways, and only one end of it has ever been measured here. Every rung below is live. Read down until you cannot read them, and that is the answer nothing in this repository can supply.
min(swing) / |text − background|, so high contrast means
a large separation means a low ratio. Measured on stroke-width bars: at 4.21:1
a single captured frame is readable, at 2.26:1 it is marginal, at 1.72:1 it is
masked. What nobody has established is where you stop being able to read
it, and the answer decides whether a usable band exists at all.
The midpoint is held constant down the ladder so only the separation changes. Mid-grey has the most headroom in both directions, so it is the friendliest place for the split. Drag it toward either end and watch the masking column fall away even at separations that were fine before.
Colour, not just separation
The ladder above is grey, so it only tests how far apart the two tones are. Real designs have a hue, and hue matters for a reason that is not obvious: swing is per channel. A saturated colour has at least one channel near 0 or 255, that channel has no room to be displaced, and the pair cannot carry noise however far apart the two colours look.
Same separation in every cell below. Only hue and saturation change.
fit
desaturates when it has to.
min(swing) / separation and 4:1 is a large separation.
The ladder above measures it live if you want the numbers on your own pair.
That does not make 4:1 wrong, it makes it a different product. The anti-scraping half does not depend on the palette at all: the value is canvas pixels either way, so it is absent from the DOM, the accessibility tree,
innerText and Select All whatever the contrast. Choose 4:1 and you
keep every one of those absolutely, and give up the capture story. Choose 2:1
and you keep both, at a contrast below WCAG AA for body text.
Pick a pair
Text and background hue move independently here, because a coloured accent on a neutral ground is a real design and the solved row below only ever pairs a hue with itself. Every slider previews what it produces.
Palettes at a contrast you choose
Pick a contrast and every hue below is solved to hit it, so you can compare colours rather than greys at the readability level you actually want. The lightness pair is searched per hue, because the same two lightnesses give different contrast at different hues.
What to look for
- Read down until it stops being legible. Glance and read, do not stare it into focus. The rung above where you fail is your floor.
- Then look at the masking column at that rung. If it is 1.0 or better there is a usable band. If it is well under 1.0 then legibility and masking do not overlap at this midpoint, and the honest answer is that this palette cannot do both.
- Check the leak column too. Masking ratio is a prediction; the leak is what one captured frame actually gives away, measured on this text.