Tokens and workflow
One JSON file defines every value in the system; two mirrors serve CSS and Tailwind. This page covers how the pipeline works, how names are built, how versions move, and how a change becomes part of the system.
One source of truth
tokens/tokens.json is canonical. tokens.css and tailwind.preset.js are mappings of the same values, maintained by hand until the token build lands.
meta.version 0.14.0
var(--inline-ink-900)
text-ink-900
Mirror tokens.css and tailwind.preset.js in the same commit, and never let the three files disagree. When any surface contradicts tokens.json, the JSON is right and the surface carries the bug.
Planned automation
- Generation. A token build (Style Dictionary or similar) will emit both outputs from tokens.json; treat them as build artifacts and never give an output a value the JSON cannot express.
- Linting. stylelint will ban raw hex and raw z-index in product code; the tokens are the only source, so write as if the rule were already on.
Naming
Names read from group to role to step. This is the namespace as it exists in tokens.json today; the copy button gives you the plain text.
meta name, version (semver), baseUnit 4
color.{family}.{step} primitives: brand and ink at 50..950,
success, warn, danger, info at 100 200 600 800
color.{singleton} paper, surface, line, line-soft, border-strong
color.feedback.{dimension} argument evidence reasoning clarity strength
color.brainstorm.{purpose} understand explore focus gather connect challenge next-step
color.alpha.{name} translucent ink, brand, and paper mixes
color.chart.{role} series-1..4, emphasis, neutral, grid, axis-text
color.semantic.{group}.{role} aliases: text, background, border, action,
focus, selection, feedback, brainstorm
font.family / font.weight sans, mono, logo, serif · 400 500 600 750
size.{role} type ladder, display-xl down to code
space.{step} 0 0_5 1 1_5 2 3 4 5 6 7 8 10 12 16 20 24 32 40
space.semantic.{intent} inline, stack, inset, page-gutter, section, workspace-gap
control.height.{sm|md|lg} 32 40 44 · plus target-min, selection-visual, switch
icon.size.{xs..lg} 12 16 20 24 · weight regular
avatar.size.{xs..xl} 16 24 32 40 64
chip.height / toolbar.height 24 32 · 48 64
border.width none, hairline, emphasis
radius.{step} none xs sm md lg full
shadow.{tier} none raised overlay dialog
z.{layer} base raised sticky overlay toast backdrop dialog
motion.duration.{xs..xl} 80 160 240 480 720ms
motion.ease out, in-out, standard, linear
motion.recipe hover, enter, exit, overlay, page, stagger, sticky-raise
workspace draft workbench geometry: 2:1 split, rails, min height
breakpoint.{sm..2xl} 640 768 1024 1280 1536
container max 1200, reading 680, gutters
How a path maps to each output
CSS custom properties carry the --inline- prefix; Tailwind keys drop it.
| tokens.json path | tokens.css | tailwind.preset.js |
|---|---|---|
color.ink.900 | --inline-ink-900 | ink-900, as in text-ink-900 |
color.semantic.text.secondary | --inline-text-secondary | tokens.css only today |
space.semantic.stack.lg | --inline-space-stack-lg | stack-lg, as in gap-stack-lg |
radius.md | --inline-radius-md | rounded-md |
z.toast | --inline-z-toast | z-toast |
motion.duration.md | --inline-dur-md | duration-md |
The mappings compress a few group names: color.semantic.background.* becomes --inline-bg-*, motion.duration becomes --inline-dur-*, color.alpha.ink-32 becomes --inline-ink-a32, and color.chart.series-1 becomes --inline-chart-1. The pattern is predictable; when in doubt, read the mirror file rather than guessing. Two current asymmetries, closed by the planned generator: the Tailwind preset carries primitives and semantic spacing but not the semantic color roles, and motion recipes are documentation strings that exist only in the JSON.
Components consume text-primary, bg-surface, border-default, and their peers. Primitives such as ink-600 exist to define those roles, not to appear in product code.
Versioning
meta.version in tokens.json is the system version: semver, currently 0.14.0. The commit history is the changelog; a commit that changes tokens says what and why in its body.
| Change | Bump | Example |
|---|---|---|
| Addition: new token, step, or group | Minor · 0.13.1 to 0.14.0 | avatar.size gains 2xl |
| Value correction, same meaning | Patch · 0.13.1 to 0.13.2 | warn.600 shifts for contrast |
| Rename or removal | Major · 0.13.1 to 1.0.0 | space.7 leaves the scale |
A rename or removal keeps the old name as a deprecated alias for one minor version, so consumers migrate on their own schedule rather than at the moment of the commit. There is no separate changelog file to drift out of date.
Contributing
A section or component enters the system through the same loop, whether a human or an agent builds it.
| Step | Do | What it means |
|---|---|---|
| 1 | Check the decision log | platform/decisions.md is append-only memory; do not reopen settled questions, and start a reversal with a new entry. |
| 2 | Build to the contract | docs/authoring.md fixes the page skeleton, voice, shared building blocks, and page-scoped CSS rules. |
| 3 | Verify every value | Each number and hex must match tokens.json and the shipped product; where they disagree, stop and flag it. |
| 4 | Review against the checks | The checks list closes the contract: both widths, token match, table captions, nothing hidden behind script. |
| 5 | Commit | One section per commit; the message says what and why. |
In its own words: "How to write and build one page of the Inline design system so it reads and renders like every other page. This contract applies to humans and agents." Build the markdown source first; the page presents the same facts.
Decisions
Standing decisions live in platform/decisions.md: newest first, one dated paragraph each, append-only. The five most recent:
- 2026-07-27Chart series are four hues on one band. Indigo, ochre, teal, rust at L 0.46 and 0.56, C 0.10 to 0.12; hue identifies, a two-step stagger carries color-blind separation.
- 2026-07-26Question cards share the manuscript plane. Square corners on the margin card; detached surfaces keep 8 and 12px.
- 2026-07-26Icons are Phosphor Regular. Drawn at 16px, filled outlines; icon.weight replaces icon.stroke.
- 2026-07-26Selects are custom. An input-shaped trigger opening the menu overlay listbox supersedes native-first.
- 2026-07-26Plan limits are configuration. Specs carry behavior contracts; specimen numbers are examples.
The full log, including the scrim, toast, chart, mark, and docs-site decisions, is platform/decisions.md. A reversal is a new dated entry that names the one it replaces; entries are never rewritten.
Rules
Six rules keep the pipeline honest. Everything else on this page is commentary on them.
- The JSON decides. When any file or page disagrees with tokens.json, the JSON is right and the other surface carries the bug.
- Mirror in the same commit. A token change lands in tokens.json, tokens.css, and tailwind.preset.js together; the three files never disagree.
- Semantic roles over primitives. Product code consumes text-primary, bg-surface, and their peers; raw steps like ink-600 define roles rather than appear in components.
- Version every change. meta.version moves by semver, the commit body says what and why, and renames keep a deprecated alias for one minor.
- Check the log before you build. The decision log is append-only; a reversal is a new dated entry, never an edit.
- No raw hex, no raw z-index. The planned stylelint rule bans both in product code; write as if it were already on, because the tokens are the only source.