haux.studio

Section 13

Accessibility

Every token pair in the system, scored against WCAG 2.x at build time. Four combinations fail; all four are named here with the substitute to use instead.

· 86 pairs measured

Pairs measured
86
Pass AA body · 4.5:1
46
Pass AA large · 3:1
52
Pass AAA · 7:1
29

Known failures

4 combinations in the palette do not meet their threshold. They are documented rather than removed, because they are already in circulation. A rule nobody knows they are breaking is not a rule.

  1. Still failing

    Stone is captioned as text and cannot be text

    The Figma colour sheet labels Stone #AA9F8D "Muted text", and it has been used that way in decks and in early product screens.

    Stone fails AA at every size, on every surface in the system. It is not a marginal miss. On Bone, the warm surface it most often appears over, it is less than half the required ratio. It stays in the palette as a decorative colour: rules, fills, illustration, texture. Never a glyph.

    • Stone on Near-white 1002.54:1 AA fails AA-L fails AAA fails
    • Stone on Bone2.03:1 AA fails AA-L fails AAA fails
    • Stone on Sage2.06:1 AA fails AA-L fails AAA fails
    • Near-white 700 on Near-white 1008.24:1 AA passes AA-L passes AAA passes

    Use instead: --haux-white-700 on --haux-white-100 · 8.24:1.

  2. Still failing

    White on Orange 500 fails AA body

    White text on an orange button is the default instinct, and it is what most of the early mockups do.

    It misses AA body by more than a point. There are two fixes and both are in the token set already: keep the Orange 500 fill and set the label in Near-black, or keep the white label and step the fill to Orange 600. The first is the house style, because --on-accent resolves to Near-black 900 for exactly this reason.

    • Near-white 100 on Orange 5003.47:1 AA fails AA-L passes AAA fails
    • Near-black 900 on Orange 5005.72:1 AA passes AA-L passes AAA fails

    Use instead: --haux-black-900 on --haux-orange-500 · 5.72:1.

  3. Still failing

    Orange 500 is not a text colour on light surfaces

    The accent is the brand, so it gets reached for as a link colour and as a heading colour.

    As text on Near-white it lands in the same place as white-on-orange: enough to be seen, not enough to be read. Orange 700 carries the same accent identity at more than twice the ratio, and is what --accent-text resolves to. Orange 500 remains correct as a fill, a rule, or a mark.

    • Orange 500 on Near-white 1003.47:1 AA fails AA-L passes AAA fails
    • Orange 700 on Near-white 1008.54:1 AA passes AA-L passes AAA passes

    Use instead: --haux-orange-700 on --haux-white-100 · 8.54:1.

  4. Still failing

    Silver misses the 3:1 non-text threshold

    Silver #AFAFAF is specified as the border colour, and --border resolved to it.

    Borders and focus rings are held to 3:1 under WCAG 2.x §1.4.11, and Silver does not reach it on Near-white. This is the failure that audits miss, because contrast tooling looks at text. Silver stays as a decorative rule; anything a person has to locate (an input boundary, a focus ring) uses a darker step.

    • Silver on Near-white 1002.14:1 3:1 non-text fails
    • Near-white 500 on Near-white 1003.28:1 3:1 non-text passes

    Use instead: --haux-white-500 on --haux-white-100 · 3.28:1.

The matrix

Every ink against every surface, in both themes. Computed at build time from the token values, so this table cannot disagree with the colour section.

  • AAA · 7:1 and above
  • AA body · 4.5:1
  • AA large only · 3:1
  • Below 3:1 · text prohibited

Light theme

Every ink the system offers, against every surface it can land on. Ratios are measured against Near-white 100, the actual value of --surface, not against pure white.

Light theme contrast matrix: inks down the side, surfaces across the top, WCAG 2.x ratios in each cell.
Ink \ SurfaceNear-white 100--surfaceCloud--surface-subtleSage--surface-raisedBone--surface-warmNear-black 900--surface-inverseOrange 500--accentOrange 600--accent-fill
Near-black 900--ink19.87Near-black 900 on Near-white 100, 19.87:1, passes AAA16.94Near-black 900 on Cloud, 16.94:1, passes AAA16.09Near-black 900 on Sage, 16.09:1, passes AAA15.89Near-black 900 on Bone, 15.89:1, passes AAASame colour, not applicable5.72Near-black 900 on Orange 500, 5.72:1, passes AA body3.58Near-black 900 on Orange 600, 3.58:1, passes AA large text only
Umber--ink-secondary7.46Umber on Near-white 100, 7.46:1, passes AAA6.36Umber on Cloud, 6.36:1, passes AA body6.04Umber on Sage, 6.04:1, passes AA body5.96Umber on Bone, 5.96:1, passes AA body2.66Umber on Near-black 900, 2.66:1, fails at every size2.15Umber on Orange 500, 2.15:1, fails at every size1.34Umber on Orange 600, 1.34:1, fails at every size
Near-white 700--ink-muted8.24Near-white 700 on Near-white 100, 8.24:1, passes AAA7.03Near-white 700 on Cloud, 7.03:1, passes AAA6.68Near-white 700 on Sage, 6.68:1, passes AA body6.59Near-white 700 on Bone, 6.59:1, passes AA body2.41Near-white 700 on Near-black 900, 2.41:1, fails at every size2.37Near-white 700 on Orange 500, 2.37:1, fails at every size1.48Near-white 700 on Orange 600, 1.48:1, fails at every size
Stone2.54Stone on Near-white 100, 2.54:1, fails at every size2.17Stone on Cloud, 2.17:1, fails at every size2.06Stone on Sage, 2.06:1, fails at every size2.03Stone on Bone, 2.03:1, fails at every size7.82Stone on Near-black 900, 7.82:1, passes AAA1.37Stone on Orange 500, 1.37:1, fails at every size2.19Stone on Orange 600, 2.19:1, fails at every size
Orange 500--accent3.47Orange 500 on Near-white 100, 3.47:1, passes AA large text only2.96Orange 500 on Cloud, 2.96:1, fails at every size2.81Orange 500 on Sage, 2.81:1, fails at every size2.78Orange 500 on Bone, 2.78:1, fails at every size5.72Orange 500 on Near-black 900, 5.72:1, passes AA bodySame colour, not applicable1.60Orange 500 on Orange 600, 1.60:1, fails at every size
Orange 600--accent-fill5.56Orange 600 on Near-white 100, 5.56:1, passes AA body4.74Orange 600 on Cloud, 4.74:1, passes AA body4.50Orange 600 on Sage, 4.50:1, passes AA body4.44Orange 600 on Bone, 4.44:1, passes AA large text only3.58Orange 600 on Near-black 900, 3.58:1, passes AA large text only1.60Orange 600 on Orange 500, 1.60:1, fails at every sizeSame colour, not applicable
Orange 700--accent-text8.54Orange 700 on Near-white 100, 8.54:1, passes AAA7.28Orange 700 on Cloud, 7.28:1, passes AAA6.92Orange 700 on Sage, 6.92:1, passes AA body6.83Orange 700 on Bone, 6.83:1, passes AA body2.33Orange 700 on Near-black 900, 2.33:1, fails at every size2.46Orange 700 on Orange 500, 2.46:1, fails at every size1.54Orange 700 on Orange 600, 1.54:1, fails at every size
Near-white 100--ink-inverseSame colour, not applicable1.17Near-white 100 on Cloud, 1.17:1, fails at every size1.23Near-white 100 on Sage, 1.23:1, fails at every size1.25Near-white 100 on Bone, 1.25:1, fails at every size19.87Near-white 100 on Near-black 900, 19.87:1, passes AAA3.47Near-white 100 on Orange 500, 3.47:1, passes AA large text only5.56Near-white 100 on Orange 600, 5.56:1, passes AA body

Dark theme

The derived dark token set. The accent moves from Orange 500 to Orange 400 here, which is the whole reason the dark theme needed its own audit rather than an assumption.

Dark theme contrast matrix: inks down the side, surfaces across the top, WCAG 2.x ratios in each cell.
Ink \ SurfaceNear-black 900--surfaceNear-white 900--surface-subtleNear-black 800--surface-raisedEspresso--surface-warmOrange 500--accent-fillOrange 400--accent
Near-white 100--ink19.87Near-white 100 on Near-black 900, 19.87:1, passes AAA18.26Near-white 100 on Near-white 900, 18.26:1, passes AAA15.69Near-white 100 on Near-black 800, 15.69:1, passes AAA12.61Near-white 100 on Espresso, 12.61:1, passes AAA3.47Near-white 100 on Orange 500, 3.47:1, passes AA large text only2.56Near-white 100 on Orange 400, 2.56:1, fails at every size
Near-white 300--ink-secondary12.69Near-white 300 on Near-black 900, 12.69:1, passes AAA11.67Near-white 300 on Near-white 900, 11.67:1, passes AAA10.03Near-white 300 on Near-black 800, 10.03:1, passes AAA8.06Near-white 300 on Espresso, 8.06:1, passes AAA2.22Near-white 300 on Orange 500, 2.22:1, fails at every size1.63Near-white 300 on Orange 400, 1.63:1, fails at every size
Near-white 400--ink-muted9.08Near-white 400 on Near-black 900, 9.08:1, passes AAA8.35Near-white 400 on Near-white 900, 8.35:1, passes AAA7.18Near-white 400 on Near-black 800, 7.18:1, passes AAA5.76Near-white 400 on Espresso, 5.76:1, passes AA body1.59Near-white 400 on Orange 500, 1.59:1, fails at every size1.17Near-white 400 on Orange 400, 1.17:1, fails at every size
Orange 400--accent7.76Orange 400 on Near-black 900, 7.76:1, passes AAA7.13Orange 400 on Near-white 900, 7.13:1, passes AAA6.13Orange 400 on Near-black 800, 6.13:1, passes AA body4.93Orange 400 on Espresso, 4.93:1, passes AA body1.36Orange 400 on Orange 500, 1.36:1, fails at every sizeSame colour, not applicable
Orange 300--accent-text11.65Orange 300 on Near-black 900, 11.65:1, passes AAA10.71Orange 300 on Near-white 900, 10.71:1, passes AAA9.20Orange 300 on Near-black 800, 9.20:1, passes AAA7.39Orange 300 on Espresso, 7.39:1, passes AAA2.03Orange 300 on Orange 500, 2.03:1, fails at every size1.50Orange 300 on Orange 400, 1.50:1, fails at every size
Near-black 900--ink-inverseSame colour, not applicable1.09Near-black 900 on Near-white 900, 1.09:1, fails at every size1.27Near-black 900 on Near-black 800, 1.27:1, fails at every size1.58Near-black 900 on Espresso, 1.58:1, fails at every size5.72Near-black 900 on Orange 500, 5.72:1, passes AA body7.76Near-black 900 on Orange 400, 7.76:1, passes AAA

Non-text contrast

Borders, focus rings and dividers are held to 3:1 under WCAG 2.x §1.4.11. This is the threshold that gets skipped, because contrast tooling measures text.

Non-text contrast · threshold 3:1
UsePairRatio3:1Verdict
Input border · Silver on Near-white 100--haux-silver2.14:1 3:1 failsFails. Silver is a decorative rule only. Interactive borders use Near-white 500 or darker.
Substitute · Near-white 500 on Near-white 100--haux-white-5003.28:1 3:1 passesPasses the 3:1 non-text threshold. Use this for input borders and any boundary a person has to find.
Divider · Mist on Near-white 100--haux-mist1.44:1 3:1 failsBelow 3:1, and that is acceptable: a divider is decoration, not a control boundary.
Focus ring · Orange 600 on Near-white 100--haux-orange-6005.56:1 3:1 passesPasses. This is what --focus-ring resolves to in the light theme.
Focus ring · Orange 500 on Near-white 100--haux-orange-5003.47:1 3:1 passesPasses 3:1 by a margin thin enough to disappear on a poor display. Orange 600 is the specified ring.
Focus ring · Orange 300 on Near-black 900--haux-orange-30011.65:1 3:1 passesPasses. This is what --focus-ring resolves to in the dark theme.
Border · Near-black 700 on Near-black 900--haux-black-7001.82:1 3:1 failsFails 3:1. Dark-theme control borders need Near-black 500 or lighter.
Substitute · Near-black 500 on Near-black 900--haux-black-5004.62:1 3:1 passesPasses. Use for interactive boundaries in the dark theme.