Token coverage
Every value in every contract, sorted by why it has a token or doesn't. A value in a layer counts once, however many variants it applies to. npm run docs refreshes it.
| Values | Share | Meaning | |
|---|---|---|---|
| Has a token | 1014 | 60% | Uses a token, and the check tests it. |
| Token suggested | 0 | 0% | A token I want that doesn't exist yet. The freeze turned every other suggestion into a token. |
| How Figma builds it | 466 | 28% | How Figma builds the layer (position, inset, which sides get a stroke). Nothing to tokenise. |
| Figma frame size | 129 | 8% | A root size that is just the Figma frame. Written down, not checked. |
| No token, on purpose | 48 | 3% | Plain on purpose, and the contract says why. |
| Open gap | 28 | 2% | No token and no reason. Each one needs a decision from me. |
By contract
| Has a token | Token suggested | How Figma builds it | Figma frame size | No token, on purpose | Open gap | |
|---|---|---|---|---|---|---|
| Badge | 25 | · | 21 | · | · | · |
| Button | 83 | · | 38 | 9 | 5 | 1 |
| Carousel | 43 | · | 27 | 9 | 2 | 1 |
| Chip | 32 | · | 16 | 8 | · | 1 |
| Divider | 2 | · | 2 | 2 | · | · |
| Floating effect | 1 | · | · | · | · | · |
| Hero Media | 6 | · | 9 | 2 | · | · |
| IconButton | 87 | · | 32 | 7 | 6 | 2 |
| InlineBanner | 44 | · | 34 | · | · | · |
| Input | 166 | · | 35 | 20 | 4 | 3 |
| ListItem | 95 | · | 32 | 10 | 2 | 1 |
| Lock frame effect | 1 | · | · | · | · | · |
| Menu effect | 1 | · | · | · | · | · |
| Menu | 32 | · | 16 | 6 | · | 1 |
| Navigation | 13 | · | 21 | 1 | 2 | · |
| Paper effect | 6 | · | · | · | 7 | · |
| Projects | 77 | · | 33 | 8 | 4 | 4 |
| TabItem | 37 | · | 15 | 12 | · | 1 |
| Tabs | · | · | 2 | 1 | 1 | · |
| Tag | 26 | · | 13 | 3 | · | 1 |
| TestimonialPicture | 2 | · | 8 | 1 | · | · |
| Testimonials | 81 | · | 37 | 13 | 2 | 4 |
| Thumb effect | 1 | · | · | · | · | · |
| Thumbs | 77 | · | 51 | 9 | 6 | 5 |
| Toggle | 64 | · | 20 | 8 | 6 | 3 |
| Tooltip | 12 | · | 4 | · | 1 | · |
Tokens that should be there
None. The freeze on 2026-10-20 turned all 122 suggestions into tokens.
No token, on purpose
Strokes drawn inside
Figma draws a stroke inside the shape. A CSS border takes up space, so the button would come out 1px wider. These are an inset box-shadow instead. The width and the colour are tokens, only the shadow around them isn't.
- ButtonIconButtonToggle
root.box-shadowinset var(--spacing-outline-small) var(--spacing-outline-small) 0 0 var(--actions-primary-default-outline) and 4 more, one per state - Tabs
root.box-shadowinset 0 calc(-1 * var(--spacing-outline-small)) 0 0 var(--tabs-line)
Focus rings
The ring sits spacing/gap/2xsmall outside the element, so its inset is that token turned negative. On a rounded element the ring's radius grows by the same gap, so the two curves stay parallel.
- ButtonCarouselChipIconButtonInputProjectsTagTestimonialsThumbsToggle
focus-ring.insetcalc(-1 * var(--spacing-gap-2xsmall)) - CarouselThumbs
focus-ring.border-radiuscalc(var(--spacing-radius-xlarge) + var(--spacing-gap-2xsmall)) - Menu
focus-ring.insetvar(--spacing-gap-medium-large) calc(-1 * var(--spacing-gap-2xsmall))
Colours at an opacity
A colour token at an opacity token. A token can't hold both, so color-mix() puts them together where they're used.
- Carousel
background.backgroundcolor-mix(in srgb, var(--non-interactive-background-tertiary) calc(var(--opacity-medium) * 100%), transparent) - Navigation
background.backgroundcolor-mix(in srgb, var(--non-interactive-background-primary) 48%, transparent) - Thumbs
shadow.backgroundlinear-gradient(to bottom, rgba(6,8,5,0), var(--non-interactive-background-primary)) - Thumbs
content.backgroundcolor-mix(in srgb, var(--base-black) calc(var(--opacity-medium) * 100%), transparent)
Icon files
An icon is its SVG file, drawn as a mask so it takes the text colour. The file is the value.
- IconButtonToggle
glyph.maskurl(./icon-arrow-left.svg) center / contain no-repeat - InputProjectsThumbs
icons-lock.maskurl(./icon-lock.svg) center / contain no-repeat - Input
clear-glyph.maskurl(./icon-clear.svg) center / contain no-repeat - Input
icons-alarm.maskurl(./icon-alarm.svg) center / contain no-repeat - Projects
icons-arrow.maskurl(./icon-up-right.svg) center / contain no-repeat - Testimonials
icons-chevron.maskurl(./icon-chevron-down.svg) center / contain no-repeat and 1 more, one per state
Sizes with no token
Sizes and offsets that belong to one component, at a number no size token has.
- Input
supportive.topcalc(var(--spacing-size-large) + var(--spacing-gap-2xsmall))Composed from tokens: the field's height plus spacing/gap/2xsmall. - ListItem
root.width100%As wide as its list. Figma's sample is 208px. - ListItem
background.inset4pxFigma's own 4px inset of the plate. - ListItem
dot.width8pxThe small Badge's own 8px dot. - ListItem
dot.height8pxThe small Badge's own 8px dot. - Navigation
root.height100%As tall as the space it's given. Figma's sample is 408px. - Navigation
main.width100%Fills the panel inside its padding. - Navigation
action.width100%Fills the panel inside its padding. - Navigation
root.width160pxFigma's own 160px; no size token is 160. - ProjectsThumbs
dot.width3pxThe dot's own size inside the icon. - ProjectsThumbs
dot.height3pxThe dot's own size inside the icon. - Tooltip
root.height20pxFigma's own 20px; no size token is 20.
Tuned by eye
The paper effect's numbers, tuned for how the dots move. Only the paper uses them, and there are no motion tokens yet.
- Paper effect
dot.radius1pxTuned to the 16px grid. Nothing else would use it. - Paper effect
lens.radius210pxTuned by eye for how the lens moves. Only the paper uses it. - Paper effect
lens.push9pxTuned by eye for how the lens moves. Only the paper uses it. - Paper effect
lens.cursorradius 210px, power 1.0Tuned by eye: how wide the lens is, and how fast it fades. Only the paper uses it. - Paper effect
lens.haloradius 240px, power 1.3Tuned by eye: how wide the lens is, and how fast it fades. Only the paper uses it. - Paper effect
lens.pressradius 330px, power 1.7Tuned by eye: how wide the lens is, and how fast it fades. Only the paper uses it. - Paper effect
pen.cadence2s between sketches, each one 3.2s from first line to goneHow often the pen draws. There are no motion tokens yet.
Open gaps
- Button
focus-ring.border-style=solid - Carousel
focus-ring.border-style=solid - Chip
focus-ring.border-style=solid - IconButton
glyph.background=currentColor - IconButton
focus-ring.border-style=solid - Input
outline.border-style=solid - Input
clear-glyph.background=currentColor - Input
focus-ring.border-style=solid - ListItem
focus-ring.border-style=solid - Menu
focus-ring.border-style=solid - Projects
outline.left=0 - Projects
outline.right=0 - Projects
outline.bottom=0 - Projects
focus-ring.border-style=solid - TabItem
focus-ring.border-style=solid - Tag
focus-ring.border-style=solid - Testimonials
outline.left=0 - Testimonials
outline.right=0 - Testimonials
outline.bottom=0 - Testimonials
focus-ring.border-style=solid - Thumbs
shadow.left=0 - Thumbs
shadow.right=0 - Thumbs
shadow.bottom=0 - Thumbs
shadow.height=50% - Thumbs
focus-ring.border-style=solid - Toggle
glyph.background=currentColor - Toggle
focus-ring.border-style=solid - Toggle
root.width=auto
Figma variables
The Figma file has 661 variables (registry/figma-variables.json, read on 2026-10-26) and tokens/tokens.css has 661 of them. npm run tokens builds it from that read, so they can't come apart.