Platform

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.

JSON tokens/tokens.json Canonical source: values, semantic aliases, and the system version meta.version 0.14.0
mirrored by hand · same commit, always
CSS tokens/tokens.css Custom properties with the --inline- prefix var(--inline-ink-900)
JS tokens/tailwind.preset.js Tailwind preset; keys drop the prefix text-ink-900
Change the JSON first.

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.

How token paths map to CSS custom properties and Tailwind keys
tokens.json pathtokens.csstailwind.preset.js
color.ink.900--inline-ink-900ink-900, as in text-ink-900
color.semantic.text.secondary--inline-text-secondarytokens.css only today
space.semantic.stack.lg--inline-space-stack-lgstack-lg, as in gap-stack-lg
radius.md--inline-radius-mdrounded-md
z.toast--inline-z-toastz-toast
motion.duration.md--inline-dur-mdduration-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.

Semantic roles over primitives in product code, always.

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.

Semver rules for token changes
ChangeBumpExample
Addition: new token, step, or groupMinor · 0.13.1 to 0.14.0avatar.size gains 2xl
Value correction, same meaningPatch · 0.13.1 to 0.13.2warn.600 shifts for contrast
Rename or removalMajor · 0.13.1 to 1.0.0space.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.

The contributing loop, in order
StepDoWhat it means
1Check the decision logplatform/decisions.md is append-only memory; do not reopen settled questions, and start a reversal with a new entry.
2Build to the contractdocs/authoring.md fixes the page skeleton, voice, shared building blocks, and page-scoped CSS rules.
3Verify every valueEach number and hex must match tokens.json and the shipped product; where they disagree, stop and flag it.
4Review against the checksThe checks list closes the contract: both widths, token match, table captions, nothing hidden behind script.
5CommitOne section per commit; the message says what and why.
docs/authoring.md is the contract.

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.

  1. The JSON decides. When any file or page disagrees with tokens.json, the JSON is right and the other surface carries the bug.
  2. Mirror in the same commit. A token change lands in tokens.json, tokens.css, and tailwind.preset.js together; the three files never disagree.
  3. 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.
  4. Version every change. meta.version moves by semver, the commit body says what and why, and renames keep a deprecated alias for one minor.
  5. Check the log before you build. The decision log is append-only; a reversal is a new dated entry, never an edit.
  6. 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.