Repository navigation
Design Tokens
This page explains what fiscalclock's design tokens are, how the files in design/tokens/ are organised and named, how to build and check them, how a website will use them, and lists every spacing, radius, border, breakpoint, layout and motion value.
Last reviewed: 1 Nov 2026
A design token is a named design value, such as color.text.default or space.4, stored as data instead of being typed into each page. fiscalclock keeps every colour, size, spacing and timing value in a few JSON files, and a script turns them into CSS and checks them. The website, diagrams, social cards and these wiki pages then all use the same numbers, and a change made once reaches everything. The token files are the single source of truth: if a value appears anywhere else, it was copied from them (design/tokens/README.md).
| Term | Meaning |
|---|---|
| token | A name plus a value plus a type, for example space.4 = 16 px, of type dimension. |
| alias | A token whose value is another token, written in curly braces: {palette.teal.700}. |
| primitive | A raw value with no meaning attached, such as a palette colour. |
| semantic token | A token named for its job, such as color.bg.default, which aliases a primitive. Each theme points it at a different primitive. |
| composite token | A token whose value bundles several parts; fiscalclock's composite tokens are text styles. |
| CSS custom property | A variable in CSS, written --name and read with var(--name). The build writes one per token. |
| theme | The light or dark set of semantic colours (Colour-System). |
| DTCG | The W3C Design Tokens Community Group, which publishes the file format. |
More terms are on the Design-Glossary.
| Tier | What it holds | Where | Changes with theme? | Use it in pages? |
|---|---|---|---|---|
| Primitive |
palette.* colours, font.*, space.*, radius.*, border-width.*, breakpoint.*, layout.*, duration.*, easing.*
|
primitives.tokens.json |
No | Yes for sizes, spacing and motion; never for palette.*, which would bypass the theme switch |
| Semantic |
color.*: backgrounds, text, borders, accent, focus, status, code, diagram and logo roles |
semantic.light.tokens.json, semantic.dark.tokens.json
|
Yes: same names, different values | Yes, for every colour |
| Composite typography |
type.*: body, small, display, heading-1, heading-2, heading-3, code
|
primitives.tokens.json |
No | Yes, for every text style |
Component tokens, such as a colour reserved for one button, do not exist. If a later phase needs them, they would alias semantic tokens, never primitives (token research, section 6.1).
| File | What it holds |
|---|---|
primitives.tokens.json |
The palette, font families, type scale, weights, line heights, spacing, radii, border widths, breakpoints, layout widths, durations, easing and the composite type.* styles. The same in both themes. |
semantic.light.tokens.json |
Role-based colours for the light theme. Each is an alias of a palette colour and has a $description. |
semantic.dark.tokens.json |
The same roles, with the same names, for the dark theme. |
fiscalclock.resolver.json |
The resolver document: which files to load, in which order, for each theme. |
contrast-checks.json |
The colour pairs checked against WCAG 2.2 in both themes on every build. |
generated/ |
Generated files. Never edit them by hand. |
The files follow the DTCG Design Tokens Format Module 2025.10, with its Color and Resolver modules. It was published on 28 Oct 2025 as a "Final Community Group Report"; it is a stable community specification, not a W3C Standard (token research, section 1.1; format module).
A colour primitive, from primitives.tokens.json. The $type is set once on the palette group and inherited. A colour is an object: its colour space, its three components from 0 to 1, and a hex fallback; the build checks that hex matches the components.
{
"palette": {
"$type": "color",
"teal": {
"700": {
"$value": {
"colorSpace": "srgb",
"components": [0.0431, 0.4196, 0.4118],
"hex": "#0b6b69"
}
}
}
}
}A semantic alias, from semantic.light.tokens.json:
{
"color": {
"$type": "color",
"accent": {
"default": {
"$value": "{palette.teal.700}",
"$description": "The one accent: links, the current item, the open end of an interval."
}
}
}
}A composite text style, from primitives.tokens.json:
{
"type": {
"$type": "typography",
"body": {
"$value": {
"fontFamily": "{font.family.sans}",
"fontSize": "{font.size.md}",
"fontWeight": "{font.weight.regular}",
"letterSpacing": { "value": 0, "unit": "px" },
"lineHeight": "{font.line-height.body}"
}
}
}
}The JSON above is reformatted onto fewer lines; the values are copied from the files.
A resolver document says how to assemble the token files for each variant of the design. fiscalclock's loads the primitives first, then one theme modifier whose light and dark contexts each add one semantic file. Light is the default. From fiscalclock.resolver.json:
"modifiers": {
"theme": {
"contexts": {
"light": [{ "$ref": "semantic.light.tokens.json" }],
"dark": [{ "$ref": "semantic.dark.tokens.json" }]
},
"default": "light"
}
},
"resolutionOrder": [
{ "$ref": "#/sets/primitives" },
{ "$ref": "#/modifiers/theme" }
]The files keep strictly to the 2025.10 format so that an independent tool, Terrazzo, can read them unchanged as a cross-check (DD-016). No Terrazzo check is set up yet.
| Rule | Example | Source |
|---|---|---|
| Each part of a name is lowercase ASCII letters and digits, with single hyphens between words. The build rejects anything else. |
color.bg.accent-subtle, font.line-height.body
|
NAME pattern in build_tokens.py
|
| Name semantic tokens by role, not by colour. |
color.status.danger, not color.red
|
token research, section 6.1 |
Use a default leaf for the main member of a group. |
color.accent.default and color.accent.hover
|
token research, section 6.2 |
| Aliases use curly braces and point at a whole token. | "{palette.neutral.900}" |
token research, section 6.2 |
Colours use colorSpace: "srgb" and always include hex. |
see the excerpt above | token research, section 6.2 |
Every semantic token has a $description saying where it is used. |
"Page background." |
token research, section 6.2 |
| Both themes define exactly the same semantic names. The build fails otherwise. | design/tokens/README.md |
The CSS name is --fc- followed by the token name with dots replaced by hyphens:
| Token | CSS custom property |
|---|---|
color.text.default |
--fc-color-text-default |
space.4 |
--fc-space-4 |
font.line-height.body |
--fc-font-line-height-body |
type.body (composite) |
five properties: --fc-type-body-font-family, --fc-type-body-font-size, --fc-type-body-font-weight, --fc-type-body-letter-spacing, --fc-type-body-line-height
|
The prefix stops fiscalclock's variables from colliding with a framework's own, such as Tailwind's colour variables (DD-017).
Run from the repository root. The script uses only the Python standard library (DD-016).
| Command | What it does |
|---|---|
python -I design/scripts/build_tokens.py |
Regenerates everything in design/tokens/generated/. |
python -I design/scripts/build_tokens.py --check |
Builds in memory and fails if the committed files in generated/ are out of date. Prints "design tokens are up to date" on success. |
python -I design/scripts/build_tokens.py --self-test |
Feeds the builder five broken inputs and checks that each is rejected: a circular alias, an alias to a missing token, an alias of the wrong type, themes with different token names, and a hex that does not match its components. |
python -I design/scripts/check_brand.py --wiki <path to a wiki clone> |
Fails if a logo SVG, a design document or a wiki page uses a hex colour that is not in the palette, or a --fc- name that is not a token. |
python -I design/scripts/contrast.py --self-test |
Checks the contrast formula against nine published reference values. |
On every build the script also rejects any part of the format the files do not use, resolves every alias, and fails if any pair in contrast-checks.json falls below its minimum (design/tokens/README.md).
As of 1 Nov 2026 these commands are run by hand: no CI workflow in .github/workflows/ calls them yet. Running --check in CI, as the repository already does for other generated files, is Proposed (token research, section 6.4).
| File | Use |
|---|---|
generated/tokens.css |
CSS custom properties: primitives once on :root, light colours on :root, dark colours under prefers-color-scheme: dark and again under [data-theme="dark"] (DD-018). Semantic colours are written as var() references to primitives, so aliases stay visible. |
generated/tokens.light.json, generated/tokens.dark.json
|
Every token resolved to a plain CSS value, keyed by its CSS name, for tools that take values in configuration rather than CSS. The brand-asset script reads its colours from here (DD-023). |
generated/contrast.md |
The contrast report: every checked pair's ratio in both themes. Colour-System shows a copy. |
No website stack has been chosen (DD-009), so the tokens assume none. The plan, summarised from design/tokens/README.md:
-
Load
tokens.cssfirst, before any framework style sheet. It defines variables only and styles nothing. -
Map the framework's variables onto the tokens in one small style sheet, for example
--vp-c-bg: var(--fc-color-bg-default);for VitePress. The token research, section 5 lists the variables and dark-mode selector of twelve docs frameworks. -
Set the theme on
<html>. With no attribute the page follows the operating system;data-theme="light"or"dark"overrides it. Set it before the first paint and add<meta name="color-scheme" content="light dark">. -
For frameworks configured with values instead of CSS (Mintlify, Nextra, Furo), read
tokens.light.jsonandtokens.dark.jsonat build time instead of copying hex values by hand. -
Copy breakpoints into media queries. CSS cannot read a custom property inside a media query, so the
breakpoint.*values must be written into the site's media queries and kept in step.
@import "tokens.css";
body {
background: var(--fc-color-bg-default);
color: var(--fc-color-text-default);
font-family: var(--fc-type-body-font-family);
font-size: var(--fc-type-body-font-size);
line-height: var(--fc-type-body-line-height);
}- Edit the token file, then run
python -I design/scripts/build_tokens.py. - If the change touches a colour, the build reruns every contrast check. Fix a failure by changing the colour, never by removing the check.
- Run
python -I design/scripts/build_tokens.py --checkandpython -I design/scripts/check_brand.py --wiki <path to a wiki clone>. - Record the change and its reason in
design/DECISIONS.md, and update the wiki pages that show the value (Colour-System, Typography, Layout-and-Spacing and this page). - If it is a brand colour, regenerate the logo and card exports in
assets/brand/and update the Canva designs listed on Asset-Inventory. - Commit the token files and the regenerated
generated/files together.
Every value below is copied from generated/tokens.css. Colour tokens are listed on Colour-System and type tokens on Typography. How to use the spacing and layout values is on Layout-and-Spacing.
| CSS custom property | Token | Value |
|---|---|---|
--fc-space-0 |
space.0 |
0 |
--fc-space-1 |
space.1 |
4px |
--fc-space-2 |
space.2 |
8px |
--fc-space-3 |
space.3 |
12px |
--fc-space-4 |
space.4 |
16px |
--fc-space-5 |
space.5 |
24px |
--fc-space-6 |
space.6 |
32px |
--fc-space-7 |
space.7 |
48px |
--fc-space-8 |
space.8 |
64px |
--fc-space-9 |
space.9 |
96px |
| CSS custom property | Token | Value |
|---|---|---|
--fc-radius-none |
radius.none |
0 |
--fc-radius-sm |
radius.sm |
3px |
--fc-radius-md |
radius.md |
6px |
--fc-radius-lg |
radius.lg |
8px |
--fc-radius-xl |
radius.xl |
12px |
--fc-radius-full |
radius.full |
9999px |
| CSS custom property | Token | Value |
|---|---|---|
--fc-border-width-thin |
border-width.thin |
1px |
--fc-border-width-thick |
border-width.thick |
2px |
A breakpoint is a minimum screen width at which the layout changes.
| CSS custom property | Token | Value |
|---|---|---|
--fc-breakpoint-sm |
breakpoint.sm |
640px |
--fc-breakpoint-md |
breakpoint.md |
768px |
--fc-breakpoint-lg |
breakpoint.lg |
1024px |
--fc-breakpoint-xl |
breakpoint.xl |
1280px |
| CSS custom property | Token | Value |
|---|---|---|
--fc-layout-prose |
layout.prose |
720px |
--fc-layout-sidebar |
layout.sidebar |
264px |
--fc-layout-toc |
layout.toc |
224px |
--fc-layout-page |
layout.page |
1440px |
--fc-layout-header |
layout.header |
56px |
--fc-layout-gutter-sm |
layout.gutter-sm |
16px |
--fc-layout-gutter-lg |
layout.gutter-lg |
32px |
| CSS custom property | Token | Value |
|---|---|---|
--fc-duration-fast |
duration.fast |
120ms |
--fc-duration-base |
duration.base |
200ms |
An easing curve sets how an animation speeds up and slows down.
| CSS custom property | Token | Value |
|---|---|---|
--fc-easing-standard |
easing.standard |
cubic-bezier(0.2, 0, 0, 1) |
Where durations and easing are used is not decided yet. Any motion must stop when the reader asks for reduced motion (Accessibility).
- Design-System, Colour-System, Typography, Layout-and-Spacing, Accessibility, Asset-Inventory, Design-Glossary, Design-Decisions
- Token folder and its guide:
design/tokens/,design/tokens/README.md - Scripts:
design/scripts/build_tokens.py,design/scripts/check_brand.py,design/scripts/contrast.py - Research:
design/research/design-tokens.md - Decision log:
design/DECISIONS.md(DD-009, DD-016, DD-017, DD-018, DD-023) - Specification: DTCG Format 2025.10, Color 2025.10, Resolver 2025.10
fiscalclock is licensed under MIT OR Apache-2.0 (MIT, Apache-2.0). Last reviewed: 31 Oct 2026. Found an error on this page? Report it with the documentation form.