Foundations · @csdr/theme
Colour palettes
Three swappable palettes — default (PatternFly), landscape, goap — on PatternFly’s token contract: ramps, roles, validated chart sets, and every component rendered in the palette you are viewing.
- Import
palette: goap # report frontmatter · PUBLIC_CSDR_PALETTE=landscape · <SiteLayout palette="goap">- Use on
- reports · landing · docs · tools
Global Ocean Accounts Partnership goap
The Partnership palette (greens/teals, blues, sand, greys) pinned verbatim into PatternFly's steps, plus the status hues and chart set a UI needs. Where a documented pairing fails WCAG AA the palette uses the neighbouring step of the same hue — see the sign-off issue.
- Brand family
teal— links, focus ring, primary buttons, masthead- Role remaps
brand → tealinfo → blue- Provenance
- SustainableDevelopmentReform/CSDR-GOAP-Design-System@ebcf73c — goap/tokens.css, CSDR-GOAP-Style-Guide.md §3.4. Sign-off: CSDR-GOAP-Design-System#1.
- Select it
- Report:
palette: goapin frontmatter · Site:PUBLIC_CSDR_PALETTE=goap· Page:<SiteLayout palette="goap">
Ramps
Nine PatternFly families at PatternFly's steps (grays 10–95). The step is the promise: 10–20 tints, 30 dark-mode text and links, 40 dark-mode UI, 50 light-mode interactive, 60 text on white (≥ 4.5:1 in every family), 70–80 emphasis. Base and semantic tokens (--pf-t--global--*) resolve to these; components never touch them directly.
blueinfo#e2f0f5
#aed1d8
#9dcadd
#51a5bb
#217794
#25667c
#164151
#2a3f58
tealbrand#e2f1f0
#bfdfde
#9ccdcc
#67afae
#167b7b
#0a5455
#134444
#19383b
greensuccess#e2f2e9
#bee1cf
#9bd0b6
#66b390
#3b9c7b
#1f6d4e
#124632
#0e2f21
yellowwarning#f5ecdc
#e9d5b1
#dcbe88
#c39948
#a57807
#77570b
#4f3700
#352402
orange#f9f5f0
#e5d5c3
#d6bea3
#b59e81
#9e794d
#745735
#4b3821
#322516
red-orangedanger#fee8e2
#facbbf
#f3af9e
#e0846d
#c55d43
#92412d
#60291b
#401c13
red#fef0ef
#fee7e5
#fdc9c6
#f7aba8
#e57e7c
#ca5557
#963b3d
#622526
#421919
purple#eeebf5
#dad4e8
#c6bdda
#a699c1
#8777a5
#625679
#3f374f
#2a2434
gray#f3f2f0
#e3e3e3
#c8c7c5
#a4a3a1
#8d8c8a
#727272
#4e4d4b
#393836
#2a2927
#30302f
#161514
Pinned brand hexes
Brand colours are pinned verbatim into the step they belong to; the generator reports how far each sits from the step's lightness so fidelity costs are visible.
| Family · step | Hex | OKLCH L | Step target | Δ L |
|---|---|---|---|---|
| gray-20 | #E3E3E3 | 0.916 | 0.907 | +0.009 |
| gray-50 | #727272 | 0.552 | 0.545 | +0.007 |
| gray-90 | #30302F | 0.309 | 0.239 | +0.07 |
| blue-20 | #AED1D8 | 0.838 | 0.88 | -0.043 |
| blue-40 | #51A5BB | 0.678 | 0.707 | -0.029 |
| blue-80 | #2A3F58 | 0.362 | 0.275 | +0.087 |
| green-50 | #3B9C7B | 0.626 | 0.601 | +0.025 |
| orange-10 | #F9F5F0 | 0.972 | 0.946 | +0.026 |
| orange-40 | #B59E81 | 0.712 | 0.707 | +0.005 |
| teal-60 | #0A5455 | 0.406 | 0.479 | -0.073 |
| teal-80 | #19383B | 0.318 | 0.275 | +0.043 |
Step contract
Contrast ratios the generator enforces on every family (pnpm check:palette). Brand-50 must reach 4.5:1 because it is the link and primary-button colour; other families need 3:1 at 50.
| Family | 50 on white | 60 on white | 70 on white | 30 on dark | 40 on dark | 10 vs white |
|---|---|---|---|---|---|---|
| blue | ✓ 5.08 | ✓ 6.42 | ✓ 11 | ✓ 8.26 | ✓ 5.16 | ✓ 1.17 |
| green | ✓ 3.37 | ✓ 6.26 | ✓ 10.78 | ✓ 8.38 | ✓ 5.83 | ✓ 1.16 |
| orange | ✓ 3.97 | ✓ 6.65 | ✓ 11.13 | ✓ 8.14 | ✓ 5.66 | ✓ 1.09 |
| purple | ✓ 4.03 | ✓ 6.72 | ✓ 11.23 | ✓ 8.1 | ✓ 5.51 | ✓ 1.18 |
| red | ✓ 4.24 | ✓ 7.02 | ✓ 11.59 | ✓ 7.86 | ✓ 5.27 | ✓ 1.18 |
| red-orange | ✓ 4.18 | ✓ 6.96 | ✓ 11.47 | ✓ 7.92 | ✓ 5.33 | ✓ 1.18 |
| teal | ✓ 5.06 | ✓ 8.71 | ✓ 10.84 | ✓ 8.33 | ✓ 5.76 | ✓ 1.16 |
| yellow | ✓ 3.97 | ✓ 6.66 | ✓ 11.18 | ✓ 8.15 | ✓ 5.52 | ✓ 1.17 |
Role tokens
- ✓ link on white (brand-50): 5.06:1 (needs 4.5:1)
- ✓ link on secondary surface (brand-50 on gray-10): 4.52:1 (needs 4.5:1)
- ✓ brand text (brand-60) on white: 8.71:1 (needs 4.5:1)
- ✓ white on brand (brand-50): 5.06:1 (needs 4.5:1)
- ✓ dark link (brand-20) on dark surface: 10.27:1 (needs 4.5:1)
- ✓ dark brand (brand-30) on dark surface: 8.33:1 (needs 4.5:1)
- ✓ body text (gray-95) on white: 18.24:1 (needs 7:1)
- ✓ subtle text (gray-60) on white: 8.44:1 (needs 4.5:1)
- ✓ danger text on white: 6.96:1 (needs 4.5:1)
- ✓ success text on white: 6.26:1 (needs 4.5:1)
- ✓ warning text on white: 6.66:1 (needs 4.5:1)
- ✓ info text on white: 6.42:1 (needs 4.5:1)
- ✓ white on info (info-50): 5.08:1 (needs 4.5:1)
- ✓ info text (info-50) on white: 5.08:1 (needs 4.5:1)
Chart sets
Categorical colours are a separate parameter from UI colours: muted brand hues fall under the chart chroma floor and read as grey in a series, so each palette carries a "data-grade" set derived from the same hues and validated (lightness band, chroma floor ≥ 0.10, adjacent CVD ΔE ≥ 8, normal-vision ΔE ≥ 15, ≥ 3:1 vs surface). Assigned in fixed order, never cycled; status colours are reserved and never used for series.
Light surface — 6 primary slots
- ✓ lightness band — all inside L 0.43–0.77
- ✓ chroma floor — all ≥ 0.1
- ✓ CVD separation (adjacent) — worst #9d381f↔#2b9c71 ΔE 14.1 (deutan); target ≥ 8, floor 6
- ✓ normal-vision floor — worst #aa7e18↔#027d9f ΔE 22.5; floor 15
- ✓ contrast vs surface — all ≥ 3:1 on #ffffff
- All-pairs clean (scatter, maps, small multiples) up to 2 slots.
Sequential 7
Diverging
Status
Dark surface — 6 primary slots
- ✓ lightness band — all inside L 0.48–0.67
- ✓ chroma floor — all ≥ 0.1
- ✓ CVD separation (adjacent) — worst #219f9f↔#be563d ΔE 13.1 (deutan); target ≥ 8, floor 6
- ✓ normal-vision floor — worst #7f6cb4↔#33a377 ΔE 21.9; floor 15
- ✓ contrast vs surface — all ≥ 3:1 on #2a2927
- All-pairs clean (scatter, maps, small multiples) up to 2 slots.
Sequential 7
Diverging
Status
Six series, this palette (build-time SVG)
View data
| year | North (index) | South (index) | East (index) | West (index) | Central (index) | Islands (index) |
|---|---|---|---|---|---|---|
| 2019 | 12 | 8 | 5 | 10 | 3 | 6 |
| 2020 | 14 | 9 | 7 | 8 | 4 | 5 |
| 2021 | 13 | 11 | 6 | 9 | 6 | 4 |
| 2022 | 16 | 10 | 9 | 7 | 5 | 6 |
View data
| year | North | South | East | West | Central | Islands |
|---|---|---|---|---|---|---|
| 2019 | 12 | 8 | 5 | 10 | 3 | 6 |
| 2020 | 14 | 9 | 7 | 8 | 4 | 5 |
| 2021 | 13 | 11 | 6 | 9 | 6 | 4 |
| 2022 | 16 | 10 | 9 | 7 | 5 | 6 |
Code
<LineChart data={rows} x="year" y="value" series="region" alt="…" /> {/* colours follow the page's palette */}Components in this palette
Everything below is the ordinary component rendered on a page stamped data-palette="goap" — nothing is styled specially for this page.
Brand and status
Info alert:Data updated 5 August 2026
Success alert:Build passed
Warning alert:Provisional values for the current year
Danger alert:Checksum mismatch in bundle noaa-mlo-co2
Code
<Button variant="primary">Download PDF</Button> <Button variant="secondary">Cite</Button> <Button variant="link">Read more</Button>Editorial
Latest monthly mean
431.1ppm
+2.4 vs a year earlier
Growth, 1960s
0.9ppm/yr
Growth, 2010s
2.5ppm/yr
Code
<Callout kind="key-finding" title="…">…</Callout> <StatTile tone="good" … />The other palettes
Adding or changing a palette
- Edit or add
packages/theme/palettes/<id>.json: nine families ashue+chroma(with optionalpins for exact brand hexes), optionalextensions,roles, and the chart sets. - Run
pnpm palette:build. It generates the CSS palette layer, the chart values and this page's report — and refuses to write if a contract, role or chart check fails. pnpm check(which runscheck:palette) fails on any drift between the JSON and the generated files, so hexes never get hand-edited downstream.- Look at it here and in the report preview; then
pnpm testfor the axe/VR matrix. See Theme → Palettes and D13.