01 · Three-tier swatch · hero context
data-tierLive context · surface = elevated
The cards adapt without writing a single mode.
Nebula
Colour as constellation, not as paint.
Orion
Components read tier, never raw hex.
Aurora
Animation breathes through the same surface.
02 · Tier inspector · which tokens drive what
--bg* familyLowtier 1
--bg--ink--line--ink-faintElevatedtier 2
--bg-elev--ink--line-strong--accentHightier 3
--bg-elev-2--ink--accent-2--accent-303 · Side-by-side · same card · three tiers
comparelow
Sign in
elevated
Sign in
high
Sign in
04 · Tier morph · hover to cycle
transition: background 600mscurrent tier · low · hover or focus
Usage
API surfaceAuthoring contract
A picker writes --bg, --bg-elev, and --bg-elev-2 onto the target surface. Components inside read those tokens — none of them know which tier they're in. Switching is a token rewrite, not a class swap. Reduce-motion users see an instant swap; everyone else sees a 600ms morph.
| Hook | Values | Effect |
|---|---|---|
data-tier | low · elevated · high | Current tier on the swatch / morph host. |
aria-pressed on swatch | boolean | Selected tier indicator (radio semantics). |
--bg | colour token | Tier 1 surface — page floor. |
--bg-elev | colour token | Tier 2 surface — default card / panel. |
--bg-elev-2 | colour token | Tier 3 surface — popovers, lifted UI. |
--line / --line-strong | colour token | Borders pair with the tier above. |
| JS event | stp:change | Fires on the host with detail.tier. |
prefers-reduced-motion | — | Morph transition collapses to 0ms. |
View HTML
<div class="lsd-stp">
<div class="lsd-stp__row" role="radiogroup">
<button class="lsd-stp__swatch" data-tier="low" role="radio" aria-pressed="false">…</button>
<button class="lsd-stp__swatch" data-tier="elevated" role="radio" aria-pressed="true">…</button>
<button class="lsd-stp__swatch" data-tier="high" role="radio" aria-pressed="false">…</button>
</div>
<div class="lsd-stp__context" data-stp-context>…</div>
</div>