Use these tokens in all new code. Each token encodes a role, not a raw size.
| Token | Value | Swatch | Role |
|---|---|---|---|
--space-none | 0 | Explicit zero gap — use instead of a 0 literal wherever a gap or padding should be absent. | |
--space-tight | 0.5rem | Inside a single control (icon-to-label, badge padding) | |
--space-group | 0.75rem | Between closely related items (buttons in a row, inline fields) | |
--space-form-row | 1rem | Between form rows, list items, stacked labeled fields | |
--space-block | 1.25rem | Between distinct content blocks inside a section | |
--space-section | 2.5rem | Between major page sections |
These tokens exist for backward compatibility only. Do not use them in new code; migrate call sites to the semantic role tokens above when you touch them.
| Token | Value |
|---|---|
--space-1 | 0.25rem |
--space-2 | 0.5rem |
--space-3 | 0.75rem |
--space-4 | 1rem |
--space-5 | 1.25rem |
--space-6 | 1.75rem |
--space-7 | 2.5rem |
--space-8 | 3.5rem |
--space-9 | 5rem |
site-main-inner owns section-to-section spacing. It is a flex column with gap: var(--space-section) (2.5 rem), so every direct child is separated by the same section gap without any child needing to set a margin.
Nested containers such as rules-section and layout-stack own the spacing between their own children, using smaller tokens: --space-block (1.25 rem) for content blocks inside a section, or --space-form-row (1 rem) for stacked form rows.
Components should not set margin-top or margin-bottom on themselves. Let the parent gap provide the spacing. Doing otherwise produces compounding or unpredictable gaps.
site-main-inner ← gap: --space-section (2.5rem between children) ├─ h1 ← no margin; gap above it comes from site-main-inner ├─ rules-lead ← no margin; gap above it comes from site-main-inner └─ rules-section ← no margin; gap above it comes from site-main-inner ├─ h2 ← no margin; rules-section owns inner spacing ├─ p ← no margin; rules-section owns inner spacing └─ rule-callout ← no margin; rules-section owns inner spacingException: hr keeps margin: var(--space-7) 0. It is used as an in-flow visual divider inside prose-like containers (such as this design-system page), not as a container boundary, so symmetric margin is intentional.
Four CSS-only Light-DOM custom elements that compose the semantic spacing tokens. No JavaScript. No Shadow DOM. Styled via attribute selectors on unknown HTML tags.
Stacks children vertically in a flex column; use it wherever content flows top-to-bottom with consistent spacing between items.
| Attribute | Values | Default | Notes |
|---|---|---|---|
gap | none | tight | group | form-row | block | section | form-row | Maps to the corresponding --space-* token. |
gap="none"
gap="tight"
gap="group"
gap="form-row" (default)
gap="block"
gap="section"
Arranges children horizontally in a wrapping flex row with vertically centered alignment; use it for button groups, inline fields, and any items that belong side by side.
| Attribute | Values | Default | Notes |
|---|---|---|---|
gap | none | tight | group | form-row | block | section | group | Maps to the corresponding --space-* token. |
gap="none"
gap="tight"
gap="group" (default)
gap="form-row"
gap="block"
gap="section"
Wrap example — many items
Places children into a responsive auto-fit grid where each column is at least min wide, growing to fill available space; use it for card grids, stat blocks, and any content where columns should reflow automatically.
| Attribute | Values | Default | Notes |
|---|---|---|---|
gap | none | tight | group | form-row | block | section | block | Maps to the corresponding --space-* token. |
min | sm | md | lg | md (16rem) | sm = 12rem, md = 16rem, lg = 20rem. Resolves via --grid-min-* tokens. |
Default (gridmin="medium", gap="block")
gridmin="small" — tighter columns (12rem min)
gridmin="large"— wider columns (20rem min)
Places children in a horizontal row with space pushed between them, useful for headers, toolbars, and any pairing of a label on one side with an action on the other.
| Attribute | Values | Default | Notes |
|---|---|---|---|
gap | none | tight | group | form-row | block | section | group | Maps to the corresponding --space-* token. Gap applies when items wrap on narrow viewports. |
Two children
Three children
gap="none"
gap="block"
Any container can be annotated with surface to pick up a shared visual treatment — background, border, and radius. Works on any element.
| Attribute | Values | Default | Notes |
|---|---|---|---|
surface | raised | flat | sunken | (none — absent = no treatment) | Any element |
surface="raised"
Child A Child Bsurface="flat"
Child A Child Bsurface="sunken"
Child A Child BAny container can be annotated with pad to apply a consistent padding drawn from the semantic spacing scale.
| Attribute | Values | Default | Notes |
|---|---|---|---|
pad | tight | group | form-row | block | section | (none — absent = no padding) | Any element |
pad="tight"
Childpad="group"
Childpad="form-row"
Childpad="block"
Childpad="section"
ChildA labeled numeric tile — mono value on top, mono uppercase label beneath. Used for stat readouts (HP, AP, shield, XP, etc.). Use inline-flex so tiles line up cleanly in a row.
| Attribute | Values | Default | Notes |
|---|---|---|---|
size | small | (none = default) | Compact variant for inline usage |
Default
size="small"
A page-header primitive with five slots: optional in-head breadcrumbs, a mono uppercase kicker, a native h1 (overrides global centred h1 to left-align inside page-head), and a page-meta row that holds sub + actions. On tablet+ (≥48em), sub and actions share a bottom-aligned row; on mobile they stack column.
| Element | Values | Default | Notes |
|---|---|---|---|
page-crumbs | — | — | In-head breadcrumb slot. Contains a nav/ol trail. Used when SuppressBreadcrumbs is set on LayoutProps. |
page-kicker | — | — | Mono uppercase, muted. |
h1 | — | — | Native h1 inside page-head. page-head h1 scoped selector sets text-align: left and margin: 0, overriding the global centred h1. |
page-meta | — | — | Wrapper for sub + actions. Column on mobile, bottom-aligned row at ≥48em. |
page-sub | — | — | Caps at var(--max-prose) (68ch). Child of page-meta. |
page-actions | — | — | Wraps; pushes to right at ≥48em via margin-left: auto. Child of page-meta. |
Minimal
Full
With breadcrumbs
h2 is the default section-divider heading — mono bold with top border and section margin. Use variant="plain" to opt out (for dialog titles, stat labels, mid-card subheads).
| Attribute | Values | Default | Notes |
|---|---|---|---|
variant | plain | (none = section-divider default) | Opt-out: removes border/margin/padding |
Subsequent h2 (divider visible)
A paragraph precedes this h2, so it is not first-child.
Top border and section margin are visible above this heading.
Plain variant (no divider regardless of position)
A paragraph precedes this h2, but the plain variant suppresses the divider.
No top border or margin regardless of position in the container.
Native <button> is the canonical action element. Attribute variants cover visual tones; the [block] attribute makes it full-width. For icon-only actions, use <icon-button> which enforces a 44×44 hit target.
| Element | Attribute | Values | Default | Notes |
|---|---|---|---|---|
button | variant | primary, ghost, danger, damage | (none = default) | default has dashed-border "quiet" look (pre-existing; restyle is a separate ticket) |
button | size | small | (none = default) | existing; no change |
button | block | (boolean) | — | full-width |
icon-button | — | — | — | 44×44 hit target; wrap a <button> or <a> inside for semantics |
Default variants
Sizes
Block (full-width)
Icon buttons
Use <rule-callout> to pull out guidance, warnings, or constraints inside rule prose. The variant attribute picks tone; add a <rule-callout-title> child for a mono uppercase label.
| Element | Attribute | Values | Default | Notes |
|---|---|---|---|---|
rule-callout | variant | note, warning, constraint, danger | (none = default) | left-border color changes per tone |
rule-callout-title | — | — | — | optional mono uppercase label at top |
Default callout — no variant. Use this for general guidance that doesn't carry a strong tone.
Accent-tinted callout for things worth flagging but not alarming.
Warm-tinted callout for situations that can go wrong if you're not careful.
Error-tinted callout for hard limits and rules that cannot be bent.
Strong error-tinted callout for consequences that are immediate and severe.
A generic progress bar for health, XP, fatigue, cooldowns. Height is fixed at 12px. Fill width comes from inline style="width: N%" on the inner <meter-bar-fill>. data-state on the outer element picks the fill color.
| Element | Attribute | Values | Default | Notes |
|---|---|---|---|---|
meter-bar | data-state | wounded, dying, dead | (none = healthy/green) | picks fill color |
meter-bar-fill | style="width: N%" | — | required | author sets percentage |
Healthy (75%)
Wounded (45%)
Dying (15%)
Dead (0%)
Small mono tag/badge for statuses, labels, enum values. The variant attribute tunes tone; use sparingly so the accent pulls attention where it matters.
| Element | Attribute | Values | Default | Notes |
|---|---|---|---|---|
info-pill | variant | accent, warm, good, bad | (none = neutral) | tone |
The site shell is the persistent frame surrounding all page content: a sticky header across the top, a nav panel that stacks below the header on narrow viewports and moves to the left at ≥64em (ships in T-DSA-3), and a footer at the bottom.
Mobile (stacked) Wide (≥64em) ┌─────────────────────┐ ┌────────────────────────────┐ │ site-header │ │ site-header │ ├─────────────────────┤ ├──────────┬─────────────────┤ │ nav-panel │ │ nav- │ │ ├─────────────────────┤ │ panel │ site-main │ │ site-main │ │ │ │ ├─────────────────────┤ ├──────────┴─────────────────┤ │ site-footer │ │ site-footer │ └─────────────────────┘ └────────────────────────────┘Sticky banner rendered once at the top of every page. Contains the site logo and (on narrow viewports) a nav-toggle.
| Attribute | Values | Default | Notes |
|---|---|---|---|
| No attributes currently. | |||
Inner-wrap at --max-page ships in T-DSA-3.
Brand-mark plus wordmark composite. Composed of a site-logo-mark (26×26 square brand-mark with serif "S") and site-logo-text (wordmark), separated by var(--space-tight).
| Element | Role | Notes |
|---|---|---|
site-logo | Container | Inline-flex row with gap: var(--space-tight). |
site-logo-mark | Brand-mark | 26×26 square, var(--font-display), inverted colours. Add aria-hidden="true". |
site-logo-text | Wordmark | var(--font-display) at 1.25rem, tracking −0.01em. |
Forward-declared — ships in T-DSA-4. Flat link list with top-border group separators (nav-group) and a 2px inset-left accent indicator on the current page link.
Full-viewport-width footer with a two-column inner wrapper. Brand column on the left, link navigation on the right. Columns stack on narrow viewports. Inner wrapper centers at --max-page.
© Soltherra RPG System
Four tokens used by the combat flanking widget only.
--color-flank-front--color-flank-side--color-flank-rear--color-flank-behind© Soltherra RPG System