Opus design system

Foundation and components — 19 primitives

Overview

Every component at a glance — select one to jump to its section.

design.md

Raw markdown documentation for the whole system.

# Opus Design System

The Opus design system is a white-label UI foundation for the manager dashboard.
It is built from a small set of theme drivers, semantic tokens, and reusable
React primitives. The source of truth is src/app/globals.css.

## Goals

- Keep product UI calm, mostly white, and content-first.
- Support tenant theming from a brand color and a canvas color.
- Use semantic tokens in components instead of raw hex, Tailwind grays, or one-off CSS.
- Keep status colors stable so meaning survives white-label branding.
- Make primitives feel consistent across dashboard, builder, docs, and training flows.

## Token Layers

1. Theme drivers — runtime values derived from the two tenant inputs (brand + canvas).
2. Foundation tokens — low-level colors, alpha, radius, shadows, type, status ramps.
3. Semantic tokens — product-facing roles consumed by components.

Components should only touch layer 3. Layers 1 and 2 exist for the theme engine.

## Theme Drivers

Defaults below are Opus brand #1D82FF on canvas #F9F8F6.

  --hue:       85       /* neutral surface + text hue (from canvas) */
  --c-bg:      0.003    /* neutral surface chroma / tint */
  --c-tx:      0.008    /* text + icon chroma tuning constant */
  --bg-l:      0.979    /* canvas lightness — anchors the off-white background */
  --contrast:  0.84     /* separation between surface / border / text steps */
  --brand-h:   257      /* brand hue */
  --brand-c:   0.195    /* brand chroma (0 = neutral dark primary) */
  --brand-l:   0.62     /* brand lightness */

## Neutral Ramp (OKLCH)

The neutral scale is an OKLCH grayscale tinted by the canvas hue — not a fixed
Tailwind gray. Surface steps stay near white and tint with the tenant; text
steps use the text chroma constant.

  --color-gray-0:    oklch(1 0 0)                                  /* pure white */
  --color-gray-25:   oklch(0.992 var(--c-bg) var(--hue))
  --color-gray-50:   oklch(var(--bg-l) var(--c-bg) var(--hue))     /* canvas */
  --color-gray-100:  oklch(calc(1 - 0.035 * var(--contrast)) var(--c-bg) var(--hue))
  --color-gray-200:  oklch(calc(1 - 0.055 * var(--contrast)) var(--c-bg) var(--hue))
  --color-gray-300:  oklch(calc(1 - 0.09  * var(--contrast)) var(--c-bg) var(--hue))
  --color-gray-400:  oklch(0.72 var(--c-tx) var(--hue))
  --color-gray-500:  oklch(0.58 var(--c-tx) var(--hue))
  --color-gray-600:  oklch(0.45 var(--c-tx) var(--hue))
  --color-gray-700:  oklch(0.36 var(--c-tx) var(--hue))
  --color-gray-800:  oklch(0.29 var(--c-tx) var(--hue))
  --color-gray-900:  oklch(0.22 var(--c-tx) var(--hue))
  --color-gray-950:  oklch(0.16 var(--c-tx) var(--hue))

## Alpha Ramp

Adaptive overlays for borders, states, and scrims.

  --color-alpha-dark-2:   oklch(0 0 0 / 0.02)
  --color-alpha-dark-4:   oklch(0 0 0 / 0.04)
  --color-alpha-dark-6:   oklch(0 0 0 / 0.06)
  --color-alpha-dark-8:   oklch(0 0 0 / 0.08)
  --color-alpha-dark-12:  oklch(0 0 0 / 0.12)
  --color-alpha-dark-16:  oklch(0 0 0 / 0.16)
  --color-alpha-light-4:  oklch(1 0 0 / 0.04)
  --color-alpha-light-8:  oklch(1 0 0 / 0.08)
  --color-alpha-light-12: oklch(1 0 0 / 0.12)
  --color-alpha-light-16: oklch(1 0 0 / 0.16)

## Brand

  --color-brand-primary: oklch(var(--brand-l) var(--brand-c) var(--brand-h))
  --color-brand-hover:   oklch(calc(var(--brand-l) - 0.05) var(--brand-c) var(--brand-h))
  --color-brand-active:  oklch(calc(var(--brand-l) - 0.09) var(--brand-c) var(--brand-h))
  --color-brand-bg:      oklch(var(--brand-l) var(--brand-c) var(--brand-h) / 0.10)
  --color-brand-border:  oklch(var(--brand-l) var(--brand-c) var(--brand-h) / 0.38)
  --color-brand-text:    oklch(calc(var(--brand-l) - 0.12) var(--brand-c) var(--brand-h))

## Semantic Colors

Backgrounds:

  bg-bg-canvas     -> --color-gray-50    /* lowest app background */
  bg-bg-primary    -> --color-gray-0     /* primary white surface */
  bg-bg-subtle     -> --color-gray-25    /* almost-white subtle background */
  bg-bg-secondary  -> --color-gray-100   /* grouped secondary surface */
  bg-bg-tertiary   -> --color-gray-200   /* recessed / inset surface */
  bg-bg-elevated   -> --color-gray-0     /* floating UI */

Text:

  text-text-primary    -> --color-gray-950
  text-text-secondary  -> --color-gray-600
  text-text-tertiary   -> --color-gray-500
  text-text-disabled   -> --color-gray-400
  text-text-inverse    -> --color-gray-0

Icons:

  text-icon-primary    -> --color-gray-800
  text-icon-secondary  -> oklch(0.50 var(--c-tx) var(--hue))
  text-icon-tertiary   -> oklch(0.64 var(--c-tx) var(--hue))
  text-icon-disabled   -> oklch(0.76 var(--c-tx) var(--hue))

Borders + states:

  border-border-primary    -> --color-alpha-dark-8
  border-border-secondary  -> --color-alpha-dark-12
  border-border-tertiary   -> --color-alpha-dark-16
  bg-state-hover           -> --color-alpha-dark-4
  bg-state-pressed         -> --color-alpha-dark-8
  bg-state-selected        -> --color-brand-bg
  ring-state-focus         -> --color-brand-primary
  overlay scrim            -> oklch(0 0 0 / 0.46)

Accent:

  accent-primary             -> --color-brand-primary
  accent-primary-hover       -> --color-brand-hover
  accent-primary-active      -> --color-brand-active
  accent-primary-foreground  -> --color-gray-0
  action-secondary             -> --color-alpha-dark-4
  action-secondary-hover       -> --color-alpha-dark-8
  action-secondary-active      -> --color-alpha-dark-12
  action-secondary-foreground  -> --color-text-primary
  action-destructive             -> --color-status-error-bg
  action-destructive-hover       -> error bg mixed 10% toward error text
  action-destructive-active      -> error bg mixed 16% toward error text
  action-destructive-foreground  -> --color-status-error-text

## Status Colors (fixed, not brand-derived)

  success  bg green-2      text green-11      border green-5
  warning  bg yellow-2     text yellow-11     border yellow-5
  error    bg red-2        text red-11        border red-5
  info     bg teal-2       text teal-11       border teal-5
  remediation bg orange-3  text orange-11     border orange-6
  ai       bg ai-1/10      text ai-1         border ai-1/28

Status is always paired with an icon + label so it survives a red brand.

## Typography

Families:

  --font-sans  Inter Variable   /* product UI + display */
  --font-mono  Geist Mono       /* code, token names, kbd */

Size tokens (name -> rem / px / line-height):

  micro     0.6875rem  11px  1.35
  mini      0.75rem    12px  1.35
  small     0.875rem   14px  1.4
  regular   1rem       16px  1.45    /* body default */
  large     1.125rem   18px  1.4
  title3    1.25rem    20px  1.3
  title2    1.5rem     24px  1.25
  title1    2.25rem    36px  1.1

Weights:

  light 300   normal 450   medium 500   semibold 600   bold 700

Composite utilities:

  title-display       opsz 32, 20px, weight 500, -0.015em
  title-display-bold  opsz 32, 24px, weight 700, -0.02em
  screen-body         opsz 32, 18px, weight 450, -0.01em

## Radius

  --radius:          0.5rem    /* 8px base */
  --radius-control:  0.625rem  /* 10px — compact controls */
  rounded-sm   -> base - 4px   /* 4px  */
  rounded-md   -> base - 2px   /* 6px  */
  rounded-lg   -> base         /* 8px  */
  rounded-xl   -> base + 4px   /* 12px */
  rounded-2xl  -> base * 1.8   /* ~14px */
  rounded-3xl  -> base * 2.2
  rounded-4xl  -> base * 2.6
  rounded-full -> 9999px       /* pills, tabs, buttons */

## Elevation

Base family (pure shadow):

  --shadow-bas-sm:  0 4px 12px rgba(25,25,25,.027), 0 1px 2px rgba(25,25,25,.02)
  --shadow-bas-md:  0 8px 12px rgba(25,25,25,.027), 0 2px 6px rgba(25,25,25,.027)
  --shadow-bas-lg:  0 20px 24px rgba(25,25,25,.05),  0 5px 8px rgba(25,25,25,.027)
  --shadow-bas-dif: 0 12px 32px rgba(25,25,25,.027)
  --shadow-bas-scr: 0 24px 48px rgba(25,25,25,.24),  0 4px 12px rgba(25,25,25,.14)

Outlined family (shadow + 1px hairline ring):

  --shadow-out-sm:  0 2px 4px rgba(0,0,0,.04),       0 0 0 0.5px rgba(42,28,0,.07)
  --shadow-out-md:  0 8px 12px rgba(25,25,25,.027),  0 0 0 0.5px rgba(42,28,0,.07)
  --shadow-out-lg:  0 20px 24px rgba(25,25,25,.05),  0 0 0 0.5px rgba(42,28,0,.07)
  --shadow-out-dif: 0 12px 32px rgba(25,25,25,.027), 0 0 0 0.5px rgba(42,28,0,.07)
  --shadow-out-scr: 0 24px 48px rgba(25,25,25,.24),  0 0 0 0.5px rgba(42,28,0,.07)

Use the smallest shadow that communicates the layer.

## Motion

Use motion only when it clarifies a change, never for decoration. Most
interactions should feel instant: a duration of `0ms` is often the snappiest
and best choice, and the call is context-dependent.

When motion genuinely helps, such as revealing or moving an element, keep it
short and physical with the easing `cubic-bezier(0.175, 0.885, 0.32, 1.1)`:
roughly 150ms for state changes, 200ms for popovers and tooltips, and 300ms for
overlays and modals.

Avoid long, looping, or attention-grabbing animation, and honor
`prefers-reduced-motion` by dropping nonessential motion.

## Components

Avatar, Badge, Button, Card, Checkbox, Divider, Label, Progress, Select,
Tabs, Text Field, Toggle, Tooltip.

Button rule: primary/default buttons must include a visible text label. Do not
use the primary/default variant for icon-only buttons; use secondary, outline,
ghost, or destructive with an aria-label instead.

## Engineering Rules

- Prefer semantic classes over raw CSS variables in component markup.
- Do not hardcode hex values in product UI.
- Do not use raw Tailwind neutral classes for product surfaces.
- Keep shadcn compatibility tokens (--background, --card, etc.) as an adapter layer.
- Status colors stay semantic and fixed across tenants.
- Components should be reusable without tenant-specific branches.

Colors

Semantic color roles derived from brand and canvas drivers.

Engineer model

The theme starts from two tenant inputs: a brand color and a canvas color. Runtime code decomposes those into OKLCH drivers such as --hue, --c-bg, --bg-l, --contrast, and brand hue/chroma/lightness values.

The neutral scale is not a fixed Tailwind gray. It is an OKLCH grayscale tinted by the canvas hue, so white-label themes can feel warm, cool, or neutral without every component changing classes.

Components should consume semantic roles like bg-bg-secondary. Raw gray steps are foundation tokens used to derive those roles, not the normal product API.

Raw OKLCH gray ramp

gray-0

white

gray-25

near white

gray-50

canvas

gray-100

secondary

gray-200

tertiary

gray-300

soft

gray-400

disabled

gray-500

tertiary text

gray-600

secondary text

gray-700

strong

gray-800

icons

gray-900

darkest

gray-950

primary text

Raw OKLCH red ramp

Fixed crimson status scale at hue 17. Error semantics use red-2 for fill, red-5 for borders, and red-11 for readable text.

--color-red-1

softest

--color-red-2

error fill

--color-red-3

tint

--color-red-4

soft

--color-red-5

error border

--color-red-6

medium

--color-red-7

strong tint

--color-red-8

strong

--color-red-9

solid

--color-red-10

hover solid

--color-red-11

error text

--color-red-12

deep text

Raw OKLCH green ramp

Fixed success scale at hue 145. Success semantics use green-2 for fill, green-5 for borders, and green-11 for readable text.

--color-green-1

softest

--color-green-2

success fill

--color-green-3

tint

--color-green-4

soft

--color-green-5

success border

--color-green-6

medium

--color-green-7

strong tint

--color-green-8

strong

--color-green-9

solid

--color-green-10

hover solid

--color-green-11

success text

--color-green-12

deep text

Raw OKLCH yellow ramp

Fixed warning scale at hue 91. Warning semantics use yellow-2 for fill, yellow-5 for borders, and yellow-11 for readable text.

--color-yellow-1

softest

--color-yellow-2

warning fill

--color-yellow-3

tint

--color-yellow-4

soft

--color-yellow-5

warning border

--color-yellow-6

medium

--color-yellow-7

strong tint

--color-yellow-8

strong

--color-yellow-9

solid

--color-yellow-10

hover solid

--color-yellow-11

warning text

--color-yellow-12

deep text

Raw OKLCH orange ramp

Fixed auxiliary warm scale at hue 55 for orange accents and charts.

--color-orange-1

softest

--color-orange-2

fill

--color-orange-3

tint

--color-orange-4

soft

--color-orange-5

border

--color-orange-6

medium

--color-orange-7

strong tint

--color-orange-8

strong

--color-orange-9

solid

--color-orange-10

hover solid

--color-orange-11

text

--color-orange-12

deep text

Raw OKLCH purple ramp

Fixed purple scale at hue 295 for purple accents and charts.

--color-purple-1

softest

--color-purple-2

fill

--color-purple-3

tint

--color-purple-4

soft

--color-purple-5

border

--color-purple-6

medium

--color-purple-7

strong tint

--color-purple-8

strong

--color-purple-9

solid

--color-purple-10

hover solid

--color-purple-11

text

--color-purple-12

deep text

Raw OKLCH teal ramp

Fixed info scale at hue 180. Info semantics use teal-2 for fill, teal-5 for borders, and teal-11 for readable text.

--color-teal-1

softest

--color-teal-2

info fill

--color-teal-3

tint

--color-teal-4

soft

--color-teal-5

info border

--color-teal-6

medium

--color-teal-7

strong tint

--color-teal-8

strong

--color-teal-9

solid

--color-teal-10

hover solid

--color-teal-11

info text

--color-teal-12

deep text

Raw OKLCH AI ramp

Saturated AI identity colors. AI semantics use ai-1 as readable text, with translucent ai-1 fills and borders for surfaces.

--color-ai-1

ai text

--color-ai-2

violet

--color-ai-3

purple

--color-ai-4

magenta

--color-ai-5

hot pink

--color-ai-6

rose

--color-ai-7

coral

--color-ai-8

glow

Solid color comparison

Every chromatic family at its solid step (9), placed flush so the set can be judged together.

red
orange
yellow
green
teal
purple

Alpha ramp

Adaptive overlay tokens for borders, interaction states, and scrims. Dark alpha is previewed on white; light alpha is previewed on dark.

alpha-dark-2

2% dark overlay

alpha-dark-4

4% dark overlay

alpha-dark-6

6% dark overlay

alpha-dark-8

8% dark overlay

alpha-dark-12

12% dark overlay

alpha-dark-16

16% dark overlay

alpha-light-4

4% light overlay

alpha-light-8

8% light overlay

alpha-light-12

12% light overlay

alpha-light-16

16% light overlay

Product semantic tokens

background
bg-bg-canvasLowest app background
bg-bg-primaryPrimary white surface
bg-bg-subtleAlmost-white subtle background surface
bg-bg-secondaryGrouped secondary surface
bg-bg-tertiaryRecessed or inset surface
bg-bg-elevatedFloating surface
text
text-text-primaryDefault readable text
text-text-secondarySupporting body text
text-text-tertiaryMetadata and helper text
text-text-disabledDisabled or unavailable text
text-text-inverseText on dark or brand fills
icon
text-icon-primaryPrimary icons
text-icon-secondarySecondary icons
text-icon-tertiarySubtle icons
text-icon-disabledDisabled icons
text-icon-inverseIcons on dark or brand fills
border and state
border-border-primaryDefault hairline edge
border-border-secondaryStronger dividers and inputs
border-border-tertiaryHighest contrast border
bg-state-hoverHover state fill
bg-state-pressedPressed state fill
bg-state-selectedSelected state fill
ring-state-focusKeyboard focus ring
bg-overlay-scrimModal and overlay scrim
accent
accent-primaryTenant brand action color
accent-primary-hoverPrimary action hover
accent-primary-activePrimary action pressed
accent-primary-foregroundText on primary actions
action-secondarySecondary action fill
action-secondary-hoverSecondary action hover
action-secondary-activeSecondary action pressed
action-secondary-foregroundText on secondary actions
action-destructiveDestructive action fill
action-destructive-hoverDestructive action hover
action-destructive-activeDestructive action pressed
action-destructive-foregroundText on destructive actions
status
bg-status-success-bgSuccess background
text-status-success-textSuccess text
border-status-success-borderSuccess border
bg-status-success-solidSuccess solid
text-status-success-solid-foregroundSuccess solid foreground
bg-status-warning-bgWarning background
text-status-warning-textWarning text
border-status-warning-borderWarning border
bg-status-error-bgError background
text-status-error-textError text
border-status-error-borderError border
bg-status-info-bgInfo background
text-status-info-textInfo text
border-status-info-borderInfo border
bg-status-remediation-bgRemediation background
text-status-remediation-textRemediation text
border-status-remediation-borderRemediation border
bg-status-ai-bgAI background
text-status-ai-textAI text
border-status-ai-borderAI border

Rules

Use semantic roles

Product UI should use bg-bg-*, text-text-*, text-icon-*, border-border-*, state, accent, and status tokens.

Avoid raw grays

The neutral ramp exists as a foundation. Components should not reach for raw gray steps unless documenting the system.

Status is fixed

Success, warning, error, info, and AI colors stay independent from tenant brand colors so meaning remains stable.

Surfaces

How background tokens stack to build layered layouts.

Surface stack

Surfaces are the background tokens arranged by depth. The warm canvas sits lowest as the app shell; white primary surfaces hold content; subtle, secondary, and tertiary surfaces create gentle hierarchy inside them; and elevated floats above for popovers and menus.

bg-bg-canvas · app shell
bg-bg-primary
bg-bg-primary · main
bg-bg-subtle
bg-bg-secondary
bg-bg-tertiary · inset
bg-bg-elevated

Roles

bg-bg-canvasLowest app background — the dashboard shell.
bg-bg-primaryPrimary white surface for cards, panels, and content.
bg-bg-subtleAlmost-white subtle background inside white surfaces.
bg-bg-secondaryGrouped secondary surface for related blocks.
bg-bg-tertiaryRecessed or inset surface such as wells.
bg-bg-elevatedFloating UI: popovers, dropdowns, dialogs, sheets.

Rules

Stack by depth

Use canvas for the shell, primary for content, and subtle/secondary/tertiary only when nested hierarchy is needed.

Elevated for floating

Reach for bg-bg-elevated on floating UI even when it matches primary in the light theme — the role may diverge in other themes.

Pair with elevation

Floating surfaces combine with the shadow scale (shadow-out-*) to read as lifted above the page.

Typography

Font families, named size tokens, weights, and composite title utilities.

Families

Inter Variable

Primary UI and display

var(--font-sans)

Geist Mono

Code, token names, keyboard hints

var(--font-mono)

Named Size Tokens

text-micro

11px · lh 1.35

0.6875rem

Micro labels

text-mini

12px · lh 1.35

0.75rem

Small metadata

text-small

14px · lh 1.4

0.875rem

Controls and labels

text-regular

16px · lh 1.45

1rem

Body default

text-large

18px · lh 1.4

1.125rem

Large body

text-title3

20px · lh 1.3

1.25rem

Section title

text-title2

24px · lh 1.25

1.5rem

Page title

text-title1

36px · lh 1.1

2.25rem

Hero title

Weight Tokens

light

300

normal

450

medium

500

semibold

600

bold

700

Composite Utilities

title-display · 20px / 500

Build training that scales

title-display-bold · 24px / 700

Manager dashboard

Title + Subtitle Pairings

Common label/metadata combinations. Title uses text-text-primary; subtitles step down in size and color for hierarchy.

Assign trainees

Choose who receives this module

16px / 14px · secondary

Manager dashboard

Updated 2 hours ago

14px / 13px · secondary

Forklift safety basics

6 screens · Draft

14px / 12px · tertiary

Completion rate

Last 30 days

14px / 11px · tertiary

Certificate issued

Sent to 12 trainees

13px / 13px · tertiary

Alex Brinza

Operations lead

13px / 12px · tertiary

Paragraphs

Body copy options for descriptions and helper text. Sorted largest to smallest; use text-text-secondary for readable body and text-text-tertiary for supporting detail.

16px · lh 1.45 · secondary · Regular body

About this training module

Assign this module to a trainee to begin tracking completion and check-ins. Managers can review progress, send reminders, and issue certificates once every screen is finished.

14px · lh 1.4 · secondary · Compact body

How completion tracking works

Assign this module to a trainee to begin tracking completion and check-ins. Managers can review progress, send reminders, and issue certificates once every screen is finished.

13px · lh 1.35 · tertiary · Helper text

When reminders are sent

Assign this module to a trainee to begin tracking completion and check-ins. Managers can review progress, send reminders, and issue certificates once every screen is finished.

12px · lh 1.35 · tertiary · Fine print

Certificate and completion policy

Assign this module to a trainee to begin tracking completion and check-ins. Managers can review progress, send reminders, and issue certificates once every screen is finished.

Rules

Atomic first

Compose typography from one family, one size token, and one weight token. Reach for title-display utilities only for product headings.

Body default

Body text uses text-regular with normal weight 450 and the app-wide letter spacing from globals.css.

Docs chrome

The documentation frame still uses only 14px, 13px, and 11px. Larger type appears here only as typography samples.

Radius

Corner scale for controls, cards, and large containers.

sm

4px

md

6px

control

10px

xl

12px

full

9999px

Use by role

Compact controls use radius-control, small inner affordances use sm/md, card-like containers use lg/xl, and pills/tabs/buttons use full.

Icons

Iconography used across the design system. Icons inherit currentColor and size from the component that owns them.

Rules

Color follows text

Use currentColor for strokes and fills. Component variants own the foreground token, so icons inherit status, action, and glass colors automatically.

Size follows component

Do not hardcode icon dimensions in call sites. Buttons, badges, tabs, and toolbar controls set icon sizes through their component styles.

Stroke style

System icons use a 1.5px rounded stroke. Custom SVGs should match that rhythm unless their source shape requires dots or filled details.

Status and badges

Lucide icons used inside Badge variants. Render at currentColor and inherit the badge foreground token.

Check

currentColor

Circle

currentColor

CircleAlert

currentColor

CircleCheck

currentColor

CircleDashed

currentColor

Clock

currentColor

FileCheck2

currentColor

FileX2

currentColor

Hourglass

currentColor

Info

currentColor

RefreshCcw

currentColor

Timer

currentColor

Actions and navigation

General action icons used by buttons, component cards, tabs, and navigation affordances.

ArrowUpRight

currentColor

LayoutGrid

currentColor

Layers

currentColor

MoreHorizontal

currentColor

Plus

currentColor

RectangleVertical

currentColor

Settings

currentColor

Product and custom

Local SVG components for branded or non-Lucide shapes. These must also use currentColor.

StackPerspectiveIcon

currentColor

ToolbarTrashIcon

currentColor

ToolbarLayersIcon

currentColor

ToolbarCheckIcon

currentColor

ToolbarPlusIcon

currentColor

Elevation

Shadow families for lift, panels, and modal-level surfaces.

Base — soft shadow, no ring

bas-sm

Subtle lift

bas-md

Card elevation

bas-lg

Raised panel

bas-dif

Diffuse float

bas-scr

Modal / scrim

Outlined — shadow + 1px hairline ring

out-sm

Outlined subtle

out-md

Outlined card

out-lg

Raised panel

out-dif

Outlined float

out-scr

Outlined modal

Motion

Timing and easing guidance for purposeful interface movement.

Principle

Use motion only when it clarifies a change, never for decoration. Most interactions should feel instant: a duration of 0ms is often the snappiest and best choice, and the call is context-dependent.

Easing

When motion genuinely helps, use cubic-bezier(0.175, 0.885, 0.32, 1.1) for short, physical movement.

150ms

Use for small state changes, such as pressed, selected, expanded, or inline feedback.

200ms

Use for popovers, tooltips, and lightweight reveal interactions.

300ms

Use for overlays and modal-level surfaces when the spatial change needs to be understood.

Reduced motion

Honor prefers-reduced-motion by dropping nonessential motion.

Avoid long, looping, or attention-grabbing animation.

Token Usage

How to choose the right foundation token family in product code.

Surface

bg-bg-primary, bg-bg-subtle, bg-bg-secondary, bg-bg-tertiary

Text

text-text-primary, text-text-secondary, text-text-tertiary

Icon

text-icon-primary, text-icon-secondary, text-icon-tertiary

Border

border-border-primary, ring-border-primary

State

hover:bg-state-hover, active:bg-state-pressed

Status

bg-status-success-bg, text-status-error-text

Avatar

User identity with fallbacks and grouping.

ABCVPN
ABCVML
+5

Badge

Compact status and metadata labels.

DefaultSecondaryOutlineGhostOverdue
CompleteDue soonOverdueNewstack-perspectiveAI draft
SmallDefaultLargeLarge icon

Demo badges

BadgeColorTokens
CompletedGreen
bg-status-success-bgtext-status-success-texttype: text-small / normal
Completed solidGreen
bg-status-success-solidtext-status-success-solid-foregroundtype: text-small / normal
PassGreen
bg-status-success-bgtext-status-success-texttype: text-small / normal
Past dueYellow
bg-status-warning-bgtext-status-warning-texttype: text-small / normal
MissedYellow
bg-status-warning-bgtext-status-warning-texttype: text-small / normal
FailRed
bg-status-error-bgtext-status-error-texttype: text-small / normal
In remediationOrange
bg-status-remediation-bgtext-status-remediation-texttype: text-small / normal
UpcomingGray
bg-bg-secondarytext-text-secondarytype: text-small / normal
Not startedGray
bg-bg-secondarytext-text-secondarytype: text-small / normal
In progressAI
bg-status-ai-bgtext-status-ai-texttype: text-small / normal
Ready for reviewBrand
bg-brand-bgtext-brand-texttype: text-small / normal

Tip Banner

A dark, glassy coach-mark for surfacing one contextual tip with a single dismissing action. Inverts against the light dashboard to read as a transient overlay.

Quick Tip

Large videos can be compressed to reduce file size. Double-click on the overlay to open Video Editor.

Heads up

Modules left in Draft are only visible to you until you publish them.

Collection Card

A board / collection tile: a fanned stack of cover images over a title and count. Hover to open the stack — back covers fan out and the front cover lifts.

Ghost

Filled (gray surface)

Small

Row · framed covers

Row · subtle surface

Gooey Loader

An indeterminate loader of two circles rotating horizontally around a shared axis. The circle turning to the front swells as it eclipses the other; an SVG metaball filter melts them where they cross. Color follows currentColor.

Loading

Default

Loading

Small

LoadingThinking…

AI thinking

Done

Success

LoadingThinking…

Thinking → done

Button

Primary action element across variants and sizes.

Variants

Sizes

Inline icon sizes

24px button · 12px icon
28px button · 14px icon
32px button · 16px icon
36px button · 16px icon

Icon buttons

Icon sizes

icon-xs24px button · 12px icon
icon-sm28px button · 16px icon
icon32px button · 16px icon
icon-lg36px button · 16px icon

Fully rounded

Fully rounded sizes

On surfaces

bg-bg-canvas
bg-bg-subtle
bg-bg-secondary
bg-bg-tertiary

On dark overlays

gray-900
bg-bg-tertiary
bg-bg-secondary
bg-bg-subtle
image backdrop

Glass toolbar

Card

Elevated white surface for grouped content.

Forklift safety basics
6 screens · Draft
Assign this module to a trainee to begin tracking completion and check-ins.

Checkbox

Binary selection with an associated label.

Divider

Hairline separator between content groups.

Section one
Assigned
In progress
Certified

Label

Field caption tied to an input control.

Progress

Linear completion indicator.

Onboarding path62%

Select

Single-choice menu from a list of options.

Tabs

Switch between related panels of content.

Text labels

Module summary, completion rate, and assigned trainees.

Icon only

Module summary, completion rate, and assigned trainees.

Canvas view switcher

Text Field

Single-line text input with states.

Toggle

Two-state button for inline options.

Tooltip

Contextual hint shown on hover or focus.

Glass Surface

A reusable glass material primitive backed by CSS tokens and the glass-surface utility. Use it for controls, overlays and toolbars that float above busy content.

builder photo

Glass Surface

Token-backed material using --glass-surface-* and the shared glass-surface utility.

white surface

Glass Surface

Same material on a light canvas — useful for toolbars and controls that float above white panels.

Glass Popover

A rich, hover-triggered popover — a tooltip with a body. Defaults to a light translucent surface, with an optional shared glass-surface material for darker overlay moments.