A project's styling starts from its design system. Committing it generates design.css: the tokens as CSS variables, plus a few base rules. Every other piece of CSS (element, template, shell, headTags stylesheet) should be small and should read the tokens instead of repeating values. Then a change on the Design page restyles the whole site.
What design.css already gives you#
Every published page links /store/{sid}/css/design.css?v={hash} as its first stylesheet. It contains:
:roottokens (the full list is below).Base rules, so you don't repeat them:
*, *::before, *::after { box-sizing: border-box; } body { margin: 0; font-family: var(--font-body); font-size: var(--text-body); line-height: var(--leading-body); color: var(--color-text); background: var(--color-surface); } h1,h2,h3,h4 { font-family: var(--font-heading); margin: 0 0 var(--space-4); } a { color: var(--color-primary-strong); } mark { color: inherit; }(A project still on tokens v1 gets the same rules on the original names:
var(--text),var(--surface),var(--space-2).):root[data-theme="light"|"dark"]blocks. Only the console's design preview uses them. Published pages never setdata-theme, so they always render the design's default scheme.
A project with no committed design system (the Design page is empty) has no design.css. Then every var(--…) falls through to its fallback, or to nothing.
The tokens#
New projects are on tokens v2. A project created before it keeps tokens v1 until someone switches it on the Design page (Tokens v2 migration). The sheet tells you which: a v2 sheet has --space-unit.
Tokens v2#
| Group | Variables |
|---|---|
| Color ramps | --color-{role}-50 … -900 for all eight roles primary, secondary, neutral, accent, success, warning, error, info — the same in both schemes |
| Acting colors | --color-{role} (buttons, links, icons; per scheme), -hover, -on (ink on it), -container / -on-container, -soft / -strong (chips, callouts) |
| Surfaces and text | --color-surface, -surface-alt, -surface-card, -surface-inverse, --color-text, -text-muted, -text-on-inverse, -text-on-primary, --color-border, --color-scheme |
| Type scale | --text-xs, -sm, -base (fixed), --text-lg … -5xl (fluid clamp()); --font-heading, -body, -button; --font-weight-body, -heading, -bold; --leading-tight, -normal, -display, -ui; --tracking-normal, -tight, -display |
| Type roles | --text-{role}, --leading-{role}, --weight-{role}, --tracking-{role} for display-lg, display, headline, title, subtitle, body, label — references into the scale |
| Space | --space-unit (the brand's grid, 4 px by default) and --space-{0,1,2,3,4,5,6,8,10,12,16,20,24,32} = N × the unit; --section-space |
| Shape and depth | --radius-sm, -md, -lg, -xl, -full, -panel; --shadow-sm, -md, -lg; --border-width |
| Motion | --motion-duration, -duration-slow, --motion-easing, --ease-out-expo, -out-quart, --ease-spring, --reveal-duration, -duration-slow, -distance, -stagger, -stagger-group, -stagger-line, -trigger |
| Layout | --container-max, --grid-columns |
| Brand | --brand-logo, --brand-mark, --brand-wordmark as url() per scheme, when the Brand tab holds files |
| Custom | your own tokens from Properties › Custom tokens, grouped (slot for component slots) |
Write every geometric value as a multiple of the unit: padding: var(--space-6), never padding: 18px. Font sizes follow the type scale instead. Color text through the surface and text set, never a raw ramp stop, so it stays correct in both schemes. Pair ink with its background: --color-primary-on on --color-primary, --color-success-strong on --color-success-soft.
Tokens v1#
| Group | Variables |
|---|---|
| Color ramps | --color-{role}-50 … -900 for the roles the design defines |
| Color pairs | --color-{role}-on, -container / -on-container, -soft / -strong |
| Surfaces | --surface, --surface-card, --surface-muted, --text, --text-muted, --border-subtle |
| Type | --font-heading, --font-body; per role --text-{role}, --leading-{role} (px), --weight-{role}, --tracking-{role} |
| Space | --space-0 … --space-7, an index into unit × density (4, 8, 12, 16, 24, 32, 48, 64 px at unit 8, regular density) |
| Shape | --radius-sm, --radius-md, --radius-lg, --radius-pill, --elevation-0 … -3 |
| Layout | --container-max, --grid-columns, --density |
A migrated project keeps a few v1 names as aliases (--surface, --text-muted, --radius-pill, --elevation-* …) until nothing uses them. Don't write them in new CSS.
Custom tokens#
Brand values with no derived token (a gradient, a section's theme color, a component slot) become custom tokens on the Design page. A name is lowercase a-z0-9-. It must not shadow a generated variable. On tokens v2 the names space-unit, section-space, container-max, grid-columns, border-width and anything starting with color-, text-, leading-, tracking-, weight-, font-, space-, radius-, shadow-, motion-, ease-, reveal- or brand- are refused. On tokens v1 the list is surface, text, density, container-max, grid-columns and the prefixes color-, text-, leading-, weight-, tracking-, space-, radius-, elevation-, font-, surface-, border-. Name brand tokens by what they are: heading-ink, outline-tint, hero-gradient, theme-laser.
Where CSS goes, in cascade order#
Later stylesheets win at equal specificity:
design.css: the tokens and base rules.- Element-library asset stylesheets (kit CSS files).
- The shell (header and footer) CSS.
- Element and fragment CSS.
- The page template's CSS.
- The
headTagsfrom Website › Web. They come after all generated stylesheets, so a<link>there overrides template CSS. - The platform cookie bar, last.
The minimal site stylesheet#
Most sites need no global stylesheet at all: each template and element carries its own scoped CSS. When you do add one (a store file linked from headTags), keep it to what is truly site-wide:
/* site.css: additions on top of the design system, not a theme */
.site-wrap { max-width: var(--container-max); margin: 0 auto; padding: 0 var(--space-4); }
.site-btn {
background: var(--color-primary);
color: var(--color-primary-on);
border-radius: var(--radius-full);
padding: var(--space-3) var(--space-6);
font: var(--font-weight-bold) var(--text-sm)/var(--leading-ui) var(--font-button);
transition: background var(--motion-duration) var(--motion-easing);
}
.site-btn:hover { background: var(--color-primary-hover); }On a project still on tokens v1, the same button reads var(--color-primary-500), var(--radius-pill), var(--space-2) var(--space-4) and the label role, with var(--color-primary-600) on hover.
Rules:
- Read tokens, don't restate them. Write
background: var(--color-primary), not#ea560d. A literal never changes when the design does. - Don't style
htmlorbody.design.cssowns them. - Prefix your classes (
.site-…, or a page's own root class) and never use bare generic selectors (.container,.btn,h2). Template CSS follows the same rule: one unique root class per template, and every selector under it. - Mobile-first. Base styles for a phone, then
@media (min-width: …)steps up. - Fonts: add them in Design system › Properties › Typography › Fonts (uploaded files, a self-hosted or linked Google family, an Adobe Fonts kit or any font stylesheet) and name the family in the type settings, so
--font-heading/--font-bodycarry it. The platform writes the@font-facerules intodesign.cssand the<link>s intoheadTags— no@font-facein your own stylesheet.
Moving an existing stylesheet onto tokens#
A site imported from elsewhere often arrives as one big stylesheet in headTags. It renders, but design edits change nothing. To move it onto the tokens without changing how the site looks:
- Commit a design system derived from that stylesheet first: its colors as the color roles, its fonts, its radii. Values that have no derived token become custom tokens.
- Replace a literal only where it exactly equals a token's value, and keep the literal as the fallback:
#ea560d→var(--color-primary-500,#ea560d). - Never define a variable through a token of the same name (
.site { --x: var(--x, …) }). That is a cycle, and the variable becomes invalid. Delete the site's copy and let the token inherit. - Leave
font-familystacks alone unless they match the token's stack exactly. A different fallback list changes how any glyph missing from the web font renders. - Write the result as a new file, repoint the
headTagslink to it, and keep the old file. Pointing the link back is the rollback. - Compare pages before and after at desktop and phone widths. Then change a token and confirm the page follows it.
Font sizes, spacing and other values that are near a token but not equal to it stay literal. Moving them onto the scale changes the site visibly, so it is a design decision, not a migration step.