Tokens
Every design token opsinjs defines, what it controls, and which parts of the system consume it.
How this is generated
Source: tokens/color.json, tokens/material.json, tokens/motion.json,
tokens/type.json, tokens/space.json, tokens/shape.json.
Script: scripts/build-tokens.mts, which also writes lib/generated/tokens.ts
and app/tokens.generated.css. Command: pnpm run generate.
Three columns, and the third is the one that matters. Token is the name you write. What it controls is the single property or decision it owns. If a token controls two unrelated things, that is a bug in the token, not a longer sentence in this column. Used by lists the components and foundations that read it, which is how you find out whether changing a value is a local adjustment or a system event.
Tier is shown for every row. Primitive tokens are raw values and are listed for completeness only; a component that reads one has broken the rule described in Token architecture. Semantic and component tiers are the ones you are meant to use.
What is deliberately excluded. The documentation site's own theme variables are not opsinjs tokens and are not listed, and that covers everything lyra, shadcn and fumadocs define for the chrome you are looking at. They are not part of the public surface, they carry no semver promise, and confusing the two is the most common way a consumer ends up styling their product with our sidebar's colours.
If you want to change a value rather than read one, you want Theming. If you want to know what a value means, you want Foundations. To change a row here, edit the JSON source; this page cannot be edited.
Tokens
color
neutral
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-neutral-0 | primitive | Neutral ramp, step 0. | oklch(1 0 0) | same | no component |
--opsin-neutral-50 | primitive | Neutral ramp, step 50. | oklch(0.985 0.002 250) | same | no component |
--opsin-neutral-100 | primitive | Neutral ramp, step 100. | oklch(0.967 0.003 250) | same | no component |
--opsin-neutral-200 | primitive | Neutral ramp, step 200. | oklch(0.929 0.004 250) | same | no component |
--opsin-neutral-300 | primitive | Neutral ramp, step 300. | oklch(0.871 0.005 250) | same | no component |
--opsin-neutral-400 | primitive | Neutral ramp, step 400. | oklch(0.708 0.008 250) | same | no component |
--opsin-neutral-500 | primitive | Neutral ramp, step 500. | oklch(0.556 0.009 250) | same | no component |
--opsin-neutral-600 | primitive | Neutral ramp, step 600. | oklch(0.439 0.009 250) | same | no component |
--opsin-neutral-700 | primitive | Neutral ramp, step 700. | oklch(0.371 0.008 250) | same | no component |
--opsin-neutral-800 | primitive | Neutral ramp, step 800. | oklch(0.269 0.007 250) | same | no component |
--opsin-neutral-900 | primitive | Neutral ramp, step 900. | oklch(0.205 0.006 250) | same | no component |
--opsin-neutral-950 | primitive | Neutral ramp, step 950. | oklch(0.145 0.005 250) | same | no component |
--opsin-neutral-1000 | primitive | Neutral ramp, step 1000. | oklch(0 0 0) | same | no component |
chrome
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-chrome-background | semantic | Chrome role background, resolved to the ladder step it names. | oklch(0.985 0.002 250) | oklch(0.145 0.005 250) | no component |
--opsin-chrome-foreground | semantic | Chrome role foreground, resolved to the ladder step it names. | oklch(0.205 0.006 250) | oklch(0.967 0.003 250) | no component |
--opsin-chrome-card | semantic | Chrome role card, resolved to the ladder step it names. | oklch(1 0 0) | oklch(0.205 0.006 250) | no component |
--opsin-chrome-card-foreground | semantic | Chrome role cardForeground, resolved to the ladder step it names. | oklch(0.205 0.006 250) | oklch(0.967 0.003 250) | no component |
--opsin-chrome-muted | semantic | Chrome role muted, resolved to the ladder step it names. | oklch(0.967 0.003 250) | oklch(0.269 0.007 250) | no component |
--opsin-chrome-muted-foreground | semantic | Chrome role mutedForeground, resolved to the ladder step it names. | oklch(0.439 0.009 250) | oklch(0.871 0.005 250) | no component |
--opsin-chrome-border | semantic | Chrome role border, resolved to the ladder step it names. | oklch(0.556 0.009 250) | oklch(0.556 0.009 250) | no component |
--opsin-chrome-input | semantic | Chrome role input, resolved to the ladder step it names. | oklch(0.556 0.009 250) | oklch(0.556 0.009 250) | no component |
--opsin-chrome-ring | semantic | Chrome role ring, resolved to the ladder step it names. | oklch(0.55 0.13 250) | oklch(0.68 0.115 250) | no component |
--opsin-chrome-primary | semantic | Chrome role primary, resolved to the ladder step it names. | oklch(0.51 0.135 250) | oklch(0.72 0.12 250) | no component |
--opsin-chrome-primary-foreground | semantic | Chrome role primaryForeground, resolved to the ladder step it names. | oklch(0.99 0 0) | oklch(0.16 0.01 260) | no component |
category
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-category-sleep-50 | primitive | Sleep ramp, step 50. | oklch(0.972 0.013 275) | same | no component |
--opsin-category-sleep-100 | primitive | Sleep ramp, step 100. | oklch(0.941 0.028 275) | same | no component |
--opsin-category-sleep-200 | primitive | Sleep ramp, step 200. | oklch(0.884 0.057 275) | same | no component |
--opsin-category-sleep-300 | primitive | Sleep ramp, step 300. | oklch(0.806 0.092 275) | same | no component |
--opsin-category-sleep-400 | primitive | Sleep ramp, step 400. | oklch(0.714 0.123 275) | same | no component |
--opsin-category-sleep-500 | primitive | Sleep ramp, step 500. | oklch(0.622 0.14 275) | same | no component |
--opsin-category-sleep-600 | primitive | Sleep ramp, step 600. | oklch(0.541 0.136 275) | same | no component |
--opsin-category-sleep-700 | primitive | Sleep ramp, step 700. | oklch(0.452 0.123 275) | same | no component |
--opsin-category-sleep-800 | primitive | Sleep ramp, step 800. | oklch(0.362 0.104 275) | same | no component |
--opsin-category-sleep-900 | primitive | Sleep ramp, step 900. | oklch(0.276 0.081 275) | same | no component |
--opsin-category-sleep-950 | primitive | Sleep ramp, step 950. | oklch(0.208 0.062 275) | same | no component |
--opsin-category-sleep-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.013 275) | oklch(0.208 0.062 275) | no component |
--opsin-category-sleep-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.136 275) | oklch(0.806 0.092 275) | trend-sparkline |
--opsin-category-sleep-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.104 275) | oklch(0.884 0.057 275) | metric-tile, range-bar, result-card, score-dial |
--opsin-category-sleep-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.58 0.14 275) | oklch(0.714 0.123 275) | log-sheet |
--opsin-category-heart-50 | primitive | Heart ramp, step 50. | oklch(0.972 0.014 15) | same | no component |
--opsin-category-heart-100 | primitive | Heart ramp, step 100. | oklch(0.941 0.03 15) | same | no component |
--opsin-category-heart-200 | primitive | Heart ramp, step 200. | oklch(0.884 0.062 15) | same | no component |
--opsin-category-heart-300 | primitive | Heart ramp, step 300. | oklch(0.806 0.112 15) | same | no component |
--opsin-category-heart-400 | primitive | Heart ramp, step 400. | oklch(0.714 0.15 15) | same | no component |
--opsin-category-heart-500 | primitive | Heart ramp, step 500. | oklch(0.622 0.17 15) | same | no component |
--opsin-category-heart-600 | primitive | Heart ramp, step 600. | oklch(0.541 0.165 15) | same | no component |
--opsin-category-heart-700 | primitive | Heart ramp, step 700. | oklch(0.452 0.15 15) | same | no component |
--opsin-category-heart-800 | primitive | Heart ramp, step 800. | oklch(0.362 0.126 15) | same | no component |
--opsin-category-heart-900 | primitive | Heart ramp, step 900. | oklch(0.276 0.099 15) | same | no component |
--opsin-category-heart-950 | primitive | Heart ramp, step 950. | oklch(0.208 0.075 15) | same | no component |
--opsin-category-heart-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.014 15) | oklch(0.208 0.075 15) | no component |
--opsin-category-heart-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.165 15) | oklch(0.806 0.112 15) | trend-sparkline |
--opsin-category-heart-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.126 15) | oklch(0.884 0.062 15) | metric-tile, range-bar, result-card, score-dial |
--opsin-category-heart-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.62 0.17 15) | oklch(0.714 0.15 15) | log-sheet |
--opsin-category-activity-50 | primitive | Activity ramp, step 50. | oklch(0.972 0.022 140) | same | no component |
--opsin-category-activity-100 | primitive | Activity ramp, step 100. | oklch(0.941 0.038 140) | same | no component |
--opsin-category-activity-200 | primitive | Activity ramp, step 200. | oklch(0.884 0.067 140) | same | no component |
--opsin-category-activity-300 | primitive | Activity ramp, step 300. | oklch(0.806 0.106 140) | same | no component |
--opsin-category-activity-400 | primitive | Activity ramp, step 400. | oklch(0.714 0.141 140) | same | no component |
--opsin-category-activity-500 | primitive | Activity ramp, step 500. | oklch(0.622 0.16 140) | same | no component |
--opsin-category-activity-600 | primitive | Activity ramp, step 600. | oklch(0.541 0.155 140) | same | no component |
--opsin-category-activity-700 | primitive | Activity ramp, step 700. | oklch(0.452 0.141 140) | same | no component |
--opsin-category-activity-800 | primitive | Activity ramp, step 800. | oklch(0.362 0.118 140) | same | no component |
--opsin-category-activity-900 | primitive | Activity ramp, step 900. | oklch(0.276 0.092 140) | same | no component |
--opsin-category-activity-950 | primitive | Activity ramp, step 950. | oklch(0.208 0.07 140) | same | no component |
--opsin-category-activity-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.022 140) | oklch(0.208 0.07 140) | no component |
--opsin-category-activity-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.155 140) | oklch(0.806 0.106 140) | trend-sparkline |
--opsin-category-activity-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.118 140) | oklch(0.884 0.067 140) | metric-tile, range-bar, result-card, score-dial |
--opsin-category-activity-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.7 0.16 140) | oklch(0.714 0.141 140) | log-sheet |
--opsin-category-nutrition-50 | primitive | Nutrition ramp, step 50. | oklch(0.972 0.02 70) | same | no component |
--opsin-category-nutrition-100 | primitive | Nutrition ramp, step 100. | oklch(0.941 0.034 70) | same | no component |
--opsin-category-nutrition-200 | primitive | Nutrition ramp, step 200. | oklch(0.884 0.059 70) | same | no component |
--opsin-category-nutrition-300 | primitive | Nutrition ramp, step 300. | oklch(0.806 0.092 70) | same | no component |
--opsin-category-nutrition-400 | primitive | Nutrition ramp, step 400. | oklch(0.714 0.123 70) | same | no component |
--opsin-category-nutrition-500 | primitive | Nutrition ramp, step 500. | oklch(0.622 0.135 70) | same | no component |
--opsin-category-nutrition-600 | primitive | Nutrition ramp, step 600. | oklch(0.541 0.118 70) | same | no component |
--opsin-category-nutrition-700 | primitive | Nutrition ramp, step 700. | oklch(0.452 0.099 70) | same | no component |
--opsin-category-nutrition-800 | primitive | Nutrition ramp, step 800. | oklch(0.362 0.08 70) | same | no component |
--opsin-category-nutrition-900 | primitive | Nutrition ramp, step 900. | oklch(0.276 0.062 70) | same | no component |
--opsin-category-nutrition-950 | primitive | Nutrition ramp, step 950. | oklch(0.208 0.049 70) | same | no component |
--opsin-category-nutrition-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.02 70) | oklch(0.208 0.049 70) | no component |
--opsin-category-nutrition-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.118 70) | oklch(0.806 0.092 70) | trend-sparkline |
--opsin-category-nutrition-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.08 70) | oklch(0.884 0.059 70) | metric-tile, range-bar, result-card, score-dial |
--opsin-category-nutrition-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.75 0.14 70) | oklch(0.714 0.123 70) | log-sheet |
--opsin-category-mind-50 | primitive | Mind ramp, step 50. | oklch(0.972 0.018 310) | same | no component |
--opsin-category-mind-100 | primitive | Mind ramp, step 100. | oklch(0.941 0.034 310) | same | no component |
--opsin-category-mind-200 | primitive | Mind ramp, step 200. | oklch(0.884 0.059 310) | same | no component |
--opsin-category-mind-300 | primitive | Mind ramp, step 300. | oklch(0.806 0.092 310) | same | no component |
--opsin-category-mind-400 | primitive | Mind ramp, step 400. | oklch(0.714 0.123 310) | same | no component |
--opsin-category-mind-500 | primitive | Mind ramp, step 500. | oklch(0.622 0.14 310) | same | no component |
--opsin-category-mind-600 | primitive | Mind ramp, step 600. | oklch(0.541 0.136 310) | same | no component |
--opsin-category-mind-700 | primitive | Mind ramp, step 700. | oklch(0.452 0.123 310) | same | no component |
--opsin-category-mind-800 | primitive | Mind ramp, step 800. | oklch(0.362 0.104 310) | same | no component |
--opsin-category-mind-900 | primitive | Mind ramp, step 900. | oklch(0.276 0.081 310) | same | no component |
--opsin-category-mind-950 | primitive | Mind ramp, step 950. | oklch(0.208 0.062 310) | same | no component |
--opsin-category-mind-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.018 310) | oklch(0.208 0.062 310) | no component |
--opsin-category-mind-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.136 310) | oklch(0.806 0.092 310) | trend-sparkline |
--opsin-category-mind-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.104 310) | oklch(0.884 0.059 310) | metric-tile, range-bar, result-card, score-dial |
--opsin-category-mind-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.62 0.14 310) | oklch(0.714 0.123 310) | log-sheet |
--opsin-category-labs-50 | primitive | Labs ramp, step 50. | oklch(0.972 0.015 210) | same | no component |
--opsin-category-labs-100 | primitive | Labs ramp, step 100. | oklch(0.941 0.026 210) | same | no component |
--opsin-category-labs-200 | primitive | Labs ramp, step 200. | oklch(0.884 0.046 210) | same | no component |
--opsin-category-labs-300 | primitive | Labs ramp, step 300. | oklch(0.806 0.073 210) | same | no component |
--opsin-category-labs-400 | primitive | Labs ramp, step 400. | oklch(0.714 0.097 210) | same | no component |
--opsin-category-labs-500 | primitive | Labs ramp, step 500. | oklch(0.622 0.108 210) | same | no component |
--opsin-category-labs-600 | primitive | Labs ramp, step 600. | oklch(0.541 0.094 210) | same | no component |
--opsin-category-labs-700 | primitive | Labs ramp, step 700. | oklch(0.452 0.079 210) | same | no component |
--opsin-category-labs-800 | primitive | Labs ramp, step 800. | oklch(0.362 0.063 210) | same | no component |
--opsin-category-labs-900 | primitive | Labs ramp, step 900. | oklch(0.276 0.049 210) | same | no component |
--opsin-category-labs-950 | primitive | Labs ramp, step 950. | oklch(0.208 0.038 210) | same | no component |
--opsin-category-labs-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.015 210) | oklch(0.208 0.038 210) | no component |
--opsin-category-labs-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.094 210) | oklch(0.806 0.073 210) | trend-sparkline |
--opsin-category-labs-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.063 210) | oklch(0.884 0.046 210) | metric-tile, range-bar, result-card, score-dial |
--opsin-category-labs-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.6 0.11 210) | oklch(0.714 0.097 210) | log-sheet |
status
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-status-steady-50 | primitive | Steady ramp, step 50. | oklch(0.972 0.015 178) | same | no component |
--opsin-status-steady-100 | primitive | Steady ramp, step 100. | oklch(0.941 0.026 178) | same | no component |
--opsin-status-steady-200 | primitive | Steady ramp, step 200. | oklch(0.884 0.046 178) | same | no component |
--opsin-status-steady-300 | primitive | Steady ramp, step 300. | oklch(0.806 0.073 178) | same | no component |
--opsin-status-steady-400 | primitive | Steady ramp, step 400. | oklch(0.714 0.097 178) | same | no component |
--opsin-status-steady-500 | primitive | Steady ramp, step 500. | oklch(0.622 0.11 178) | same | no component |
--opsin-status-steady-600 | primitive | Steady ramp, step 600. | oklch(0.541 0.1 178) | same | no component |
--opsin-status-steady-700 | primitive | Steady ramp, step 700. | oklch(0.452 0.084 178) | same | no component |
--opsin-status-steady-800 | primitive | Steady ramp, step 800. | oklch(0.362 0.067 178) | same | no component |
--opsin-status-steady-900 | primitive | Steady ramp, step 900. | oklch(0.276 0.052 178) | same | no component |
--opsin-status-steady-950 | primitive | Steady ramp, step 950. | oklch(0.208 0.041 178) | same | no component |
--opsin-status-steady-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.015 178) | oklch(0.208 0.041 178) | alert-banner, status-pill |
--opsin-status-steady-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.1 178) | oklch(0.806 0.073 178) | alert-banner, range-bar, range-legend, status-pill |
--opsin-status-steady-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.067 178) | oklch(0.884 0.046 178) | alert-banner, score-dial, status-pill |
--opsin-status-steady-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.62 0.11 178) | oklch(0.714 0.097 178) | score-dial |
--opsin-status-watch-50 | primitive | Watch ramp, step 50. | oklch(0.972 0.02 82) | same | no component |
--opsin-status-watch-100 | primitive | Watch ramp, step 100. | oklch(0.941 0.034 82) | same | no component |
--opsin-status-watch-200 | primitive | Watch ramp, step 200. | oklch(0.884 0.059 82) | same | no component |
--opsin-status-watch-300 | primitive | Watch ramp, step 300. | oklch(0.806 0.092 82) | same | no component |
--opsin-status-watch-400 | primitive | Watch ramp, step 400. | oklch(0.714 0.123 82) | same | no component |
--opsin-status-watch-500 | primitive | Watch ramp, step 500. | oklch(0.622 0.129 82) | same | no component |
--opsin-status-watch-600 | primitive | Watch ramp, step 600. | oklch(0.541 0.112 82) | same | no component |
--opsin-status-watch-700 | primitive | Watch ramp, step 700. | oklch(0.452 0.094 82) | same | no component |
--opsin-status-watch-800 | primitive | Watch ramp, step 800. | oklch(0.362 0.076 82) | same | no component |
--opsin-status-watch-900 | primitive | Watch ramp, step 900. | oklch(0.276 0.059 82) | same | no component |
--opsin-status-watch-950 | primitive | Watch ramp, step 950. | oklch(0.208 0.046 82) | same | no component |
--opsin-status-watch-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.02 82) | oklch(0.208 0.046 82) | alert-banner, status-pill |
--opsin-status-watch-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.112 82) | oklch(0.806 0.092 82) | alert-banner, range-bar, range-legend, status-pill |
--opsin-status-watch-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.076 82) | oklch(0.884 0.059 82) | alert-banner, score-dial, status-pill |
--opsin-status-watch-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.60 0.123 82) | oklch(0.714 0.123 82) | score-dial |
--opsin-status-attention-50 | primitive | Needs attention ramp, step 50. | oklch(0.972 0.015 45) | same | no component |
--opsin-status-attention-100 | primitive | Needs attention ramp, step 100. | oklch(0.941 0.032 45) | same | no component |
--opsin-status-attention-200 | primitive | Needs attention ramp, step 200. | oklch(0.884 0.063 45) | same | no component |
--opsin-status-attention-300 | primitive | Needs attention ramp, step 300. | oklch(0.806 0.099 45) | same | no component |
--opsin-status-attention-400 | primitive | Needs attention ramp, step 400. | oklch(0.714 0.132 45) | same | no component |
--opsin-status-attention-500 | primitive | Needs attention ramp, step 500. | oklch(0.622 0.15 45) | same | no component |
--opsin-status-attention-600 | primitive | Needs attention ramp, step 600. | oklch(0.541 0.145 45) | same | no component |
--opsin-status-attention-700 | primitive | Needs attention ramp, step 700. | oklch(0.452 0.13 45) | same | no component |
--opsin-status-attention-800 | primitive | Needs attention ramp, step 800. | oklch(0.362 0.105 45) | same | no component |
--opsin-status-attention-900 | primitive | Needs attention ramp, step 900. | oklch(0.276 0.082 45) | same | no component |
--opsin-status-attention-950 | primitive | Needs attention ramp, step 950. | oklch(0.208 0.065 45) | same | no component |
--opsin-status-attention-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.015 45) | oklch(0.208 0.065 45) | alert-banner, status-pill |
--opsin-status-attention-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.145 45) | oklch(0.806 0.099 45) | alert-banner, range-bar, range-legend, status-pill |
--opsin-status-attention-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.105 45) | oklch(0.884 0.063 45) | alert-banner, score-dial, status-pill |
--opsin-status-attention-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.58 0.15 45) | oklch(0.714 0.132 45) | score-dial |
--opsin-status-urgent-50 | primitive | Urgent ramp, step 50. | oklch(0.972 0.014 27) | same | no component |
--opsin-status-urgent-100 | primitive | Urgent ramp, step 100. | oklch(0.941 0.03 27) | same | no component |
--opsin-status-urgent-200 | primitive | Urgent ramp, step 200. | oklch(0.884 0.061 27) | same | no component |
--opsin-status-urgent-300 | primitive | Urgent ramp, step 300. | oklch(0.806 0.11 27) | same | no component |
--opsin-status-urgent-400 | primitive | Urgent ramp, step 400. | oklch(0.714 0.176 27) | same | no component |
--opsin-status-urgent-500 | primitive | Urgent ramp, step 500. | oklch(0.622 0.2 27) | same | no component |
--opsin-status-urgent-600 | primitive | Urgent ramp, step 600. | oklch(0.541 0.194 27) | same | no component |
--opsin-status-urgent-700 | primitive | Urgent ramp, step 700. | oklch(0.452 0.176 27) | same | no component |
--opsin-status-urgent-800 | primitive | Urgent ramp, step 800. | oklch(0.362 0.148 27) | same | no component |
--opsin-status-urgent-900 | primitive | Urgent ramp, step 900. | oklch(0.276 0.115 27) | same | no component |
--opsin-status-urgent-950 | primitive | Urgent ramp, step 950. | oklch(0.208 0.088 27) | same | no component |
--opsin-status-urgent-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.014 27) | oklch(0.208 0.088 27) | alert-banner, status-pill |
--opsin-status-urgent-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.194 27) | oklch(0.806 0.11 27) | alert-banner, range-bar, range-legend, status-pill |
--opsin-status-urgent-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.148 27) | oklch(0.884 0.061 27) | alert-banner, score-dial, status-pill |
--opsin-status-urgent-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.52 0.2 27) | oklch(0.714 0.176 27) | score-dial |
--opsin-status-unknown-50 | primitive | Unknown ramp, step 50. | oklch(0.972 0.003 250) | same | no component |
--opsin-status-unknown-100 | primitive | Unknown ramp, step 100. | oklch(0.941 0.005 250) | same | no component |
--opsin-status-unknown-200 | primitive | Unknown ramp, step 200. | oklch(0.884 0.008 250) | same | no component |
--opsin-status-unknown-300 | primitive | Unknown ramp, step 300. | oklch(0.806 0.013 250) | same | no component |
--opsin-status-unknown-400 | primitive | Unknown ramp, step 400. | oklch(0.714 0.018 250) | same | no component |
--opsin-status-unknown-500 | primitive | Unknown ramp, step 500. | oklch(0.622 0.02 250) | same | no component |
--opsin-status-unknown-600 | primitive | Unknown ramp, step 600. | oklch(0.541 0.019 250) | same | no component |
--opsin-status-unknown-700 | primitive | Unknown ramp, step 700. | oklch(0.452 0.018 250) | same | no component |
--opsin-status-unknown-800 | primitive | Unknown ramp, step 800. | oklch(0.362 0.015 250) | same | no component |
--opsin-status-unknown-900 | primitive | Unknown ramp, step 900. | oklch(0.276 0.012 250) | same | no component |
--opsin-status-unknown-950 | primitive | Unknown ramp, step 950. | oklch(0.208 0.009 250) | same | no component |
--opsin-status-unknown-surface | semantic | The tinted background a component in this ramp sits on. | oklch(0.972 0.003 250) | oklch(0.208 0.009 250) | no component |
--opsin-status-unknown-line | semantic | The boundary, icon stroke or chart mark. The lightest value in the ramp that clears the non-text floor against surface. | oklch(0.541 0.019 250) | oklch(0.806 0.013 250) | no component |
--opsin-status-unknown-ink | semantic | Text and text-sized icons on surface. Clears the text floor against surface. | oklch(0.362 0.015 250) | oklch(0.884 0.008 250) | no component |
--opsin-status-unknown-accent | semantic | The identity fill: a bar fill, a dial track, a legend dot. Chosen for recognition, not for contrast. It must be bounded by line or labelled in ink; it is never the only thing that carries the meaning. | oklch(0.72 0.02 250) | oklch(0.714 0.018 250) | no component |
material
material
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-material-canvas-tint | semantic | Rung 0 (canvas): the tint over what is behind it. The application background. Nothing is behind it, so nothing shows through it. | var(--opsin-neutral-0) | var(--opsin-neutral-950) | surface |
--opsin-material-canvas-tint-alpha | semantic | Rung 0 (canvas): how opaque that tint is. | 1 | same | surface |
--opsin-material-canvas-blur | semantic | Rung 0 (canvas): backdrop blur radius. | 0px | same | surface |
--opsin-material-canvas-saturation | semantic | Rung 0 (canvas): backdrop saturation multiplier. | 1 | same | surface |
--opsin-material-canvas-border | semantic | Rung 0 (canvas): the boundary. | none | same | surface |
--opsin-material-canvas-shadow | semantic | Rung 0 (canvas): the shadow that separates it from what is behind. | none | same | surface |
--opsin-material-canvas-scrim | semantic | Rung 0 (canvas): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0 | same | surface |
--opsin-material-canvas-opaque | semantic | Rung 0 (canvas): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | var(--opsin-neutral-0) | var(--opsin-neutral-950) | surface |
--opsin-material-inset-tint | semantic | Rung 0.5 (inset): the tint over what is behind it. The recessed well inside a card: the explanatory note a Callout draws inside the reading it annotates, and the track a RangeBar lays its range along. Its fill sits below the card fill in both themes, so the well reads as carved into the card rather than lifted off it. In light it is neutral-100, one step under the white card, which is where a Callout already sat. In dark it is a value between the page and the card, below the card so the well is a recess and above the page so a Callout used on its own is still visible. | var(--opsin-neutral-100) | oklch(0.178 0.006 250) | callout, range-bar, surface |
--opsin-material-inset-tint-alpha | semantic | Rung 0.5 (inset): how opaque that tint is. | 1 | same | surface |
--opsin-material-inset-blur | semantic | Rung 0.5 (inset): backdrop blur radius. | 0px | same | surface |
--opsin-material-inset-saturation | semantic | Rung 0.5 (inset): backdrop saturation multiplier. | 1 | same | surface |
--opsin-material-inset-border | semantic | Rung 0.5 (inset): the boundary. | none | same | surface |
--opsin-material-inset-shadow | semantic | Rung 0.5 (inset): the shadow that separates it from what is behind. | none | same | surface |
--opsin-material-inset-scrim | semantic | Rung 0.5 (inset): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0 | same | surface |
--opsin-material-inset-opaque | semantic | Rung 0.5 (inset): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | var(--opsin-neutral-100) | oklch(0.178 0.006 250) | surface |
--opsin-material-card-tint | semantic | Rung 1 (card): the tint over what is behind it. The default home for a health value. Opaque, bounded by a line rather than a shadow, and the rung every ResultCard, MetricTile and RangeBar sits on. | var(--opsin-neutral-0) | var(--opsin-neutral-900) | surface |
--opsin-material-card-tint-alpha | semantic | Rung 1 (card): how opaque that tint is. | 1 | same | surface |
--opsin-material-card-blur | semantic | Rung 1 (card): backdrop blur radius. | 0px | same | surface |
--opsin-material-card-saturation | semantic | Rung 1 (card): backdrop saturation multiplier. | 1 | same | surface |
--opsin-material-card-border | semantic | Rung 1 (card): the boundary. | var(--opsin-neutral-200) | var(--opsin-neutral-800) | surface |
--opsin-material-card-shadow | semantic | Rung 1 (card): the shadow that separates it from what is behind. | none | same | surface |
--opsin-material-card-scrim | semantic | Rung 1 (card): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0 | same | surface |
--opsin-material-card-opaque | semantic | Rung 1 (card): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | var(--opsin-neutral-0) | var(--opsin-neutral-900) | surface |
--opsin-material-raised-tint | semantic | Rung 2 (raised): the tint over what is behind it. Menus, popovers, tooltips, a dragged card. Still opaque: the shadow, not translucency, is what says 'above'. | var(--opsin-neutral-0) | var(--opsin-neutral-800) | surface |
--opsin-material-raised-tint-alpha | semantic | Rung 2 (raised): how opaque that tint is. | 1 | same | surface |
--opsin-material-raised-blur | semantic | Rung 2 (raised): backdrop blur radius. | 0px | same | surface |
--opsin-material-raised-saturation | semantic | Rung 2 (raised): backdrop saturation multiplier. | 1 | same | surface |
--opsin-material-raised-border | semantic | Rung 2 (raised): the boundary. | var(--opsin-neutral-200) | var(--opsin-neutral-700) | surface |
--opsin-material-raised-shadow | semantic | Rung 2 (raised): the shadow that separates it from what is behind. | 0 1px 2px oklch(0 0 0 / 0.06), 0 4px 12px oklch(0 0 0 / 0.06) | same | surface |
--opsin-material-raised-scrim | semantic | Rung 2 (raised): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0 | same | surface |
--opsin-material-raised-opaque | semantic | Rung 2 (raised): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | var(--opsin-neutral-0) | var(--opsin-neutral-800) | surface |
--opsin-material-sheet-tint | semantic | Rung 3 (sheet): the tint over what is behind it. A bottom sheet or side panel the reader can dismiss by dragging. Its tint is now near opaque, so the panel lands close to the card colour and a white control inside it no longer floats above a greyer surface. What keeps the covered page recognisable is the scrim around the panel rather than the page reading through the panel, because at this opacity very little of the page shows through the tint. | var(--opsin-neutral-0) | var(--opsin-neutral-900) | surface |
--opsin-material-sheet-tint-alpha | semantic | Rung 3 (sheet): how opaque that tint is. | 0.93 | 0.9 | surface |
--opsin-material-sheet-blur | semantic | Rung 3 (sheet): backdrop blur radius. | 20px | same | surface |
--opsin-material-sheet-saturation | semantic | Rung 3 (sheet): backdrop saturation multiplier. | 1.6 | same | surface |
--opsin-material-sheet-border | semantic | Rung 3 (sheet): the boundary. | oklch(0 0 0 / 0.08) | oklch(1 0 0 / 0.10) | surface |
--opsin-material-sheet-shadow | semantic | Rung 3 (sheet): the shadow that separates it from what is behind. | 0 -1px 2px oklch(0 0 0 / 0.05) | same | sheet, surface |
--opsin-material-sheet-scrim | semantic | Rung 3 (sheet): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0.93 | same | surface |
--opsin-material-sheet-opaque | semantic | Rung 3 (sheet): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | var(--opsin-neutral-0) | var(--opsin-neutral-900) | surface |
--opsin-material-overlay-tint | semantic | Rung 4 (overlay): the tint over what is behind it. A pinned toolbar, a tab bar and a floating action bar are all chrome that content scrolls beneath. | var(--opsin-neutral-0) | var(--opsin-neutral-900) | surface |
--opsin-material-overlay-tint-alpha | semantic | Rung 4 (overlay): how opaque that tint is. | 0.74 | 0.7 | surface |
--opsin-material-overlay-blur | semantic | Rung 4 (overlay): backdrop blur radius. | 28px | same | surface |
--opsin-material-overlay-saturation | semantic | Rung 4 (overlay): backdrop saturation multiplier. | 1.8 | same | surface |
--opsin-material-overlay-border | semantic | Rung 4 (overlay): the boundary. | oklch(0 0 0 / 0.10) | oklch(1 0 0 / 0.12) | surface |
--opsin-material-overlay-shadow | semantic | Rung 4 (overlay): the shadow that separates it from what is behind. | 0 8px 32px oklch(0 0 0 / 0.12) | same | combobox, menu, popover, select, surface, toast, tooltip |
--opsin-material-overlay-scrim | semantic | Rung 4 (overlay): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0.74 | same | surface |
--opsin-material-overlay-opaque | semantic | Rung 4 (overlay): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | var(--opsin-neutral-0) | var(--opsin-neutral-900) | surface |
--opsin-material-scrim-tint | semantic | Rung 5 (scrim): the tint over what is behind it. The dimming layer behind a modal dialog or a consent sheet. Its job is to remove the page from consideration, not to look like glass. | var(--opsin-neutral-950) | var(--opsin-neutral-1000) | surface |
--opsin-material-scrim-tint-alpha | semantic | Rung 5 (scrim): how opaque that tint is. | 0.44 | 0.6 | surface |
--opsin-material-scrim-blur | semantic | Rung 5 (scrim): backdrop blur radius. | 2px | same | surface |
--opsin-material-scrim-saturation | semantic | Rung 5 (scrim): backdrop saturation multiplier. | 1 | same | surface |
--opsin-material-scrim-border | semantic | Rung 5 (scrim): the boundary. | none | same | surface |
--opsin-material-scrim-shadow | semantic | Rung 5 (scrim): the shadow that separates it from what is behind. | none | same | surface |
--opsin-material-scrim-scrim | semantic | Rung 5 (scrim): the minimum scrim opacity needed for text on this rung to clear the contrast floor. | 0.44 | same | surface |
--opsin-material-scrim-opaque | semantic | Rung 5 (scrim): the opaque substitute used under prefers-reduced-transparency and where backdrop-filter is unsupported. | oklch(0.205 0.006 250 / 0.72) | oklch(0 0 0 / 0.8) | surface |
motion
ease
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-ease-spring-snap | semantic | Direct manipulation only: a switch the reader just flipped, a segmented control, a pressed button settling. It overshoots by 1.5%. That is enough to feel physical but not enough to look playful. The 1.5% is the largest overshoot in the system but not the only one: spring-settle overshoots by 0.88%. Only spring-calm and spring-sheet reach their target without passing it. | linear(0, 0.0715, 0.2271, 0.4053, 0.5722, 0.7119, 0.8198, 0.8978, 0.9505, 0.9836, 1.0025, 1.0118, 1.015, 1.0147, 1.0126, 1.01, 1.0073, 1.0051, 1.0033, 1.0019, 1) | same | no component |
--opsin-ease-spring-settle | semantic | The workhorse for chrome: popovers, tooltips, menus, chips appearing and disappearing. | linear(0, 0.0742, 0.2328, 0.4113, 0.5758, 0.7116, 0.8157, 0.8905, 0.9412, 0.9736, 0.9928, 1.003, 1.0076, 1.0088, 1.0082, 1.0068, 1.0053, 1.0038, 1.0026, 1.0017, 1) | same | no component |
--opsin-ease-spring-calm | semantic | A health value that changes while it is already on screen: a bar re-filling from one reading to the next, a dial travelling between two values the reader has already been shown. Never a first paint and never a first reveal. A value arrives at its final figure, with no count-up, no dial sweep and no line drawing itself in (health/motion-in-health-ui rule 2). Slightly overdamped (zeta just over 1) so it never overshoots and never bounces. | linear(0, 0.0829, 0.2457, 0.4157, 0.5642, 0.6832, 0.774, 0.841, 0.8893, 0.9236, 0.9476, 0.9643, 0.9757, 0.9836, 0.9889, 0.9926, 0.995, 0.9967, 0.9978, 0.9985, 1) | same | no component |
--opsin-ease-spring-sheet | semantic | Large surfaces travelling a long distance: sheets, dialogs, full-screen pushes. Overdamped, because a sheet that bounces at the top of its travel reads as a dropped object. | linear(0, 0.0881, 0.2576, 0.431, 0.5798, 0.6971, 0.7854, 0.8497, 0.8958, 0.9282, 0.9508, 0.9664, 0.9771, 0.9845, 0.9895, 0.9929, 0.9952, 0.9967, 0.9978, 0.9985, 1) | same | dialog, sheet |
--opsin-ease-standard | semantic | Non-spring transitions where a spring would be overkill: colour, opacity, border. Fast out, slow in. | cubic-bezier(0.2, 0, 0, 1) | same | accordion, body-map, button, checkbox, combobox, consent-sheet, dialog, menu, number-field, popover, progress, radio-group, scale-input, scroll-area, segmented-control, select, sheet, skeleton, slider, switch, symptom-picker, tab-bar, tabs, textarea, toast, tooltip |
--opsin-ease-enter | semantic | Something arriving from off-screen or from nothing. Decelerating, because an arrival should feel like it is coming to rest. | cubic-bezier(0.05, 0.7, 0.1, 1) | same | no component |
--opsin-ease-exit | semantic | Something leaving. Accelerating and shorter than its enter, because a reader does not need to watch a dismissal finish. | cubic-bezier(0.3, 0, 0.8, 0.15) | same | dialog |
duration
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-duration-spring-snap | semantic | Settle time for the spring-snap spring, measured from its own parameters. | 283ms | same | no component |
--opsin-duration-spring-settle | semantic | Settle time for the spring-settle spring, measured from its own parameters. | 382ms | same | no component |
--opsin-duration-spring-calm | semantic | Settle time for the spring-calm spring, measured from its own parameters. | 550ms | same | no component |
--opsin-duration-spring-sheet | semantic | Settle time for the spring-sheet spring, measured from its own parameters. | 483ms | same | dialog, sheet |
--opsin-duration-instant | semantic | State change with no travel: hover tint, focus ring, checkbox tick. | 80ms | same | no component |
--opsin-duration-fast | semantic | Small elements moving a small distance. | 140ms | same | accordion, body-map, button, checkbox, combobox, consent-sheet, dialog, menu, number-field, popover, progress, radio-group, scale-input, scroll-area, segmented-control, select, sheet, skeleton, slider, switch, symptom-picker, tab-bar, tabs, textarea, toast, tooltip |
--opsin-duration-base | semantic | The default for chrome that is not spring-driven. | 220ms | same | dialog, sheet |
--opsin-duration-slow | semantic | Layout change: a list reflowing, a card expanding. | 360ms | same | no component |
--opsin-duration-deliberate | semantic | The ceiling on a transition a reader is waiting on, such as a first-run reveal or a consent sheet, where the point is that the reader notices. No such transition may exceed it. A looping placeholder period, like the skeleton shimmer, is bounded instead by its iteration count, so a single sweep of it may run longer. | 560ms | same | no component |
--opsin-duration-shimmer | semantic | One sweep of a loading placeholder's sheen. This is a period, the time for the sheen to make one pass across the bar, and not a travel time. At 1600ms the movement reads as calm rather than as urgency, which the first motion rule requires of anything that is not a value the reader controls. Its consumer pairs it with a finite iteration count so the total motion stays under the five seconds at which WCAG 2.2 SC 2.2.2 engages. | 1600ms | same | skeleton |
type
font
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-font-sans | semantic | The sans family stack. | system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif | same | no component |
--opsin-font-mono | semantic | The mono family stack. | ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace | same | no component |
--opsin-font-numeric | semantic | The numeric family stack. | system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif | same | result-card, value |
text
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-text-large-title-size | semantic | The largest step in the scale, reserved for a surface whose entire subject is one number or one word. No component in the system sets a value at this step yet. | 2.125rem | same | no component |
--opsin-text-large-title-leading | semantic | Line height for largeTitle, unitless so it scales with the size. | 1.206 | same | no component |
--opsin-text-large-title-tracking | semantic | Letter spacing for largeTitle. | -0.011em | same | no component |
--opsin-text-large-title-weight | semantic | Font weight for largeTitle. | 700 | same | no component |
--opsin-text-title1-size | semantic | A screen title, and the hero treatment a value's number takes at size display. | 1.75rem | same | result-card, value |
--opsin-text-title1-leading | semantic | Line height for title1, unitless so it scales with the size. | 1.214 | same | result-card, value |
--opsin-text-title1-tracking | semantic | Letter spacing for title1. | -0.009em | same | result-card, value |
--opsin-text-title1-weight | semantic | Font weight for title1. | 700 | same | result-card, value |
--opsin-text-title2-size | semantic | Section title; the floor for a primary health value inside a card. | 1.375rem | same | goal-ring |
--opsin-text-title2-leading | semantic | Line height for title2, unitless so it scales with the size. | 1.273 | same | goal-ring |
--opsin-text-title2-tracking | semantic | Letter spacing for title2. | -0.006em | same | goal-ring |
--opsin-text-title2-weight | semantic | Font weight for title2. | 600 | same | goal-ring |
--opsin-text-title3-size | semantic | A Dialog or Sheet title, and the unit beside a value's number at size display. | 1.25rem | same | dialog, questionnaire, reading-input, sheet, value |
--opsin-text-title3-leading | semantic | Line height for title3, unitless so it scales with the size. | 1.25 | same | dialog, questionnaire, reading-input, sheet, value |
--opsin-text-title3-tracking | semantic | Letter spacing for title3. | -0.004em | same | dialog, questionnaire, reading-input, sheet, value |
--opsin-text-title3-weight | semantic | Font weight for title3. | 600 | same | dialog, questionnaire, reading-input, sheet, value |
--opsin-text-headline-size | semantic | An emphasised line of body text, such as a status sentence or a question in a form. | 1.0625rem | same | accordion, alert-banner, avatar, button, callout, card, care-card, empty-state, field, log-sheet, menu, popover, range-bar, reading-input, result-card, scale-input, segmented-control, status-pill, surface, tabs, textarea, timeline-entry, toast, trend-sparkline, value |
--opsin-text-headline-leading | semantic | Line height for headline, unitless so it scales with the size. | 1.294 | same | accordion, alert-banner, avatar, button, callout, card, care-card, empty-state, field, log-sheet, menu, popover, range-bar, reading-input, result-card, scale-input, segmented-control, status-pill, surface, tabs, textarea, timeline-entry, toast, trend-sparkline, value |
--opsin-text-headline-tracking | semantic | Letter spacing for headline. | -0.003em | same | accordion, alert-banner, avatar, button, callout, card, care-card, empty-state, field, log-sheet, menu, popover, range-bar, reading-input, result-card, scale-input, segmented-control, status-pill, surface, tabs, textarea, timeline-entry, toast, trend-sparkline, value |
--opsin-text-headline-weight | semantic | Font weight for headline. | 600 | same | accordion, alert-banner, avatar, button, callout, card, care-card, empty-state, field, log-sheet, menu, popover, range-bar, reading-input, result-card, scale-input, segmented-control, status-pill, surface, tabs, textarea, timeline-entry, toast, trend-sparkline, value |
--opsin-text-body-size | semantic | Everything a reader reads as prose. The anchor of the scale. | 1.0625rem | same | accordion, alert-banner, badge, callout, card, care-card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, empty-state, field, link, menu, number-field, popover, questionnaire, radio-group, range-bar, range-legend, reading-input, relative-time, result-card, score-dial, scroll-area, select, sheet, surface, switch, symptom-picker, table, tabs, term, textarea, timeline-entry, toast, tooltip, trend-sparkline, value, visually-hidden |
--opsin-text-body-leading | semantic | Line height for body, unitless so it scales with the size. | 1.294 | same | accordion, alert-banner, badge, callout, card, care-card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, empty-state, field, link, menu, number-field, popover, questionnaire, radio-group, range-bar, range-legend, reading-input, relative-time, result-card, score-dial, scroll-area, select, sheet, skeleton, surface, switch, symptom-picker, table, tabs, term, textarea, timeline-entry, toast, tooltip, trend-sparkline, value, visually-hidden |
--opsin-text-body-tracking | semantic | Letter spacing for body. | -0.003em | same | accordion, alert-banner, badge, callout, card, care-card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, empty-state, field, link, menu, number-field, popover, questionnaire, radio-group, range-bar, range-legend, reading-input, relative-time, result-card, score-dial, scroll-area, select, sheet, surface, switch, symptom-picker, table, tabs, term, textarea, timeline-entry, toast, tooltip, trend-sparkline, value, visually-hidden |
--opsin-text-body-weight | semantic | Font weight for body. | 400 | same | accordion, alert-banner, badge, callout, card, care-card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, empty-state, field, link, menu, number-field, popover, questionnaire, radio-group, range-bar, range-legend, reading-input, relative-time, result-card, score-dial, scroll-area, select, sheet, surface, switch, symptom-picker, table, tabs, term, textarea, timeline-entry, toast, tooltip, trend-sparkline, value, visually-hidden |
--opsin-text-callout-size | semantic | Secondary prose inside a card or a callout. | 1rem | same | dialog, sheet, toast |
--opsin-text-callout-leading | semantic | Line height for callout, unitless so it scales with the size. | 1.313 | same | dialog, sheet, toast |
--opsin-text-callout-tracking | semantic | Letter spacing for callout. | -0.002em | same | dialog, sheet, toast |
--opsin-text-callout-weight | semantic | Font weight for callout. | 400 | same | dialog, sheet, toast |
--opsin-text-subheadline-size | semantic | A supporting line under a title. | 0.9375rem | same | button, care-card, empty-state, goal-ring, metric-tile, progress, radio-group, score-dial, segmented-control, slider, spinner, status-pill, stepper, table |
--opsin-text-subheadline-leading | semantic | Line height for subheadline, unitless so it scales with the size. | 1.333 | same | button, care-card, empty-state, goal-ring, metric-tile, progress, radio-group, score-dial, segmented-control, slider, spinner, status-pill, stepper, table |
--opsin-text-subheadline-tracking | semantic | Letter spacing for subheadline. | -0.001em | same | button, care-card, empty-state, goal-ring, metric-tile, progress, radio-group, score-dial, segmented-control, slider, spinner, status-pill, stepper, table |
--opsin-text-subheadline-weight | semantic | Font weight for subheadline. | 400 | same | button, care-card, empty-state, goal-ring, metric-tile, progress, radio-group, score-dial, segmented-control, slider, spinner, status-pill, stepper, table |
--opsin-text-subheadline-emphasis-size | semantic | The emphasised twin of subheadline, for a compact control's label, where the control must read as narrower and never as quieter. | 0.9375rem | same | avatar, button |
--opsin-text-subheadline-emphasis-leading | semantic | Line height for subheadlineEmphasis, unitless so it scales with the size. | 1.333 | same | avatar, button |
--opsin-text-subheadline-emphasis-tracking | semantic | Letter spacing for subheadlineEmphasis. | -0.001em | same | avatar, button |
--opsin-text-subheadline-emphasis-weight | semantic | Font weight for subheadlineEmphasis. | 600 | same | avatar, button |
--opsin-text-footnote-size | semantic | Provenance: who measured this, when, with what. | 0.8125rem | same | body-map, card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, goal-ring, log-sheet, menu, metric-tile, questionnaire, radio-group, range-bar, range-legend, result-card, scale-input, score-dial, sheet, source-citation, status-pill, stepper, switch, symptom-picker, table, timeline-entry, toast, tooltip, trend-sparkline |
--opsin-text-footnote-leading | semantic | Line height for footnote, unitless so it scales with the size. | 1.385 | same | body-map, card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, goal-ring, log-sheet, menu, metric-tile, questionnaire, radio-group, range-bar, range-legend, result-card, scale-input, score-dial, sheet, source-citation, status-pill, stepper, switch, symptom-picker, table, timeline-entry, toast, tooltip, trend-sparkline |
--opsin-text-footnote-tracking | semantic | Letter spacing for footnote. | 0em | same | body-map, card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, goal-ring, log-sheet, menu, metric-tile, questionnaire, radio-group, range-bar, range-legend, result-card, scale-input, score-dial, sheet, source-citation, status-pill, stepper, switch, symptom-picker, table, timeline-entry, toast, tooltip, trend-sparkline |
--opsin-text-footnote-weight | semantic | Font weight for footnote. | 400 | same | body-map, card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, dose-tracker, goal-ring, log-sheet, menu, metric-tile, questionnaire, radio-group, range-bar, range-legend, result-card, scale-input, score-dial, sheet, source-citation, status-pill, stepper, switch, symptom-picker, table, timeline-entry, toast, tooltip, trend-sparkline |
--opsin-text-caption1-size | semantic | Axis labels, legend text, and legal text. | 0.75rem | same | avatar, badge, consent-sheet, dose-tracker, range-bar, skeleton, tab-bar, visually-hidden |
--opsin-text-caption1-leading | semantic | Line height for caption1, unitless so it scales with the size. | 1.333 | same | avatar, badge, consent-sheet, dose-tracker, range-bar, skeleton, tab-bar, visually-hidden |
--opsin-text-caption1-tracking | semantic | Letter spacing for caption1. | 0.002em | same | avatar, badge, consent-sheet, dose-tracker, range-bar, skeleton, tab-bar, visually-hidden |
--opsin-text-caption1-weight | semantic | Font weight for caption1. | 400 | same | avatar, badge, consent-sheet, dose-tracker, range-bar, skeleton, tab-bar, visually-hidden |
--opsin-text-caption2-size | semantic | The smallest text the system permits, and only for text that repeats a label already present elsewhere. Never the only place a fact appears. | 0.6875rem | same | no component |
--opsin-text-caption2-leading | semantic | Line height for caption2, unitless so it scales with the size. | 1.182 | same | no component |
--opsin-text-caption2-tracking | semantic | Letter spacing for caption2. | 0.005em | same | no component |
--opsin-text-caption2-weight | semantic | Font weight for caption2. | 500 | same | no component |
numerals
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-numerals | semantic | Every component that renders a number sets this, so a changing value does not shift its own layout. | tabular-nums | same | no component |
space
space
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-space-0 | primitive | 0px. | 0rem | same | no component |
--opsin-space-1 | primitive | Gap between an icon and its label. | 0.25rem | same | badge, button, callout, care-card, checkbox, combobox, dialog, dose-tracker, empty-state, field, goal-ring, log-sheet, menu, questionnaire, radio-group, range-bar, result-card, scale-input, scroll-area, segmented-control, select, sheet, slider, source-citation, status-pill, stepper, surface, symptom-picker, tab-bar, tabs, timeline-entry, toast, tooltip, trend-sparkline |
--opsin-space-2 | primitive | Gap between tightly related lines. For the separation between two interactive targets see targets.separation, which is the same number and carries its scope. | 0.5rem | same | alert-banner, avatar, badge, body-map, button, callout, combobox, consent-sheet, dialog, disclaimer-note, dose-tracker, empty-state, field, icon-button, log-sheet, menu, metric-tile, number-field, popover, progress, questionnaire, radio-group, range-bar, range-legend, reading-input, relative-time, scale-input, score-dial, scroll-area, segmented-control, select, sheet, skeleton, slider, spinner, status-pill, surface, symptom-picker, tab-bar, table, tabs, textarea, timeline-entry, toast, tooltip, trend-sparkline, visually-hidden |
--opsin-space-3 | primitive | Inner padding of a compact control. | 0.75rem | same | accordion, alert-banner, button, card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, divider, empty-state, field, log-sheet, menu, metric-tile, popover, progress, radio-group, reading-input, result-card, scroll-area, segmented-control, select, sheet, slider, status-pill, stepper, surface, symptom-picker, tab-bar, table, tabs, textarea, timeline-entry, toast, tooltip, value |
--opsin-space-4 | primitive | The default gap between elements inside a card. | 1rem | same | accordion, avatar, badge, button, callout, care-card, consent-sheet, dialog, divider, empty-state, goal-ring, link, log-sheet, menu, popover, range-legend, result-card, scale-input, score-dial, segmented-control, sheet, surface, switch, tabs, timeline-entry, toast |
--opsin-space-5 | primitive | Card inner padding on a phone. | 1.25rem | same | avatar, button, consent-sheet, dialog, questionnaire, sheet, slider, switch, symptom-picker |
--opsin-space-6 | primitive | Card inner padding on a wide screen; gap between cards. | 1.5rem | same | avatar, card, dialog, disclaimer-note, empty-state, field, log-sheet, skeleton, stepper, switch, tab-bar, trend-sparkline |
--opsin-space-8 | primitive | Gap between sections within a screen. | 2rem | same | avatar, body-map, disclaimer-note, popover, range-bar, reading-input, sheet, stepper |
--opsin-space-10 | primitive | Space above a section heading. | 2.5rem | same | avatar, sheet, skeleton, switch |
--opsin-space-12 | primitive | Gap between major regions of a screen. | 3rem | same | avatar, trend-sparkline |
--opsin-space-16 | primitive | Top of a screen below the safe area; the space a consent sheet leaves above its first question. | 4rem | same | dialog, skeleton |
--opsin-space-20 | primitive | Empty-state vertical rhythm. | 5rem | same | no component |
--opsin-space-24 | primitive | The largest step. Beyond this, use a layout, not a gap. | 6rem | same | no component |
--opsin-space-px | primitive | Hairline borders only. | 0.0625rem | same | body-map, trend-sparkline |
--opsin-space-0-5 | primitive | Optical nudges. Not a layout step. | 0.125rem | same | badge, dose-tracker, radio-group, range-legend, result-card, scroll-area, segmented-control, status-pill, stepper, switch, tab-bar, tabs, term, trend-sparkline |
target
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-target-minimum | semantic | The opsinjs floor for any interactive control, applied to the hit area rather than to the visible box. | 2.75rem | same | accordion, body-map, button, card, checkbox, combobox, consent-sheet, dialog, disclaimer-note, field, icon-button, menu, metric-tile, number-field, popover, questionnaire, radio-group, reading-input, scale-input, segmented-control, select, sheet, slider, source-citation, switch, symptom-picker, tab-bar, tabs, textarea, toast, tooltip |
--opsin-target-comfortable | semantic | The default for a primary action in the product theme. | 3rem | same | dialog |
--opsin-target-generous | semantic | A single primary action on a consent, escalation or emergency surface, where a mis-tap has a real cost. | 3.5rem | same | no component |
--opsin-target-separation | semantic | The minimum gap between two adjacent targets whose visible boxes are smaller than 44px. It is a floor for undersized targets only. Two targets that both meet the 44px minimum are outside its scope, and separating those is governed by the differing cost of a mis-tap between them rather than by a fixed gap. | 0.5rem | same | alert-banner, card, care-card, consent-sheet, result-card |
gutter
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-gutter-phone | semantic | The screen gutter in the phone responsive mode. | 16px | same | no component |
--opsin-gutter-tablet | semantic | The screen gutter in the tablet responsive mode. | 24px | same | no component |
--opsin-gutter-wide | semantic | The screen gutter in the wide responsive mode. | 32px | same | no component |
measure
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-measure-tight | semantic | A caption or a legend. | 45ch | same | dialog, empty-state, goal-ring, popover, tooltip |
--opsin-measure-comfortable | semantic | The maximum line length for prose anywhere in the product, including a disclaimer nobody wants to read. | 66ch | same | disclaimer-note, result-card, score-dial, sheet, source-citation, term |
--opsin-measure-wide | semantic | Code and machine output only. | 80ch | same | no component |
graphic
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-graphic-dial | semantic | The maximum width of the ScoreDial arc. This is 16em against the product body of 1.0625rem, which is 17rem and lands on the 4px grid at 68 steps, and it yields to w-full when the column is narrower. | 17rem | same | goal-ring, score-dial |
safe
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-safe-top | semantic | The top safe-area inset, for installed web apps where browser chrome does not protect the edge. | env(safe-area-inset-top, 0px) | same | no component |
--opsin-safe-right | semantic | The right safe-area inset, for installed web apps where browser chrome does not protect the edge. | env(safe-area-inset-right, 0px) | same | sheet |
--opsin-safe-bottom | semantic | The bottom safe-area inset, for installed web apps where browser chrome does not protect the edge. | env(safe-area-inset-bottom, 0px) | same | dialog, sheet |
--opsin-safe-left | semantic | The left safe-area inset, for installed web apps where browser chrome does not protect the edge. | env(safe-area-inset-left, 0px) | same | sheet |
shape
radius
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-radius-base | semantic | The one radius the whole ladder is derived from. | 0.875rem | same | accordion, alert-banner, button, callout, card, care-card, combobox, empty-state, field, menu, metric-tile, popover, questionnaire, radio-group, range-bar, reading-input, result-card, scale-input, segmented-control, select, skeleton, symptom-picker, tab-bar, textarea, timeline-entry, toast, tooltip, trend-sparkline |
--opsin-radius-none | semantic | Full-bleed media and anything that meets a screen edge. | 0rem | same | no component |
--opsin-radius-xs | semantic | The floor for a nested corner. Tags inside a chip, a swatch inside a legend. | 0.25rem | same | popover, range-legend, surface, symptom-picker, term, tooltip |
--opsin-radius-sm | semantic | Inputs and small controls inside a card. | 0.4375rem | same | card, checkbox, combobox, consent-sheet, dialog, divider, field, log-sheet, menu, number-field, progress, reading-input, scroll-area, select, sheet, skeleton, slider, switch, tab-bar, tabs, toast, visually-hidden |
--opsin-radius-md | semantic | The default. Buttons, chips, cards. | 0.875rem | same | alert-banner, button, callout, card, combobox, empty-state, menu, metric-tile, popover, questionnaire, radio-group, result-card, scale-input, segmented-control, select, skeleton, symptom-picker, tab-bar, textarea, toast, tooltip |
--opsin-radius-lg | semantic | Cards on a phone, where the card is nearly the width of the screen. | 1.3125rem | same | accordion, card, combobox, disclaimer-note, menu, popover, result-card, scroll-area, segmented-control, select, surface, toast |
--opsin-radius-xl | semantic | Sheets and dialogs. Applied to the leading edge only when the surface meets a screen edge on the other side. | 1.75rem | same | alert-banner, dialog, sheet |
--opsin-radius-inner-card | semantic | A box inside a card at the comfortable density (card padding p-5). | max(calc(0.875rem - 5 * var(--spacing)), var(--opsin-radius-xs)) | same | no component |
--opsin-radius-inner-card-compact | semantic | A box inside a card at the compact density (card padding p-4). | max(calc(0.875rem - 4 * var(--spacing)), var(--opsin-radius-xs)) | same | no component |
corner-shape
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-corner-shape | semantic | The squircle curvature. Degrades to round where corner-shape is unsupported. | superellipse(4) | same | alert-banner, callout, card, dialog, metric-tile, result-card, sheet |
border
| Token | Tier | What it controls | Light | Dark | Used by |
|---|---|---|---|---|---|
--opsin-border-hairline | semantic | Every boundary in the system by default. | 1px | same | button, surface |
--opsin-border-emphasis | semantic | The boundary of a surface carrying attention or urgent, where the boundary is one of the three non-colour carriers of the status. | 2px | same | disclaimer-note, field, surface |
--opsin-border-focus | semantic | The focus ring. Always 2px with a 2px offset, always in a colour measured against both the surface and the page behind it, and never removed. See /docs/accessibility/keyboard-and-focus. | 2px | same | accordion, body-map, button, card, checkbox, combobox, consent-sheet, link, menu, number-field, popover, questionnaire, radio-group, scale-input, scroll-area, segmented-control, select, slider, switch, symptom-picker, tab-bar, table, tabs, term, textarea, toast, tooltip |
--opsin-border-focus-offset | semantic | Offset for the focus boundary. | 2px | same | accordion, body-map, button, card, checkbox, combobox, consent-sheet, link, menu, number-field, popover, questionnaire, radio-group, scale-input, scroll-area, segmented-control, select, slider, switch, symptom-picker, tab-bar, table, tabs, term, textarea, toast, tooltip |