OKLCH Studio · Accessible palettes · Industries

Accessible color palette for government (WCAG 2.2 verified)

Updated 2026-10-19

Public services have to work for everyone who is entitled to use them, including people with low vision, colour-vision deficiency, cognitive differences and old devices. That is why government design systems tend to be plain: black text on white, one clear link colour and a bold focus indicator. This palette follows that tradition and verifies each pair.

Public-sector sites are also where legal obligations are most visible. Standards such as US Section 508 and the European standard EN 301 549 reference WCAG, and WCAG 2.2 AA is the level most commonly cited. This palette goes beyond that for text, links and the primary action by targeting AAA at 7:1. It is a colour starting point, not legal advice.

Because services involve forms for benefits, permits and taxes, error handling and focus visibility get as much attention as colour pairs. The border and focus ring are held at 3:1 or better, and the error colour is verified as text and as a filled message block.

How to build a palette like this by hand is explained in the accessible colour palette guide; this page is the finished, verified result.

The palette: light and dark

Hex values are the sRGB result after gamut mapping. The oklch() values are those of the final hex, so converting either gives the same colour.

Appointment confirmed

Secondary text sits on the surface colour.

Link in primary · Accent text

Primary buttonSuccessWarningErrorInfo

Light theme

  • Background

    #FCFCFC

    oklch(0.991 0.000 0.0)

    Sample text

  • Surface

    #FEFEFE

    oklch(0.997 0.000 0.0)

    Sample text

  • Text

    #1B1B1B

    oklch(0.222 0.000 0.0)

    Sample text

  • Muted text

    #565656

    oklch(0.453 0.000 0.0)

    Sample text

  • Primary

    #2652AB

    oklch(0.460 0.151 262.4)

    Sample text

  • Primary foreground

    #FCFCFC

    oklch(0.991 0.000 0.0)

    Sample text

  • Accent

    #2652AB

    oklch(0.460 0.151 262.4)

    Sample text

  • Border

    #919191

    oklch(0.657 0.000 0.0)

    Sample text

  • Focus ring

    #224FA7

    oklch(0.449 0.151 262.0)

    Sample text

  • Success

    #00845A

    oklch(0.5422 0.1184 162.29)

    Sample text

  • Success fill

    #008558

    oklch(0.545 0.122 160.9)

    Sample text

  • Success fill label

    #FCFCFC

    oklch(0.991 0.000 0.0)

    Sample text

  • Warning

    #A46600

    oklch(0.5651 0.1234 68.77)

    Sample text

  • Warning fill

    #FFBA44

    oklch(0.8335 0.1508 76.88)

    Sample text

  • Warning fill label

    #0F0F0F

    oklch(0.168 0.000 0.0)

    Sample text

  • Error

    #A21A1B

    oklch(0.4603 0.1706 26.95)

    Sample text

  • Error fill

    #C8322E

    oklch(0.551 0.187 27.1)

    Sample text

  • Error fill label

    #FCFCFC

    oklch(0.991 0.000 0.0)

    Sample text

  • Info

    #2274AF

    oklch(0.540 0.120 245.0)

    Sample text

  • Info fill

    #1377B9

    oklch(0.5501 0.1324 245.13)

    Sample text

  • Info fill label

    #FCFCFC

    oklch(0.991 0.000 0.0)

    Sample text

Appointment confirmed

Secondary text sits on the surface colour.

Link in primary · Accent text

Primary buttonSuccessWarningErrorInfo

Dark theme

  • Background

    #161616

    oklch(0.200 0.000 0.0)

    Sample text

  • Surface

    #202020

    oklch(0.244 0.000 0.0)

    Sample text

  • Text

    #EEEEEE

    oklch(0.949 0.000 0.0)

    Sample text

  • Muted text

    #BEBEBE

    oklch(0.802 0.000 0.0)

    Sample text

  • Primary

    #88BCFF

    oklch(0.785 0.111 255.1)

    Sample text

  • Primary foreground

    #0D0D0D

    oklch(0.159 0.000 0.0)

    Sample text

  • Accent

    #8EC3FF

    oklch(0.803 0.102 252.1)

    Sample text

  • Border

    #6B6B6B

    oklch(0.528 0.000 0.0)

    Sample text

  • Focus ring

    #88BCFF

    oklch(0.785 0.111 255.1)

    Sample text

  • Success

    #6CE5B5

    oklch(0.839 0.130 164.9)

    Sample text

  • Success fill

    #3BCD9A

    oklch(0.759 0.143 165.0)

    Sample text

  • Success fill label

    #0F0F0F

    oklch(0.168 0.000 0.0)

    Sample text

  • Warning

    #FFBC56

    oklch(0.839 0.140 75.1)

    Sample text

  • Warning fill

    #E9A11D

    oklch(0.7605 0.1539 75.30)

    Sample text

  • Warning fill label

    #0F0F0F

    oklch(0.168 0.000 0.0)

    Sample text

  • Error

    #F66D62

    oklch(0.700 0.171 27.0)

    Sample text

  • Error fill

    #FF7A6D

    oklch(0.732 0.165 27.5)

    Sample text

  • Error fill label

    #0F0F0F

    oklch(0.168 0.000 0.0)

    Sample text

  • Info

    #71BFFF

    oklch(0.780 0.120 245.0)

    Sample text

  • Info fill

    #61B9FF

    oklch(0.760 0.132 244.8)

    Sample text

  • Info fill label

    #0F0F0F

    oklch(0.168 0.000 0.0)

    Sample text

Contrast table: every verified pair

Pass or fail uses the raw WCAG 2.x ratio; the ratio shown is floored to two decimals so a near miss is never rounded up. APCA Lc is signed: positive is dark on light, negative is light on dark. Each row opens the pair in the checker.

Light theme: 25 pairs
PairWCAG ratioTargetNormal AA / AAALarge AA / AAAAPCA LcAPCA tierCheck
Text on background#1b1b1b on #fcfcfc16.78:1AAA 7:1Pass / PassPass / Pass+102.3Lc 75: body textOpen in checker
Text on surface#1b1b1b on #fefefe17.07:1AAA 7:1Pass / PassPass / Pass+103.5Lc 75: body textOpen in checker
Muted text on background#565656 on #fcfcfc7.15:1AAA 7:1Pass / PassPass / Pass+83.7Lc 75: body textOpen in checker
Muted text on surface#565656 on #fefefe7.27:1AAA 7:1Pass / PassPass / Pass+84.9Lc 75: body textOpen in checker
Primary as link text on background#2652ab on #fcfcfc7.11:1AAA 7:1Pass / PassPass / Pass+83.1Lc 75: body textOpen in checker
Primary as link text on surface#2652ab on #fefefe7.23:1AAA 7:1Pass / PassPass / Pass+84.3Lc 75: body textOpen in checker
Button label on primary#fcfcfc on #2652ab7.11:1AAA 7:1Pass / PassPass / Pass−87.8Lc 75: body textOpen in checker
Accent text on background#2652ab on #fcfcfc7.11:1AAA 7:1Pass / PassPass / Pass+83.1Lc 75: body textOpen in checker
Accent text on surface#2652ab on #fefefe7.23:1AAA 7:1Pass / PassPass / Pass+84.3Lc 75: body textOpen in checker
Border on background#919191 on #fcfcfc3.07:13:1 (WCAG 1.4.11)Fail / FailPass / Fail+56.8Lc 45: headlines and large textOpen in checker
Border on surface#919191 on #fefefe3.12:13:1 (WCAG 1.4.11)Fail / FailPass / Fail+58.0Lc 45: headlines and large textOpen in checker
Focus ring on background#224fa7 on #fcfcfc7.45:13:1 (WCAG 1.4.11)Pass / PassPass / Pass+84.3Lc 75: body textOpen in checker
Focus ring on surface#224fa7 on #fefefe7.58:13:1 (WCAG 1.4.11)Pass / PassPass / Pass+85.5Lc 75: body textOpen in checker
Success text on background#00845a on #fcfcfc4.60:1AA 4.5:1Pass / FailPass / Pass+70.4Lc 60: larger content textOpen in checker
Success text on surface#00845a on #fefefe4.68:1AA 4.5:1Pass / FailPass / Pass+71.6Lc 60: larger content textOpen in checker
Success badge label on fill#fcfcfc on #0085584.55:1AA 4.5:1Pass / FailPass / Pass−75.3Lc 75: body textOpen in checker
Warning text on background#a46600 on #fcfcfc4.56:1AA 4.5:1Pass / FailPass / Pass+70.4Lc 60: larger content textOpen in checker
Warning text on surface#a46600 on #fefefe4.64:1AA 4.5:1Pass / FailPass / Pass+71.6Lc 60: larger content textOpen in checker
Warning badge label on fill#0f0f0f on #ffba4411.28:1AA 4.5:1Pass / PassPass / Pass+73.2Lc 60: larger content textOpen in checker
Error text on background#a21a1b on #fcfcfc7.58:1AA 4.5:1Pass / PassPass / Pass+83.5Lc 75: body textOpen in checker
Error text on surface#a21a1b on #fefefe7.71:1AA 4.5:1Pass / PassPass / Pass+84.7Lc 75: body textOpen in checker
Error badge label on fill#fcfcfc on #c8322e5.17:1AA 4.5:1Pass / FailPass / Pass−78.4Lc 75: body textOpen in checker
Info text on background#2274af on #fcfcfc4.89:1AA 4.5:1Pass / FailPass / Pass+72.5Lc 60: larger content textOpen in checker
Info text on surface#2274af on #fefefe4.97:1AA 4.5:1Pass / FailPass / Pass+73.7Lc 60: larger content textOpen in checker
Info badge label on fill#fcfcfc on #1377b94.68:1AA 4.5:1Pass / FailPass / Pass−76.3Lc 75: body textOpen in checker
Dark theme: 25 pairs
PairWCAG ratioTargetNormal AA / AAALarge AA / AAAAPCA LcAPCA tierCheck
Text on background#eeeeee on #16161615.59:1AAA 7:1Pass / PassPass / Pass−95.8Lc 75: body textOpen in checker
Text on surface#eeeeee on #20202014.04:1AAA 7:1Pass / PassPass / Pass−94.6Lc 75: body textOpen in checker
Muted text on background#bebebe on #1616169.73:1AAA 7:1Pass / PassPass / Pass−66.5Lc 60: larger content textOpen in checker
Muted text on surface#bebebe on #2020208.76:1AAA 7:1Pass / PassPass / Pass−65.3Lc 60: larger content textOpen in checker
Primary as link text on background#88bcff on #1616169.20:1AAA 7:1Pass / PassPass / Pass−63.7Lc 60: larger content textOpen in checker
Primary as link text on surface#88bcff on #2020208.28:1AAA 7:1Pass / PassPass / Pass−62.5Lc 60: larger content textOpen in checker
Button label on primary#0d0d0d on #88bcff9.88:1AAA 7:1Pass / PassPass / Pass+65.8Lc 60: larger content textOpen in checker
Accent text on background#8ec3ff on #1616169.82:1AAA 7:1Pass / PassPass / Pass−67.1Lc 60: larger content textOpen in checker
Accent text on surface#8ec3ff on #2020208.84:1AAA 7:1Pass / PassPass / Pass−65.9Lc 60: larger content textOpen in checker
Border on background#6b6b6b on #1616163.39:13:1 (WCAG 1.4.11)Fail / FailPass / Fail−24.3Below Lc 30Open in checker
Border on surface#6b6b6b on #2020203.05:13:1 (WCAG 1.4.11)Fail / FailPass / Fail−23.1Below Lc 30Open in checker
Focus ring on background#88bcff on #1616169.20:13:1 (WCAG 1.4.11)Pass / PassPass / Pass−63.7Lc 60: larger content textOpen in checker
Focus ring on surface#88bcff on #2020208.28:13:1 (WCAG 1.4.11)Pass / PassPass / Pass−62.5Lc 60: larger content textOpen in checker
Success text on background#6ce5b5 on #16161611.64:1AA 4.5:1Pass / PassPass / Pass−77.0Lc 75: body textOpen in checker
Success text on surface#6ce5b5 on #20202010.48:1AA 4.5:1Pass / PassPass / Pass−75.8Lc 75: body textOpen in checker
Success badge label on fill#0f0f0f on #3bcd9a9.47:1AA 4.5:1Pass / PassPass / Pass+64.6Lc 60: larger content textOpen in checker
Warning text on background#ffbc56 on #16161610.84:1AA 4.5:1Pass / PassPass / Pass−72.7Lc 60: larger content textOpen in checker
Warning text on surface#ffbc56 on #2020209.76:1AA 4.5:1Pass / PassPass / Pass−71.5Lc 60: larger content textOpen in checker
Warning badge label on fill#0f0f0f on #e9a11d8.74:1AA 4.5:1Pass / PassPass / Pass+60.6Lc 60: larger content textOpen in checker
Error text on background#f66d62 on #1616166.27:1AA 4.5:1Pass / FailPass / Pass−46.5Lc 45: headlines and large textOpen in checker
Error text on surface#f66d62 on #2020205.65:1AA 4.5:1Pass / FailPass / Pass−45.3Lc 45: headlines and large textOpen in checker
Error badge label on fill#0f0f0f on #ff7a6d7.53:1AA 4.5:1Pass / PassPass / Pass+54.2Lc 45: headlines and large textOpen in checker
Info text on background#71bfff on #1616169.13:1AA 4.5:1Pass / PassPass / Pass−63.4Lc 60: larger content textOpen in checker
Info text on surface#71bfff on #2020208.22:1AA 4.5:1Pass / PassPass / Pass−62.2Lc 60: larger content textOpen in checker
Info badge label on fill#0f0f0f on #61b9ff9.02:1AA 4.5:1Pass / PassPass / Pass+62.1Lc 60: larger content textOpen in checker

Status colours and colour blindness

The four status fills were simulated for protanopia, deuteranopia and tritanopia (Machado et al., 2009). Success against error, the pair most often confused, must stay at least 6 ΔE-OK ×100 apart under every simulation. The other pairs are shown for information, so keep an icon and a word on every status.

Light theme, status fills
PairNormal visionProtanopiaDeuteranopiaTritanopiaHeld to 6
success / warning34.226.039.031.7Shown only
success / error28.516.66.533.0Yes
success / info17.116.215.23.2Shown only
warning / error31.842.037.422.6Shown only
warning / info40.034.244.531.2Shown only
error / info30.324.121.633.0Shown only

Fills as simulated:Normal visionProtanopiaDeuteranopiaTritanopia

Dark theme, status fills
PairNormal visionProtanopiaDeuteranopiaTritanopiaHeld to 6
success / warning20.911.815.527.5Shown only
success / error28.815.36.431.3Yes
success / info17.715.214.33.8Shown only
warning / error13.313.210.55.5Shown only
warning / info28.526.028.726.2Shown only
error / info28.321.820.829.7Shown only

Fills as simulated:Normal visionProtanopiaDeuteranopiaTritanopia

Why these colours

The neutrals have no tint at all: chroma zero, so black, white and greys are true neutrals. A tint can shift contrast slightly and signals brand; government sites prefer to signal neutrality. The only hue is a single blue at about OKLCH hue 262, used for links, buttons and the focus ring, which keeps the interface instantly learnable.

Having one accent hue means the accent and the primary are the same colour, so there are no competing signals. Lightness was solved for AAA against both the page and card colours with that one hue held. In the dark theme the blue rises in lightness rather than gaining chroma, which keeps the contrast without glare.

The generator solved 50 pairs (25 light, 25 dark), and all of them meet their target on the raw WCAG ratio. The tightest is success badge label on fill in the light theme at 4.55:1 against a target of 4.5:1. After gamut mapping to sRGB the light primary keeps 100% of the requested chroma; hue was held throughout.

How to use it

  • Keep the link colour for links only, always underlined in body text, so links are identifiable without relying on colour (WCAG 1.4.1).
  • Use the focus ring colour for a thick focus outline with an offset, and never remove it for pointer users.
  • Use plain error summaries at the top of a form with links to each field, in the error text colour with an icon.
  • Do not add decorative tints or gradients behind text; if the brand requires them, test every pair with the checker.
  • Offer a visible way to increase text size and respect the user's prefers-contrast and forced-colors settings.

Export

Generated from the verified values above, never typed by hand. Light and dark are both included.

CSS custom properties (hex, then oklch())

/* sRGB hex first: every browser. */
:root {
  --color-background: #fcfcfc;
  --color-surface: #fefefe;
  --color-text: #1b1b1b;
  --color-text-muted: #565656;
  --color-primary: #2652ab;
  --color-primary-foreground: #fcfcfc;
  --color-accent: #2652ab;
  --color-border: #919191;
  --color-focus-ring: #224fa7;
  --color-success: #00845a;
  --color-success-solid: #008558;
  --color-success-solid-foreground: #fcfcfc;
  --color-warning: #a46600;
  --color-warning-solid: #ffba44;
  --color-warning-solid-foreground: #0f0f0f;
  --color-error: #a21a1b;
  --color-error-solid: #c8322e;
  --color-error-solid-foreground: #fcfcfc;
  --color-info: #2274af;
  --color-info-solid: #1377b9;
  --color-info-solid-foreground: #fcfcfc;
}
.dark {
  --color-background: #161616;
  --color-surface: #202020;
  --color-text: #eeeeee;
  --color-text-muted: #bebebe;
  --color-primary: #88bcff;
  --color-primary-foreground: #0d0d0d;
  --color-accent: #8ec3ff;
  --color-border: #6b6b6b;
  --color-focus-ring: #88bcff;
  --color-success: #6ce5b5;
  --color-success-solid: #3bcd9a;
  --color-success-solid-foreground: #0f0f0f;
  --color-warning: #ffbc56;
  --color-warning-solid: #e9a11d;
  --color-warning-solid-foreground: #0f0f0f;
  --color-error: #f66d62;
  --color-error-solid: #ff7a6d;
  --color-error-solid-foreground: #0f0f0f;
  --color-info: #71bfff;
  --color-info-solid: #61b9ff;
  --color-info-solid-foreground: #0f0f0f;
}

/* oklch() where supported: the same colours, unclipped values of the hex above. */
@supports (color: oklch(0 0 0)) {
  :root {
    --color-background: oklch(0.991 0.000 0.0);
    --color-surface: oklch(0.997 0.000 0.0);
    --color-text: oklch(0.222 0.000 0.0);
    --color-text-muted: oklch(0.453 0.000 0.0);
    --color-primary: oklch(0.460 0.151 262.4);
    --color-primary-foreground: oklch(0.991 0.000 0.0);
    --color-accent: oklch(0.460 0.151 262.4);
    --color-border: oklch(0.657 0.000 0.0);
    --color-focus-ring: oklch(0.449 0.151 262.0);
    --color-success: oklch(0.5422 0.1184 162.29);
    --color-success-solid: oklch(0.545 0.122 160.9);
    --color-success-solid-foreground: oklch(0.991 0.000 0.0);
    --color-warning: oklch(0.5651 0.1234 68.77);
    --color-warning-solid: oklch(0.8335 0.1508 76.88);
    --color-warning-solid-foreground: oklch(0.168 0.000 0.0);
    --color-error: oklch(0.4603 0.1706 26.95);
    --color-error-solid: oklch(0.551 0.187 27.1);
    --color-error-solid-foreground: oklch(0.991 0.000 0.0);
    --color-info: oklch(0.540 0.120 245.0);
    --color-info-solid: oklch(0.5501 0.1324 245.13);
    --color-info-solid-foreground: oklch(0.991 0.000 0.0);
  }
  .dark {
    --color-background: oklch(0.200 0.000 0.0);
    --color-surface: oklch(0.244 0.000 0.0);
    --color-text: oklch(0.949 0.000 0.0);
    --color-text-muted: oklch(0.802 0.000 0.0);
    --color-primary: oklch(0.785 0.111 255.1);
    --color-primary-foreground: oklch(0.159 0.000 0.0);
    --color-accent: oklch(0.803 0.102 252.1);
    --color-border: oklch(0.528 0.000 0.0);
    --color-focus-ring: oklch(0.785 0.111 255.1);
    --color-success: oklch(0.839 0.130 164.9);
    --color-success-solid: oklch(0.759 0.143 165.0);
    --color-success-solid-foreground: oklch(0.168 0.000 0.0);
    --color-warning: oklch(0.839 0.140 75.1);
    --color-warning-solid: oklch(0.7605 0.1539 75.30);
    --color-warning-solid-foreground: oklch(0.168 0.000 0.0);
    --color-error: oklch(0.700 0.171 27.0);
    --color-error-solid: oklch(0.732 0.165 27.5);
    --color-error-solid-foreground: oklch(0.168 0.000 0.0);
    --color-info: oklch(0.780 0.120 245.0);
    --color-info-solid: oklch(0.760 0.132 244.8);
    --color-info-solid-foreground: oklch(0.168 0.000 0.0);
  }
}

Tailwind CSS v4 @theme

@theme {
  /* light */
  --color-background: oklch(0.991 0.000 0.0); /* #fcfcfc */
  --color-surface: oklch(0.997 0.000 0.0); /* #fefefe */
  --color-text: oklch(0.222 0.000 0.0); /* #1b1b1b */
  --color-text-muted: oklch(0.453 0.000 0.0); /* #565656 */
  --color-primary: oklch(0.460 0.151 262.4); /* #2652ab */
  --color-primary-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
  --color-accent: oklch(0.460 0.151 262.4); /* #2652ab */
  --color-border: oklch(0.657 0.000 0.0); /* #919191 */
  --color-focus-ring: oklch(0.449 0.151 262.0); /* #224fa7 */
  --color-success: oklch(0.5422 0.1184 162.29); /* #00845a */
  --color-success-solid: oklch(0.545 0.122 160.9); /* #008558 */
  --color-success-solid-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
  --color-warning: oklch(0.5651 0.1234 68.77); /* #a46600 */
  --color-warning-solid: oklch(0.8335 0.1508 76.88); /* #ffba44 */
  --color-warning-solid-foreground: oklch(0.168 0.000 0.0); /* #0f0f0f */
  --color-error: oklch(0.4603 0.1706 26.95); /* #a21a1b */
  --color-error-solid: oklch(0.551 0.187 27.1); /* #c8322e */
  --color-error-solid-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
  --color-info: oklch(0.540 0.120 245.0); /* #2274af */
  --color-info-solid: oklch(0.5501 0.1324 245.13); /* #1377b9 */
  --color-info-solid-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
  /* dark: use as dark:bg-background-dark, or remap under a .dark selector */
  --color-background-dark: oklch(0.200 0.000 0.0); /* #161616 */
  --color-surface-dark: oklch(0.244 0.000 0.0); /* #202020 */
  --color-text-dark: oklch(0.949 0.000 0.0); /* #eeeeee */
  --color-text-muted-dark: oklch(0.802 0.000 0.0); /* #bebebe */
  --color-primary-dark: oklch(0.785 0.111 255.1); /* #88bcff */
  --color-primary-foreground-dark: oklch(0.159 0.000 0.0); /* #0d0d0d */
  --color-accent-dark: oklch(0.803 0.102 252.1); /* #8ec3ff */
  --color-border-dark: oklch(0.528 0.000 0.0); /* #6b6b6b */
  --color-focus-ring-dark: oklch(0.785 0.111 255.1); /* #88bcff */
  --color-success-dark: oklch(0.839 0.130 164.9); /* #6ce5b5 */
  --color-success-solid-dark: oklch(0.759 0.143 165.0); /* #3bcd9a */
  --color-success-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
  --color-warning-dark: oklch(0.839 0.140 75.1); /* #ffbc56 */
  --color-warning-solid-dark: oklch(0.7605 0.1539 75.30); /* #e9a11d */
  --color-warning-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
  --color-error-dark: oklch(0.700 0.171 27.0); /* #f66d62 */
  --color-error-solid-dark: oklch(0.732 0.165 27.5); /* #ff7a6d */
  --color-error-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
  --color-info-dark: oklch(0.780 0.120 245.0); /* #71bfff */
  --color-info-solid-dark: oklch(0.760 0.132 244.8); /* #61b9ff */
  --color-info-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
}

shadcn/ui variables (:root and .dark)

:root {
  --background: oklch(0.991 0.000 0.0);
  --foreground: oklch(0.222 0.000 0.0);
  --card: oklch(0.997 0.000 0.0);
  --card-foreground: oklch(0.222 0.000 0.0);
  --popover: oklch(0.997 0.000 0.0);
  --popover-foreground: oklch(0.222 0.000 0.0);
  --primary: oklch(0.460 0.151 262.4);
  --primary-foreground: oklch(0.991 0.000 0.0);
  --secondary: oklch(0.997 0.000 0.0);
  --secondary-foreground: oklch(0.222 0.000 0.0);
  --muted: oklch(0.997 0.000 0.0);
  --muted-foreground: oklch(0.453 0.000 0.0);
  --accent: oklch(0.997 0.000 0.0);
  --accent-foreground: oklch(0.222 0.000 0.0);
  --destructive: oklch(0.551 0.187 27.1);
  --destructive-foreground: oklch(0.991 0.000 0.0);
  --border: oklch(0.657 0.000 0.0);
  --input: oklch(0.657 0.000 0.0);
  --ring: oklch(0.449 0.151 262.0);
  --success: oklch(0.545 0.122 160.9);
  --success-foreground: oklch(0.991 0.000 0.0);
  --warning: oklch(0.8335 0.1508 76.88);
  --warning-foreground: oklch(0.168 0.000 0.0);
  --info: oklch(0.5501 0.1324 245.13);
  --info-foreground: oklch(0.991 0.000 0.0);
  --brand-accent: oklch(0.460 0.151 262.4);
}

.dark {
  --background: oklch(0.200 0.000 0.0);
  --foreground: oklch(0.949 0.000 0.0);
  --card: oklch(0.244 0.000 0.0);
  --card-foreground: oklch(0.949 0.000 0.0);
  --popover: oklch(0.244 0.000 0.0);
  --popover-foreground: oklch(0.949 0.000 0.0);
  --primary: oklch(0.785 0.111 255.1);
  --primary-foreground: oklch(0.159 0.000 0.0);
  --secondary: oklch(0.244 0.000 0.0);
  --secondary-foreground: oklch(0.949 0.000 0.0);
  --muted: oklch(0.244 0.000 0.0);
  --muted-foreground: oklch(0.802 0.000 0.0);
  --accent: oklch(0.244 0.000 0.0);
  --accent-foreground: oklch(0.949 0.000 0.0);
  --destructive: oklch(0.732 0.165 27.5);
  --destructive-foreground: oklch(0.168 0.000 0.0);
  --border: oklch(0.528 0.000 0.0);
  --input: oklch(0.528 0.000 0.0);
  --ring: oklch(0.785 0.111 255.1);
  --success: oklch(0.759 0.143 165.0);
  --success-foreground: oklch(0.168 0.000 0.0);
  --warning: oklch(0.7605 0.1539 75.30);
  --warning-foreground: oklch(0.168 0.000 0.0);
  --info: oklch(0.760 0.132 244.8);
  --info-foreground: oklch(0.168 0.000 0.0);
  --brand-accent: oklch(0.803 0.102 252.1);
}

Design tokens (DTCG-style JSON)

{
  "color": {
    "light": {
      "background": {
        "$type": "color",
        "$value": "oklch(0.991 0.000 0.0)",
        "$description": "sRGB #fcfcfc"
      },
      "surface": {
        "$type": "color",
        "$value": "oklch(0.997 0.000 0.0)",
        "$description": "sRGB #fefefe"
      },
      "text": {
        "$type": "color",
        "$value": "oklch(0.222 0.000 0.0)",
        "$description": "sRGB #1b1b1b"
      },
      "text-muted": {
        "$type": "color",
        "$value": "oklch(0.453 0.000 0.0)",
        "$description": "sRGB #565656"
      },
      "primary": {
        "$type": "color",
        "$value": "oklch(0.460 0.151 262.4)",
        "$description": "sRGB #2652ab"
      },
      "primary-foreground": {
        "$type": "color",
        "$value": "oklch(0.991 0.000 0.0)",
        "$description": "sRGB #fcfcfc"
      },
      "accent": {
        "$type": "color",
        "$value": "oklch(0.460 0.151 262.4)",
        "$description": "sRGB #2652ab"
      },
      "border": {
        "$type": "color",
        "$value": "oklch(0.657 0.000 0.0)",
        "$description": "sRGB #919191"
      },
      "focus-ring": {
        "$type": "color",
        "$value": "oklch(0.449 0.151 262.0)",
        "$description": "sRGB #224fa7"
      },
      "success": {
        "$type": "color",
        "$value": "oklch(0.5422 0.1184 162.29)",
        "$description": "sRGB #00845a"
      },
      "success-solid": {
        "$type": "color",
        "$value": "oklch(0.545 0.122 160.9)",
        "$description": "sRGB #008558"
      },
      "success-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.991 0.000 0.0)",
        "$description": "sRGB #fcfcfc"
      },
      "warning": {
        "$type": "color",
        "$value": "oklch(0.5651 0.1234 68.77)",
        "$description": "sRGB #a46600"
      },
      "warning-solid": {
        "$type": "color",
        "$value": "oklch(0.8335 0.1508 76.88)",
        "$description": "sRGB #ffba44"
      },
      "warning-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.168 0.000 0.0)",
        "$description": "sRGB #0f0f0f"
      },
      "error": {
        "$type": "color",
        "$value": "oklch(0.4603 0.1706 26.95)",
        "$description": "sRGB #a21a1b"
      },
      "error-solid": {
        "$type": "color",
        "$value": "oklch(0.551 0.187 27.1)",
        "$description": "sRGB #c8322e"
      },
      "error-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.991 0.000 0.0)",
        "$description": "sRGB #fcfcfc"
      },
      "info": {
        "$type": "color",
        "$value": "oklch(0.540 0.120 245.0)",
        "$description": "sRGB #2274af"
      },
      "info-solid": {
        "$type": "color",
        "$value": "oklch(0.5501 0.1324 245.13)",
        "$description": "sRGB #1377b9"
      },
      "info-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.991 0.000 0.0)",
        "$description": "sRGB #fcfcfc"
      }
    },
    "dark": {
      "background": {
        "$type": "color",
        "$value": "oklch(0.200 0.000 0.0)",
        "$description": "sRGB #161616"
      },
      "surface": {
        "$type": "color",
        "$value": "oklch(0.244 0.000 0.0)",
        "$description": "sRGB #202020"
      },
      "text": {
        "$type": "color",
        "$value": "oklch(0.949 0.000 0.0)",
        "$description": "sRGB #eeeeee"
      },
      "text-muted": {
        "$type": "color",
        "$value": "oklch(0.802 0.000 0.0)",
        "$description": "sRGB #bebebe"
      },
      "primary": {
        "$type": "color",
        "$value": "oklch(0.785 0.111 255.1)",
        "$description": "sRGB #88bcff"
      },
      "primary-foreground": {
        "$type": "color",
        "$value": "oklch(0.159 0.000 0.0)",
        "$description": "sRGB #0d0d0d"
      },
      "accent": {
        "$type": "color",
        "$value": "oklch(0.803 0.102 252.1)",
        "$description": "sRGB #8ec3ff"
      },
      "border": {
        "$type": "color",
        "$value": "oklch(0.528 0.000 0.0)",
        "$description": "sRGB #6b6b6b"
      },
      "focus-ring": {
        "$type": "color",
        "$value": "oklch(0.785 0.111 255.1)",
        "$description": "sRGB #88bcff"
      },
      "success": {
        "$type": "color",
        "$value": "oklch(0.839 0.130 164.9)",
        "$description": "sRGB #6ce5b5"
      },
      "success-solid": {
        "$type": "color",
        "$value": "oklch(0.759 0.143 165.0)",
        "$description": "sRGB #3bcd9a"
      },
      "success-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.168 0.000 0.0)",
        "$description": "sRGB #0f0f0f"
      },
      "warning": {
        "$type": "color",
        "$value": "oklch(0.839 0.140 75.1)",
        "$description": "sRGB #ffbc56"
      },
      "warning-solid": {
        "$type": "color",
        "$value": "oklch(0.7605 0.1539 75.30)",
        "$description": "sRGB #e9a11d"
      },
      "warning-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.168 0.000 0.0)",
        "$description": "sRGB #0f0f0f"
      },
      "error": {
        "$type": "color",
        "$value": "oklch(0.700 0.171 27.0)",
        "$description": "sRGB #f66d62"
      },
      "error-solid": {
        "$type": "color",
        "$value": "oklch(0.732 0.165 27.5)",
        "$description": "sRGB #ff7a6d"
      },
      "error-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.168 0.000 0.0)",
        "$description": "sRGB #0f0f0f"
      },
      "info": {
        "$type": "color",
        "$value": "oklch(0.780 0.120 245.0)",
        "$description": "sRGB #71bfff"
      },
      "info-solid": {
        "$type": "color",
        "$value": "oklch(0.760 0.132 244.8)",
        "$description": "sRGB #61b9ff"
      },
      "info-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.168 0.000 0.0)",
        "$description": "sRGB #0f0f0f"
      }
    }
  }
}

Open in the studio

Take the primary colour into the picker, build a tonal scale from it, or check any pair of your own.

Open #2652AB in the OKLCH picker →Build a tonal scale →Check a pair

FAQ

Which standards reference WCAG for government sites?
US Section 508 and the European standard EN 301 549 both reference WCAG for web content. The exact version and level depend on the regulation and its date, so confirm with your legal or accessibility team.
Why is the accent the same as the primary?
A single accent keeps meaning simple. People learn that blue is interactive and everything else is content. A second brand hue would need its own verified pairs and adds little in public-service UIs.
Can I use this as a design system base?
Yes. The export snippets provide CSS variables, a Tailwind v4 theme block and shadcn/ui variables. The design system palette page shows a more flexible set.
Does AAA text mean pure black on white?
Not necessarily. The solver finds the lightest neutral that reaches 7:1, which keeps text strong while avoiding the harshest possible contrast. Some people with dyslexia or light sensitivity prefer slightly softer pairs.

← All accessible palettes