Purpose: Every design token SUI defines, what each one means, and which ones people expect to exist but don’t.
All tokens are declared on :root in sui.css. Always reference the variable, never
the hex. A colour written as #43CDB6 is a colour that will not follow a theme change
and will not read as semantic to the next person.
The complete machine-extracted list (72 tokens) is in generated/sui-inventory.md. This page groups them by what they are for.
| Token | Value | Use |
|---|---|---|
--accent-primary |
#43CDB6 |
Primary action, teal |
--accent-primary-active |
#C2EFDD |
Primary, pressed |
--accent-secondary |
#94A4E4 |
Secondary action, periwinkle |
--accent-secondary-active |
#BBCAEF |
Secondary, pressed |
--accent-destructive |
#EE7D69 |
Destructive action, red |
--accent-destructive-active |
#F4A990 |
Destructive, pressed |
--accent-disabled |
#7394A5 |
Inert control |
| Token | Value | Use |
|---|---|---|
--text-body |
#C5D7D9 |
Default reading colour |
--text-hint |
#A7C0C6 |
Secondary, de-emphasised |
--text-warning |
#F3C878 |
Amber |
--text-player-primary |
#43CDB6 |
Teal — “us” |
--text-player-highlight |
#86DFC6 |
Teal, emphasised |
--text-player-inverted |
#133546 |
On a teal fill |
--text-enemy-primary |
#EE7D69 |
Red — “them” |
--text-enemy-highlight |
#F4A990 |
Red, emphasised |
--text-enemy-inverted |
#2E1F3E |
On a red fill |
--text-neutral-primary |
#EBAA49 |
Gold — third parties |
| Token | Value | Use |
|---|---|---|
--page-background |
#1A2029 |
Page base (under the tiled background image) |
--surface-default |
#222034 |
Default component fill |
--surface-player-body |
#133546 |
Friendly panel body |
--surface-player-highlight |
#1C5F6A |
Friendly nav / emphasis |
--surface-player-inverted |
#43CDB6 |
Teal fill, e.g. card headers |
--surface-enemy-body |
#2E1F3E |
Hostile panel body |
--surface-enemy-highlight |
#5D0C15 |
Hostile emphasis |
--surface-enemy-inverted |
#E64D40 |
Red fill |
--surface-neutral-body |
#1E1C2E |
Third-party panel body |
--surface-panel |
#5D7E90 |
Panel chrome |
--surface-panel-medium |
#4C6475 |
Panel chrome, darker step |
| Token | Value | Use |
|---|---|---|
--border |
#5D7E90 |
Default |
--border-strong |
#A7C0C6 |
Emphasised |
--border-subtle |
#394958 |
De-emphasised |
--border-player |
#133546 |
Friendly |
--border-player-dark |
#2E1F3E |
Friendly, dark variant |
--border-enemy |
#440D3A |
Hostile |
--border-enemy-dark |
#222034 |
Hostile, dark variant |
--border-neutral-dark |
#000000 |
Third party, dark variant |
--border-focus-friendly-dark |
#2A9D9B |
Focus ring, friendly |
--border-focus-enemy-dark |
#C11F16 |
Focus ring, hostile |
The two
--border-focus-*tokens are the closest thing SUI has to a focus indicator, and nothing in the stylesheet applies them to:focus. If you add keyboard focus styling — and you should, see gotchas — use these rather than inventing a colour.
| Token | Value | Use |
|---|---|---|
--icon-colour-primary |
#43CDB6 |
Glyph icon, friendly |
--icon-colour-warning |
#F3C878 |
Glyph icon, caution |
--icon-colour-destructive |
#EE7D69 |
Glyph icon, hostile |
--icon-dark |
#394958 |
Glyph icon, inert |
--struct-health-bar-health |
#EFB719 |
Remaining HP |
--struct-health-bar-damage |
#CC2D2D |
Lost HP |
--struct-progress-bar-fill |
#C5D7D9 |
Progress fill |
--spacing-xs: 2px --spacing-sm: 4px --spacing-md: 8px --spacing-lg: 12px
--spacing-xl: 16px --spacing-xxl: 24px --spacing-xxxl: 32px
Most component gaps are 8–16px. There is no larger step; if a layout wants 48px of air, it is probably not a Structs layout.
--icon-xs: 8px --icon-sm: 16px --icon-md: 24px
--icon-lg: 32px --icon-xl: 48px --icon-xxl: 64px
--tile-width: 128px --tile-height: 128px
--form-input-height-total: 40px
--from-input-height-content: 36px /* [sic] */
Copy the typo.
--from-input-height-contentis misspelled in the source (from, notform). That is the real variable name, and.sui-screen-btnuses it for its height. Writing--form-input-height-contentsilently resolves to nothing.
| Token | Value |
|---|---|
--loading-screen-z-index |
10000 |
--popup-z-index |
2000 |
--notification-dialogue-z-index |
1500 |
--banner-z-index |
1250 |
--menu-page-z-index |
1000 |
--hud-z-index |
50 |
--picture-in-picture-z-index |
30 |
--map-z-index |
10 |
--menu-z-index |
10 |
--menu-page-fill-background-z-index |
-1 (relative to the menu page) |
Three families, six roles. Loaded via @font-face from fonts/sui/; Inter comes from
a CDN in the webapp’s base template.
| Class | Family | Size / line | Case | Use for |
|---|---|---|---|---|
.sui-text-display, h1 |
ExtremeHazard | 16 / 24 | UPPER | Page titles |
.sui-text-header, .sui-text-label, h2 |
ExtremeHazard | 8 / 16 | UPPER | Card headers, field labels, nav, buttons |
.sui-text-label-block |
ExtremeHazard | 8 / 16 | UPPER | Same, forced display: block |
.sui-text-paragraph |
DirectiveZero | 16 / 20 | normal | Body copy |
.sui-text-tiny |
DirectiveZero | 8 / 12 | normal | Fine print |
.sui-text-ticker |
Inter | 12 / 16 | normal | Tickers, timestamps |
Font weight is 500 for every one of these except .sui-text-ticker, which is 400.
That is the whole weight system — see rule 2 in the design language.
8px sounds unreadable. It isn’t, at scale(2). At 1× it is, which is what the
scaling decision is about.
.sui-text-primary, -secondary, -destructive, -disabled, -warning, -hint set
color and nothing else — no metrics. Combine them with a metric class.
sui-mod-*doubles as a global colour utility..sui-mod-primary,-secondary,-destructive,-disabledand-warningsetcolor:on any element, not just inside components.<span class="sui-mod-warning">is amber. This has consequences — see the inline alert trap.
There is no --accent-positive, --accent-negative, or --accent-warning. If you
see those in a codebase, someone invented them. Map intent to real tokens:
| Intent | Use |
|---|---|
| good / ours / success | --text-player-primary |
| bad / theirs / error | --text-enemy-primary or --accent-destructive |
| caution | --text-warning |
| inert / secondary | --text-hint or --accent-disabled |
SUI also defines font-variant-numeric nowhere. In a console full of changing
figures you want tabular-nums on every numeric cell, or columns will jitter on each
refresh. That is a sanctioned local addition, not a deviation — see
examples/sui-patch.css.
Verified against structs-webapp 6eec7f7 (2026-07-21), src/public/css/sui/sui.css.