color-system-design — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited color-system-design (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A color system is the discipline of turning color from a per-screen aesthetic decision into a derivable, accessible, theme-portable layer of the design system. It is built in three stacked layers — and proven by one audit artifact. The palette is raw values organized as per-hue scales (typically 9 to 12 steps from very light to very dark, generated in a perceptually uniform color space — OKLCH/LCH or HCT — so equal step indices read as equally spaced). The semantic tokens name colors by purpose rather than appearance (background-surface, text-primary, border-subtle, danger-bg/danger-fg). The per-theme mapping resolves each semantic token to a palette value, and is the only layer that differs between light, dark, high-contrast, brand, or product modes. A mature scale also assigns a fixed UI role to each step index, so step N means the same job (app background, component fill, border, solid fill, text) across every hue — the role convention is what makes the semantic layer cheap to define and stable across rebrands. The proof that the whole stack is safe is the pairing matrix: the documented set of foreground/background, border/background, focus/background, icon/background, and status/background combinations allowed to ship, each with its contrast result per theme.
Two non-negotiable constraints run through everything: scales must be constructed in a perceptually uniform space rather than sRGB/HSL (whose equal numeric steps look unequal), and every pairing a semantic token can produce must clear a contrast minimum — WCAG 2.x AA at a floor — in every theme it resolves in. The system's job is to make color reproducible and safe: scales generated by rule, accessibility baked into the token contract and the pairing matrix, and meaning decoupled from value so a brand shift never becomes a code change.
This skill covers color systems at the value and meaning layer:
color-mix(), relative colors, Display-P3 and sRGB fallbacks, contrast-color() limits, forced-colors behavior, and prefers-contrast variants.It does not own the runtime application of themes, the complete token build pipeline, or accessibility-law interpretation.
A scale is not just "light to dark"; in a mature system each step index carries a fixed UI role that holds across every hue. The widely-adopted Radix Colors convention uses 12 steps banded by purpose, and the same step number means the same role in every palette:
| Steps | Role |
|---|---|
| 1–2 | App background and subtle component background |
| 3–5 | Component backgrounds — 3 normal, 4 hover, 5 pressed/selected |
| 6–8 | Borders — 6 subtle/non-interactive, 7 interactive, 8 strong border + focus ring |
| 9–10 | Solid backgrounds (fills) — 9 has the highest chroma in the scale, 10 is its hover |
| 11–12 | Text — 11 low-contrast/secondary text, 12 high-contrast/primary text |
This is the layer that makes semantic tokens cheap: border-subtle → step 6, surface-hover → step 4, text-primary → step 12 are defined once against the role convention and resolve correctly for every hue and every theme. A system may use a 9-step or 10-step scale, or a labelled 50–950 ramp, instead of 12; the principle that matters is that step index encodes role, not just lightness — publish the equivalent bands so step N means the same job across every hue. The index band only proposes a role; the pairing matrix still decides whether that role is allowed in a specific theme. Anchor the brand color at a defined step (e.g., the solid-fill step) so the surrounding scale is generated rather than hand-tuned. Some libraries use APCA to tune internal step behavior, but WCAG 2.2 remains the conformance floor for the allowed product pairings.
on-* foreground token is incomplete. Do not try to make every swatch pass against every other swatch; make the allowed semantic pairings pass.50, 100, 200, …, 900, 950; Material-style systems use tone values. The exact labels matter less than stable semantics: the anchor step is the recognizable brand color, not a random midpoint.50–950 web ramp might start with approximate OKLCH lightness targets such as 50 → 0.97, 100 → 0.93, 200 → 0.86, 300 → 0.76, 400 → 0.64, 500 → 0.50, 600 → 0.41, 700 → 0.33, 800 → 0.24, 900 → 0.17, 950 → 0.10 — treat those numbers as a starting sketch, not a standard, because role pairings, brand anchors, dark-theme mapping, and hue-specific gamut limits may require a different ramp. Shape chroma as a curve, not a flat value: it usually tapers near the very light and very dark ends, peaks around the middle or solid-fill steps, and varies by hue. Reds, magentas, and some blues can sustain higher middle chroma; yellows, greens, and cyans tend to hit gamut, noise, or contrast problems sooner and often need lower chroma. Allow small hue corrections only when a hue needs them to preserve perceived balance; do not hand-tune every step independently.on-color, hover, selected, and disabled pairings. Hover and active states can often be derived from a base token with CSS color-mix() in OKLCH/OKLab or with relative color syntax, which reduces static token bloat. The recipe is still part of the color system: snapshot the resolved value, check it in the pairing matrix, and promote it to an explicit token when the state needs semantic review. State colors also need a non-color signal — icon, label, shape, or pattern — when conveying state.Color spaces matter for scale construction. sRGB and HSL are non-perceptually-uniform — equal numeric steps in lightness produce unequal perceived lightness changes, with notable cliffs around yellow and teal. OKLCH and CIELAB are perceptually uniform spaces where equal L (lightness) steps look equal regardless of hue: a yellow and a blue both at L≈0.65 read as comparably bright, and equal C (chroma) produces equal visual saturation weight across hues — something HSL cannot do because each hue has a different maximum achievable saturation. The CSS Color Module Level 4 specifies oklch() and lch() as first-class CSS color functions, and color-mix() in lch/oklch space produces predictable interpolation.
A third perceptually-uniform option is HCT (Hue, Chroma, Tone), the color space behind Google's Material 3 dynamic color. HCT takes hue and chroma from CAM16 (a modern color-appearance model) and tone directly from CIELAB's L\* — so "tone" is a contrast-bearing axis (tonal palettes run tone 0–100, and a fixed tone-delta between a color and its background maps to a predictable WCAG-ish contrast). HCT is the right generation space for Material/Android systems and tonal-palette workflows; OKLCH is the more CSS-native choice on the web. All three (OKLCH, CIELAB/LCH, HCT) satisfy the requirement that matters here — build scales in a perceptually uniform space, never in sRGB/HSL.
As of 2026, OKLCH has shipped in all major browsers since mid-2023 and is the default color format in Tailwind CSS v4, shadcn/ui, and Radix — Tailwind v4 explicitly moved its default palette from RGB to OKLCH to use the wider gamut, and exposes 11-step palettes with OKLCH copy values. Direct adoption (authoring oklch() in production with an sRGB fallback for old browsers) is now the mainstream strategy rather than a precompiled-only one; "build in OKLCH" has moved from a recommendation to an industry baseline.
The display-p3 gamut, supported by most modern displays, allows more saturated colors than sRGB in the green/red regions; declaring colors with p3 functions (or @media (color-gamut: p3)) delivers them while sRGB fallbacks handle narrow-gamut displays. Because OKLCH is unbounded, many (L, C, H) triples you generate fall outside the target gamut and must be gamut-mapped.
The CSS Color 4 default algorithm works in OKLCH, holds lightness and hue fixed, and binary-searches chroma downward — preserving brightness and hue family while shedding only saturation, which is far safer than naive per-channel clipping. Its stop condition is `deltaEOK` (the Euclidean distance in OKLab) ≤ 0.02 — the OKLab just-noticeable-difference — measured against a channel-clipped version of the candidate (the "local MINDE" / minimum-Delta-E refinement). It is not ΔE2000 ≤ 2: an earlier draft used CIEDE2000, but the current CSS spec is OKLab-based, so do not substitute CIEDE2000 as the CSS algorithm. (If a separate Lab/LCH toolchain uses CIEDE2000, DeltaE2000 ≤ 2 is only the analogous Lab-workflow JND guardrail.) Practical bound: max usable OKLCH chroma stays below ~0.37 for both sRGB and P3, and the achievable maximum varies by hue and lightness, so a scale built at a fixed high chroma will clip unevenly across hues unless you map.
Export discipline for wide-gamut values:
@media (color-gamut: p3) or equivalent build output when shipping P3-specific values on the web, and keep an explicit fallback strategy for older WebViews, email, PDFs, screenshots, canvas, and exported assets.Use names that encode purpose and relationship, not appearance:
| Token pattern | Use |
|---|---|
color.background.canvas | App or page base |
color.background.surface | Cards, panels, fields, menus |
color.text.primary | Default text on normal surface |
color.text.secondary | Lower-emphasis text that still meets contrast |
color.border.subtle | Low-emphasis separation with non-text contrast checked where meaningful |
color.action.primary.bg | Primary action filled background |
color.action.primary.fg | Text/icon on primary action background |
color.status.danger.bg | Danger status container |
color.status.danger.fg | Text/icon on danger status container |
color.focus.ring | Visible focus indicator on every relevant surface |
color.chart.series.1 | Data series color, paired with labels/patterns when needed |
Keep raw palette tokens available for the generator and design tooling, but keep component code on semantic tokens. blue.600 or red.700 can be a palette value; it should not be the component contract. If a component needs a local override, name it as a component token that aliases a semantic token, not as a raw value.
A specific and widely-used pattern for the text-on-color case is the *`on- foreground token**: every solid/emphasis fill ships a paired foreground token guaranteed to clear contrast against it — on-primary for text/icons on the primary fill, on-danger for the danger fill, on-emphasis for any high-chroma surface. This makes the foreground a first-class, audited member of the contract rather than a guess made at the call site (and it is what contrast-color(), below, can only approximate). Author one on-*` token per surface a component can sit on.
text-primary on a light theme might be near-black at L≈0.15; on a dark theme near-white at L≈0.96 — both resolve to the same component token and meet the same contrast requirement against their respective backgrounds. The discipline is to define semantic tokens by intent and contrast pair (text-on-surface, text-on-emphasis), never by appearance (text-dark-gray).
Build the contrast contract from actual rendered pairings, not isolated swatches.
text-on-background ships components whose borders and focus rings are invisible to low-vision users while passing its text audit.APCA status discipline is a common source of drift, so state it precisely. As of 2026, WCAG 2.2 is the stable, legally-referenced standard worldwide; WCAG 3.0 is a Working Draft (most recently March 2026) not expected to reach Recommendation until roughly 2029; and APCA was moved out of the WCAG 3 normative draft in July 2023 — the WCAG 3 contrast algorithm is still "to be determined" and the draft defines a generic exploratory contrast-ratio test rather than naming APCA. APCA (the Accessible Perceptual Contrast Algorithm) is a different, lightness-aware model that better predicts perceived text legibility, with thresholds expressed as Lc values, but its scores are not backwards-compatible with WCAG 2 ratios (a pair can pass one and fail the other). The correct posture: ship to WCAG 2.x AA for compliance and procurement, use APCA as the readability check that catches cases WCAG 2 scores poorly (e.g., very light or very dark mid-tones). Compute both in tooling; gate releases on the WCAG 2.x floor; never use APCA to waive a WCAG 2.2 failure. If the team adopts APCA internally, pin the exact algorithm/version and thresholds, use the absolute Lc magnitude for tiering, and keep the sign only as the polarity signal.
A practical APCA guardrail table — note the readability guidance runs the other direction from a naive reading (Lc 60 is the large-text tier, not a body-text floor):
| APCA Lc magnitude | Typical use | ||
|---|---|---|---|
| `\ | Lc\ | ≥ 90` | Preferred level for fluent/body text and text columns |
| `\ | Lc\ | ≥ 75` | Minimum for body text where readability matters |
| `\ | Lc\ | ≥ 60` | Minimum for large or non-body content text (sub-headlines, large fonts) |
| `\ | Lc\ | ≥ 45` | Large/bold display text |
| `\ | Lc\ | ≥ 30` | Incidental / disabled text |
These tiers are a secondary readability check applied with font size, weight, and polarity context — not WCAG 2.2 pass/fail rules. As a concrete anchor, Radix targets its step 11 (low-contrast/secondary text) at Lc 60 and its step 12 (high-contrast/primary text) at Lc 90 against a step-2 background of the same hue — consistent with the tiers above, since step 11 is explicitly the secondary-text role. CSS contrast-color() can help with simple dynamic black/white foreground choices, but it returns only black or white and does not replace semantic pair design (see § Modern CSS derivation primitives).
The contrast contract is not a property of individual colors — it is a property of pairings, and a mature system makes the set of allowed pairings an explicit, audited artifact rather than something verified ad hoc per screen. The pairing matrix enumerates every foreground/background combination the semantic layer can produce and records the governing floor for each, per theme:
| Pairing class | Governing floor | Examples |
|---|---|---|
| Text on surface | WCAG 2.x AA — 4.5:1 (3:1 large) | text-primary / text-secondary on each surface step |
| Text on solid fill | WCAG 2.x AA — 4.5:1 (3:1 large) | on-primary on primary fill; on-danger on danger fill |
| Non-text UI (SC 1.4.11) | 3:1 | control borders, input boundaries, toggle/checkbox states |
| Focus ring on adjacent surfaces | 3:1 | focus ring vs both the component fill and the page background |
| Icon / graphical object | 3:1 | standalone icon strokes, the meaningful parts of an illustration |
| Status colors on surface | AA for status text + 3:1 for the status mark | success/warning/danger/info on light and dark surfaces |
| Chart / data-viz marks | 3:1 between adjacent series; do not rely on hue alone | series fills, categorical legends |
| Alpha overlays | AA against the effective composited color | translucent scrims, tinted hover states (compute the resolved color, not the token's nominal value) |
The matrix is what CI gates against: each cell is a computed pass/fail in both light and dark themes, so a token change that breaks focus-ring against the dark page background fails the build instead of shipping. Alpha overlays are the classic gap — a 12%-opacity hover tint passes nothing meaningful until you composite it over the actual surface and test the result.
Do not stop at a generic "color-blind safe" checkbox. Review rendered components, charts, maps, alerts, focus states, and status treatments with a documented simulator and a redundant-channel check. For dichromacy, use a known LMS-cone-space method such as Brettel–Viénot–Mollon, or another peer-reviewed model such as Machado for severity-aware anomalous trichromacy — not a crude per-channel desaturation, which under-reports real confusions. Record the tool, algorithm, and simulated deficiency types in the audit notes.
Run at least protanopia, deuteranopia, and tritanopia reviews on the pairings that carry meaning. A simulation is not proof of accessibility; it is a risk-finding aid. The pass condition is that critical distinctions still have labels, icons, shapes, patterns, ordering, or text in addition to hue, and that chart series remain distinguishable in the actual chart context, not only as isolated legend swatches.
Every semantic token must resolve in every supported theme. Parity means equal purpose and equal safety, not equal step number.
color.text.primary may resolve to a dark neutral on a light surface and a light neutral on a dark surface; both must pass against their own surface.color.border.subtle may need stronger lightness separation in dark mode because faint borders disappear faster than on light surfaces.color.focus.ring must be visible against normal, inverse, filled, danger, and disabled-adjacent surfaces.color.status.warning.fg often needs special care because yellow/amber backgrounds can fail with both white and low-contrast dark text if the tone is wrong.#fff body text on pure #000 (use an off-white at, e.g., L≈0.92 on a surface at L≈0.12), and by slightly reducing chroma and/or font weight for dark-mode text. Then inspect dense text, hairline borders, icons, focus rings, and filled controls on real dark surfaces. Parity is "every token meets its contrast floor in both themes," not "the dark values are the arithmetic inverse of the light ones."Two distinct accessibility surfaces touch a color system, and conflating them is a common error — one is a user preference the system answers with stronger token values, the other is the OS replacing the palette entirely.
User contrast preference is expressed via the prefers-contrast media query, whose values are more, less, custom, and no-preference. Here the author's colors still render; the user is asking for an adjustment. The design consequence for this skill is that a mature system ships a high-contrast variant of its token mapping — a parallel resolution of the semantic tokens that raises every text/surface pairing toward AAA (and pushes non-text pairings well past the 3:1 floor) so prefers-contrast: more resolves to demonstrably higher-contrast values rather than the same palette; less may soften harsh pairings only where the product supports it and still clears required floors; custom signals a user-defined color set (often coupled with forced colors). This is the same shape as light/dark parity: another column in the per-theme mapping, gated by the same pairing matrix.
Forced colors is different in kind. A color system also has to survive having its colors removed. In forced-colors mode (Windows High Contrast and equivalents, surfaced by forced-colors: active), the OS overrides author colors with a small user-chosen system palette, exposed via the forced-colors: active media query and the system-color keywords (Canvas, CanvasText, LinkText, ButtonFace, ButtonText, Highlight, …). The design consequence is a constraint, not a runtime feature: meaning encoded only in a background color disappears, because backgrounds are reassigned. A button distinguished from the page solely by surface fill, a status conveyed only by a red background, or a focus state shown only by a background tint all collapse to indistinguishable. The system must therefore carry structural, non-color signals for anything load-bearing — a real border on interactive controls, an icon or text label alongside status color, an outline-based (not fill-based) focus indicator. A practical corollary: give interactive controls a border: 1px solid transparent in the normal themes, so the system palette has an existing border to repaint in forced colors and the control gains its system-colored outline without a layout shift (the box already reserved the border's space). Do not rely on shadows, background-only fills, or subtle author colors to define boundaries, because forced-colors mode may remove shadows and substitute system colors. The actual @media (forced-colors: active) / @media (prefers-contrast: more) overrides and any forced-color-adjust opt-outs are wiring that lives in dark-mode-implementation / theme-system-design; what belongs here is the upstream rule that the palette and semantic layer never make color the sole carrier of meaning, plus authoring the high-contrast token column those queries resolve to.
Three CSS features make a token system self-deriving rather than hand-listed, and all reduce the surface where contrast bugs hide:
oklch(from var(--brand) calc(l * 0.8) c h) produces a darker brand variant in-place, and the same pattern generates hover/pressed states or whole scale steps from one seed. Global support is ~90% (early 2026); keep static fallbacks for the rest.color-mix(in oklch, var(--brand) 85%, black) darkens the brand toward black perceptually, and mixing toward transparent yields alpha tints. Performed in oklch/lch it interpolates without the muddy mid-tones sRGB mixing produces, and it is the most broadly-shipped of the three primitives (Baseline since 2023) — the pragmatic default for generating hover/active/tint steps when relative-color support is still a concern.color-contrast() was dropped) takes a color and returns black or white to meet a contrast floor against it: color: contrast-color(var(--surface)). MDN lists it as Baseline 2026 "newly available" (since April 2026) — newly available means latest browsers only, not widely available, so keep fallbacks. Two sharp limits: it picks only between pure black and pure white (no brand-tinted foreground), and MDN warns explicitly that against mid-tone backgrounds neither black nor white clears AA — e.g. a royal-blue #2277d3 surface returns black text that is not readable for small text — so it is only safe over reliably light or reliably dark surfaces. It does not replace authored on-* / text-on-X tokens for the pairings a brand controls — reserve it for genuinely dynamic backgrounds (user-picked colors, tag chips) where no token could be authored ahead of time.A color system rarely lives only in CSS; its values move between Figma, Style Dictionary, Tokens Studio, and code. The interchange contract is the W3C Design Tokens Community Group (DTCG) color format (Final Community Group Report, 2025-10-28). A DTCG color token's $value is a structured object, not a hex string: `colorSpace` (required — one of ~14 spaces including srgb, display-p3, oklch, lab) and `components` (required — an array of channel numbers, with the "none" keyword allowed for a missing/powerless channel) are mandatory; `alpha` (0–1, defaults to fully opaque) and a 6-digit `hex` fallback are optional. An OKLCH value retains colorSpace: "oklch" and components in [lightness, chroma, hue] order; a Display-P3 value retains colorSpace: "display-p3" and RGB components. Alias references let semantic tokens point back to palette tokens. This is what lets a perceptually-uniform palette survive export: the OKLCH triple is carried as data rather than flattened to sRGB hex at design time.
Two round-trip risks belong to this skill, because they are where a carefully-built palette silently degrades:
hex fallback and drop the wide-gamut/OKLCH information — so the exported palette loses exactly the perceptual uniformity it was built for. Validate that every tool in the chain preserves colorSpace/components, not just hex.oklch → srgb for an older target) invokes a gamut-mapping step, and the choice of mapping algorithm materially changes the result — a chroma-reduced map (per § Wide gamut and gamut mapping) and a naive per-channel clip produce visibly different colors. Pin and verify the translation tool's mapping behavior; do not assume two tools round-trip identically.The DTCG format is what the colors are, serialized for exchange — it stays in this skill. How a build pipeline transforms, distributes, and deprecates those tokens to platform targets is theme-system-design's / design-system-architecture's machinery.
Color choices are constraints applied to perception, not free decisions. Perceptual uniformity, contrast minima, color-blindness considerations (~8% of men and ~0.5% of women have some form of color vision deficiency, most commonly red-green), gamut limits, and user contrast preferences are real and observable. A palette that ignores them produces accessibility violations and uneven scales that designers compensate for with one-off tweaks — design-system debt that surfaces whenever the product adds dark mode, a brand refresh, or a new surface.
Semantic tokens are worth the indirection because color meanings outlive specific values. "Danger" stays danger when the brand red shifts a few degrees; "surface" stays a surface when the theme flips; components keep working. Tying components directly to palette values turns every brand refresh into a code change. The step-role convention earns its up-front rigor for the same reason: when step index encodes role, a new hue drops into the system and is immediately usable for borders, fills, and text without a fresh round of hand-tuning. And the same logic protects dark mode — a semantic role can keep its promise even when it maps to a different step, lower chroma, or less intense text color because the perceptual context changed.
|Lc| ≥ 90 / 75 / 60 are applied with font size/weight/polarity context and never used to waive a WCAG 2.2 failure.on-* foreground token that clears AA against it; no component picks its own text color on a colored surface ad hoc.deltaEOK ≤ 0.02 stop condition, not per-channel clipped; P3/OKLCH values have sRGB fallbacks whose contrast is tested separately.prefers-contrast: more (raising text pairings toward AAA and non-text past 3:1, gated by the same matrix in both themes); forced-colors behavior does not override the user's palette harmfully; shadow-only or background-only boundaries have border/outline/system-color fallbacks, including transparent border/outline slots reserved to avoid layout shift.$type: "color" plus $value.colorSpace + $value.components (optional alpha, optional hex, alias references where needed), not a flattened hex, and the export pipeline has been verified to preserve wide-gamut/OKLCH values in every consuming tool — without treating format compliance as contrast proof or build-pipeline ownership.| Use instead | When |
|---|---|
visual-design-foundations | The task is broad visual craft direction, brand mood, hierarchy, density, or art direction without a reusable color-token contract. |
theme-system-design | The task is token tiering, the DTCG build/export pipeline, CSS custom-property delivery, N-theme contract governance, or token deprecation policy — how tokens are stored, transformed, and shipped, rather than what the colors are. |
design-system-architecture | The task is the broader design-token package architecture, distribution, and governance across token categories. |
dark-mode-implementation | The task is prefers-color-scheme detection, persistence, first-paint anti-flash code, asset variants, color-scheme, or browser chrome hints. |
a11y | The task is pure WCAG interpretation, a compliance audit, keyboard/focus semantics, screen-reader behavior, or assistive-technology testing. |
typography-system | The task is typeface, type scale, line height, text measure, or font delivery. |
| One-off art direction | The task is choosing colors for a single illustration, campaign graphic, screenshot, or brand exploration with no token impact. |
<!-- skill-graph-context:start (generated — do not edit by hand) -->
Classification
designtruedesign/visualWhen to use
color system, color palette, color tokens, wcag contrast, oklchNot for
dark-mode-implementation: the palette, the scale construction, the semantic color roles, and the contrast pairings against every surfaceRelated skills
a11y, semanticstheme-system-design, dark-mode-implementation, visual-design-foundations, typography-system, a11y, design-system-architecture, semanticsConcept
Grounding
universalhttps://www.w3.org/TR/WCAG22/, https://www.w3.org/TR/wcag-3.0/, https://git.apcacontrast.com/documentation/APCAeasyIntro.html, https://www.w3.org/TR/css-color-4/, https://www.w3.org/TR/css-color-5/, https://www.w3.org/TR/css-color-adjust-1/, https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch, https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix, https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/contrast-color, https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/%40media/prefers-contrast, https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/%40media/forced-colors, https://www.w3.org/community/reports/design-tokens/CG-FINAL-format-20251028/, https://www.w3.org/community/reports/design-tokens/CG-FINAL-color-20251028/, https://developer.android.com/design/ui/mobile/guides/styles/color?hl=en, https://codelabs.developers.google.com/codelabs/design-material-darktheme, https://www.radix-ui.com/colors/docs/palette-composition/understanding-the-scale, https://tailwindcss.com/blog/tailwindcss-v4, https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/color-blindness, https://pubmed.ncbi.nlm.nih.gov/9316278/Keywords
semantic color tokens, wcag contrast ratio, apca contrast, oklch color space, perceptual uniformity, gamut mapping, hct tonal palette, forced colors, light dark parity, color accessibility<!-- skill-graph-context:end -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.