Tokens and constraints
Design tokens give shared values, such as colors, a name you can use in code. Constraints are rules for using them and building the interface. These tokens and rules help keep the Tailwind and shadcn/ui pattern implementations consistent.
Standard shadcn tokens 19
These colors use shadcn’s existing token names with this site’s values. You can use those same names in your shadcn project.
--background --foreground --card --card-foreground --popover --popover-foreground --primary --primary-foreground --secondary --secondary-foreground --muted --muted-foreground --accent --accent-foreground --destructive --destructive-foreground --border --input --ring Status 4
Colors for normal, warning, critical, and unknown states. These are separate from shadcn’s --destructive color for actions such as deleting.
--status-critical #9B1627 / #F1686D --status-warn #9D6100 / #F0A94E --status-nominal #28A64F / #81F597 --status-unknown #7A828F / #A4ACB9 Data freshness 2
Colors that show whether data is current or out of date. They use the same colors as normal and warning states.
--state-stale #9D6100 / #F0A94E --state-live #28A64F / #81F597 Chart series 8
Eight distinct colors for different groups of data in a chart.
--chart-1 #D07526 / #C76E1E --chart-2 #9A9000 / #928800 --chart-3 #006863 / #009A92 --chart-4 #009FBF / #00ECFF --chart-5 #0061A1 / #0091E6 --chart-6 #7F84FB / #767CF2 --chart-7 #8B329F / #FFB6FF --chart-8 #EA54A4 / #E14B9C Sequential scales 5
Colors that get steadily lighter or darker as values change. The order stays visible in grayscale.
--scale-seq-1 #88E8FF / #004B84 --scale-seq-2 #5BC1FF / #006DA9 --scale-seq-3 #249BDB / #0190D0 --scale-seq-4 #0077B4 / #4DB6F8 --scale-seq-5 #00548E / #7BDDFF Diverging scales 5
Two color ranges for values above and below zero. Matching steps on each side have similar lightness.
--scale-div-neg-2 #A3514E / #B35C59 --scale-div-neg-1 #EA7D78 / #F4847F --scale-div-mid #F2F0EC / #2A2724 --scale-div-pos-1 #00B3BA / #00BCC2 --scale-div-pos-2 #007A7F / #00888D Direction 3
Colors for rising, falling, and unchanged values. Whether a rise is good depends on what you measure. More sales and more cancellations mean different things.
--direction-up #28A64F / #81F597 --direction-down #9B1627 / #F1686D --direction-flat #7A828F / #A4ACB9 Design rules 23
Each rule comes from a pattern’s checklist, quoted below it. Some rules have automated checks. Others guide AI coding tools or need a person to review them.
12 automated checks 7 instructions for AI tools 4 need human review
-
color.series-assigned-by-keyAutomated checkChoose each series color using its name or key. Using its position in a list can change its color when a filter removes another series.
From categorical series palette: "Is colour assigned deterministically from the series name, or by result order?"
-
color.series-mutually-separableAutomated checkKeep every pair of --chart-* colors at least 10 apart on the ΔE00 color-difference scale. This helps people tell chart series apart.
From categorical series palette: "Do any two adjacent-in-value series share similar hues?"
-
color.series-overflow-definedAI instructionWhen there are more series than colors, combine the extra series into one muted "other" group. Do not reuse colors for different series.
From categorical series palette: "Is there a defined behaviour past the palette's limit?"
-
state.failure-modes-distinctAI instructionGive empty, out-of-date, and failed data different displays and appropriate next steps. Keep the last known value when data is out of date, and label it clearly.
From error and stale state: "Is a stale value visually distinguishable from a current one, or only from a missing one?"
-
delta.window-requiredAI instructionEvery change indicator must state its comparison period. Make that period a required component input so people know what the change is measured against.
From delta indicator: "Is the comparison window stated, and is it the same one across the page?"
-
delta.no-sentiment-tokensAutomated checkUse --direction-* colors and a symbol to show change. Avoid color names such as positive or negative: whether a rise is good depends on the measure.
From delta indicator: "Is direction encoded by anything other than hue?"
-
freshness.reports-arrival-not-refreshAI instructionShow when the newest data arrived and whether it is updating on schedule. Refreshing the page does not make old data current.
From freshness indicator: "Does this show when the data arrived, or only when the page refreshed?"
-
color.alert-budgetHuman reviewKeep interface controls, labels, and values neutral until they need attention. Reserve strong colors for those states so warnings stand out.
From grayscale with alerts: "Is anything permanently coloured, and has anyone noticed?"
-
kpi.context-requiredAI instructionEach KPI tile must show how old its data is and include a comparison, status, or trend beside the value. Make both the data age and this context required component inputs.
From kpi tile: "Does the tile carry a delta, a state colour or a trend? Without one of the three, the number is a decoration."
-
color.direction-lightness-differsAutomated checkKeep --direction-up and --direction-down at least 12 apart on the CIE L* lightness scale. A lightness difference helps people distinguish the colors without relying on hue alone.
From red green direction: "Do the two colours differ in lightness as well as hue?"
-
color.direction-survives-greyscaleAutomated checkKeep --direction-up and --direction-down at least 12 L* apart after applying grayscale(1). The gray --direction-flat color is exempt from this check and must use a symbol to show its meaning.
From red green direction: "Does the display survive being viewed in greyscale?"
-
color.direction-not-sentimentAI instructionName tokens for rising, falling, or unchanged values. Whether a rise is good depends on the measure: more cancellations, for example, means losing customers.
From red green direction: "Is 'up' unambiguously good or bad for this metric, and does the colour reflect that rather than the sign?"
-
color.direction-inverted-marketsHuman reviewLet people choose the colors for rising and falling values. Some financial markets use red for rising values, so a fixed color convention can be misleading.
From red green direction: "Is the up/down colour mapping a user preference for markets that invert it?"
-
color.status-set-closedAutomated checkUse only nominal, warn, critical, or unknown for status. Use the corresponding status token for each one instead of a raw palette color.
From semantic status color: "How many states, and is the set closed and written down?"
-
color.status-nontext-contrastAutomated checkEvery --status-* color must have at least 3:1 contrast against --background in every theme. This follows WCAG 2.2 SC 1.4.11 for visual indicators that convey meaning.
From semantic status color: "Do the colours meet contrast requirements against both light and dark backgrounds?"
-
color.status-disjoint-from-seriesAutomated checkKeep every --status-* color at least 10 apart from every --chart-* color on the ΔE00 color-difference scale. This helps prevent chart colors from looking like status warnings.
From semantic status color: "Does any of these colours also appear decoratively or as a series colour on the same page?"
-
color.status-survives-greyscaleAutomated checkAfter applying grayscale(1), keep the nominal, warn, and critical colors at least 12 L* apart. Measure the result using Rec.709 luma, the brightness calculation used by the CSS filter, rather than the original color’s CIE L*. The gray --status-unknown color is exempt and must be identified by its icon and label.
From semantic status color: "Does the display survive being viewed in greyscale?"
-
color.status-lightness-separatedAutomated checkKeep nominal, warn, and critical at least 12 apart on the CIE L* lightness scale. This gives people another way to distinguish severity when hues are hard to tell apart.
From semantic status color: "Does the display survive being viewed in greyscale?"
-
color.status-has-nontext-signalAI instructionAlways pair a status color with an icon, symbol, or text label. In the reference implementation, STATUS_META includes the icon so every status has one.
From semantic status color: "Is there a non-colour signal for every state—icon, shape, label, position?"
-
color.status-thresholds-ownedHuman reviewDefine the rule behind each status color in one place and name the person responsible for it. Keep that rule current so the color reflects the actual status.
From semantic status color: "Where are the thresholds defined, and who can change them?"
-
color.seq-monotonicAutomated checkEach step in a sequential color scale must get lighter or each step must get darker, with at least 10 CIE L* between neighboring steps. Reversals or repeated lightness levels can suggest breaks in otherwise continuous data.
From sequential and diverging scales: "Does the ramp vary monotonically in lightness?"
-
color.div-symmetricAutomated checkMatch the lightness of corresponding steps on both sides of a diverging color scale. This keeps one direction from looking more important than the other.
From sequential and diverging scales: "If diverging, does the midpoint sit at a real zero rather than at the mean?"
-
color.scale-clampedHuman reviewLimit the color scale at a stated percentile and explain the cutoff in the legend. This keeps an extreme value from leaving most other values in the same color range.
From sequential and diverging scales: "Is the scale clamped, and does one outlier otherwise consume it?"
Generated from tokens/ and src/content/constraints/.
Run npm run check:tokens to check the rules that can be tested automatically.
Run npm run rules to update the instructions for AI coding tools.