# Design tokens Source: [Design tokens](https://typeroll.com/docs/guides/design-tokens/) > Set colours, fonts and scales once, reuse them in blocks, and audit deliberate exceptions. **Availability:** prepared for Core 0.2.106, template capabilities 0.54.0 and MCP 0.45.80. These features are not in Core 0.2.104. Check your connected portal and rebuild a static site after upgrading; older published files do not change when the portal is upgraded. ## Start with site settings Open **Site settings → Colors** to set the palette. In **Typography**, choose font families and expand **Named typography and spacing scales** to adjust the steps. Use **Styles** to apply these steps to body text, heading roles and reusable component styles. An AI agent can do the same through `update_site_settings` and the style tools. | Role | Use | | ----------------------------------------- | ------------------------------------------------------------------------- | | `primary` | Main brand colour, links and primary actions | | `secondary` | Supporting brand surfaces | | `accent` | Occasional emphasis | | `background` | Page canvas | | `surface` | Cards and panels | | `surface_hover` | Interactive surface; a darker derived shade unless overridden | | `text` | Body copy | | `text_light` | Muted copy, still with readable contrast | | `on_primary`, `on_secondary`, `on_accent` | Text on the corresponding brand colour; automatic contrast-aware defaults | A starting light palette is primary `#2563eb`, secondary `#1e293b`, accent `#f59e0b`, background `#ffffff`, surface `#f8fafc`, text `#0f172a`, and text\_light `#64748b`. These values belong in **settings**, not copied into blocks. Choose the role by meaning, not by which colour happens to look identical today. The block editor shows palette choices first. **Custom colour (exception)** is an explicit choice; it does not track palette changes. Record exceptions in your starter workspace’s `decisions.md`, for example white text on a photograph. Use a named style for a new component role, or a site CSS variable derived from existing palette variables for a new shade. Avoid inventing unsupported bare palette names. A derived shade can use `color-mix(in srgb, var(--color-surface) 92%, var(--color-primary))`. ## Typography and spacing | Scale | Steps | | ----------- | --------------------------------------------- | | `type_size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl` | | `space` | `none`, `xs`, `sm`, `md`, `lg`, `xl` | | `leading` | `tight`, `snug`, `normal`, `relaxed`, `loose` | Presentation fields keep their existing API names for compatibility. For example: ```json { "type": "core/prose", "data": { "html": "
Editable text
", "font_size_px": { "mobile": "md", "desktop": "lg" }, "line_height": "relaxed", "font": "body" } } ``` `gap_px: "lg"` uses the spacing scale. Numbers remain explicit overrides; counts, breakpoints and image dimensions are not automatically scale values. Read the block schema’s `design_token` metadata before using steps in a custom field. Font choices are `heading`, `body`, `mono` or inherited; family names belong only in `settings.fonts`. Configure the numeric scale once in `settings.design_scales`, then use step names in role styles and block fields. Palette names remain names in storage and become CSS variables at rendering. Unknown colour values produce `field_type_mismatch` warnings with field paths. ## Audit and migrate an existing design Run `lint_design_tokens` for saved content in the selected Version. It checks Pages, partials, page templates, custom block types, styles and custom CSS and returns source paths, counts and suggested tokens. The migration launch report includes the same **non-blocking** findings. Unsaved drafts are not included. CSS checking is heuristic: it cannot prove that dynamically constructed CSS or third-party styles follow the palette. Suggestions require visual review. `css_findings` lists custom CSS that works against the theme, each with the platform feature that does the same job: | Code | Finding | Use instead | | ------------------------------------ | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `css_important_overuse` | 10 or more `!important` declarations in one stylesheet | Site settings, named Styles and block settings | | `css_font_not_in_theme` | A font family that is not the heading, body or mono font | Set it as a theme font and use the font role | | `css_duplicate_font_load` | A theme font loaded again by `@font-face`, `@import` or a font link in `scripts_head` | Remove it; the theme loads its fonts once | | `css_first_section_background_image` | The first section’s background image comes from custom CSS, so it loads late | The section’s background image setting or an image or cover block | | `css_block_class_override` | Rules on platform classes such as `.block-*`, `[data-block]` or `.site-header` | A named Style, the block’s settings, or the header and footer partials | `read_site_readiness` summarizes the same findings in its `custom_css_overrides` and `duplicate_fonts` items. The [site starter](https://github.com/Typeroll/site-starter) contains `scripts/typeroll/color_tokens.py`. Run a dry run first: ```sh python3 scripts/typeroll/color_tokens.py --plan /tmp/design-token-plan.json ``` Review the plan and remove deliberate exceptions. Exact, unambiguous hex matches in direct block fields can be applied in a dedicated non-main Version: ```sh python3 scripts/typeroll/color_tokens.py --apply /tmp/design-token-plan.json ``` Stop other editing in that Version during this operation. It checks scope, palette and current values, refuses existing unsaved drafts, and does not retry uncertain writes or publish. Templates save immediately; Pages and partials are saved through their normal working-copy flow. If interrupted, inspect the drafts before continuing. There is no site-wide transaction. Ambiguous roles, nested/responsive colour values and custom CSS need manual review. Equal hex values do not establish that two elements should share a role. After migration, change primary and surface in a test Version and inspect header, footer, cards, menus and buttons at mobile, tablet and desktop widths without editing their blocks. Restore the test palette. Report dry-run counts separately from applied changes, then publish only after the normal approval and checks. ## Fluid typography and component rhythm Core 0.2.114 / MCP 0.45.85 / capabilities 0.55.0 adds responsive scales. Check the connected versions before using this contract. New sites use render version 10 in that release. For an existing site, test a Version first; upgrading rendering and replacing existing roles are separate, deliberate choices. Use `fonts.size_base` (default 16), `typography.ratio_mobile` (1.2), `typography.ratio_desktop` (1.25), `typography.rhythm` (1), and `typography.line_length` (65 ch). Set the controls once, then use named type, spacing and line-height steps. `apply_standard_styles` uses those steps; `overwrite: true` resets existing roles, so review their current values first. Explicit sizes and breakpoint overrides still win and are not silently migrated. Heading role margins belong to editorial flow. Component titles use their own padding/gap, and opening headings in containers/sections add no top margin. Use role-linked `core/heading` size `auto` or `theme`; explicit hero sizes remain deliberate exceptions. Do not compensate with per-card negative margins. Compare 375, 768 and 1280px in Site settings → Design and in a full site preview. After a rendering upgrade/rebuild, recheck cards, boxed headings, leading text and webfonts. Boxes should get their outer air from padding. Keep exceptions in decisions.md, and run lint\_design\_tokens before launch. ### Contextual spacing (planned: Core 0.2.115, render version 11) This version is not yet released. It restores heading rhythm inside columns and grids, including the gap after an image. The first heading in a container still has no extra top margin. Article spacing overrides apply once, and named heading styles remain authoritative. A site without saved heading roles also gets proportional spacing. An explicit named style with `space_before: "0"` still means zero. If a site used that as a workaround for opening headings, check whether the same style was also assigned to headings later in articles. Preview removing the workaround from those uses; the new opening-heading rule handles the first heading without removing spacing from later headings. Do not overwrite all saved roles. Navigation links keep their default 44px touch targets; they no longer add a second vertical gap between those targets. Explicit `gap_px` and compact settings remain available. When reviewing a footer, compare the heading-to-link gap with the gaps inside the link group, not only the overall footer height. A reserved video area is not a heading margin. Review embeds with the actual player visible and after consent choices; do not hide iframes in screenshots used to approve a layout. Test unavailable or blocked embeds separately. ### Responsive step overrides ```json { "typography": { "ratio_mobile": 1.2, "ratio_desktop": 1.25, "rhythm": 1, "line_length": 65 }, "design_scales": { "type_size": { "3xl": "clamp(2rem, 1rem + 3vw, 3.5rem)" }, "space": { "xl": { "mobile": "2rem", "tablet": "3rem", "desktop": "4rem" } } } } ``` Supported map keys are mobile, tablet, laptop, desktop and wide, using the site’s breakpoint widths. Missing lower map entries keep the platform default; subsequent widths inherit the latest override. A step accepts nonnegative px/rem/em lengths or `clamp(min, length + vw, max)` (minus is also supported). Line-height steps accept unitless values from 1 to 2, including maps. Unknown keys and unsafe CSS are refused. `design_scales` and `typography` each replace their complete settings object: read, modify, then write to preserve other overrides. Fluid default endpoints are 360px and 1280px. rem bounds respect root font size, including browser text-size preferences. Prose defaults to the configured line length; explicit block widths remain authoritative. The preview uses saved role styles with unsaved controls and disables font downloads for isolation. Always check the full site with its actual webfonts before publishing. ## Check it Run `lint_design_tokens`. Its findings, including `css_findings` for custom CSS that works against the theme, should be fixed or recorded as deliberate exceptions. The [launch readiness report](https://typeroll.com/docs/guides/launch-checklist/#custom-css-overrides) shows the same CSS findings for the whole site.