Tokens
Design tokens are design decisions stored as variables. They separate structure from visual style, so switching themes or updating a brand color cascades across every component without touching individual files.
Token layers
| Layer | Contains |
|---|---|
| Base tokens | Raw values (colors, sizes, weights) |
| Semantic tokens | Intent-based aliases (primary, surface, error) |
| Component tokens | Scoped to individual components (button-bg, input-border) |
Each layer references the one below it. Components never use base tokens directly.
Base tokens
Color
| Swatch | Token | Value |
|---|---|---|
#111827 | primary-900 | #111827 |
#1E293B | primary-800 | #1E293B |
#0043CE | accent-700 | #0043CE |
#0F62FE | accent-600 | #0F62FE |
#E8F0FE | accent-100 | #E8F0FE |
#F5F8FF | accent-50 | #F5F8FF |
#2563A0 | info-700 | #2563A0 |
#3B82B8 | info-600 | #3B82B8 |
#EFF6FF | info-100 | #EFF6FF |
#F0F7FF | info-50 | #F0F7FF |
#111827 | gray-900 | #111827 |
#374151 | gray-700 | #374151 |
#636971 | gray-500 | #636971 |
#D1D5DB | gray-300 | #D1D5DB |
#E5E7EB | gray-200 | #E5E7EB |
#F3F4F6 | gray-100 | #F3F4F6 |
#F9FAFB | gray-50 | #F9FAFB |
#FFFFFF | white | #FFFFFF |
#15803D | green-700 | #15803D |
#E2F5E7 | green-100 | #E2F5E7 |
#C07C14 | yellow-600 | #C07C14 |
#FAF0D2 | yellow-100 | #FAF0D2 |
#BB4A4A | red-600 | #BB4A4A |
#FAE8E8 | red-100 | #FAE8E8 |
Two blues:
accent-*is the interactive/brand blue (buttons, links, focus).info-*is the informational blue (notices, status messages). They are intentionally different hues — accent is vivid (#0F62FE), info is muted (#3B82B8).
Spacing
| Token | Value |
|---|---|
space-1 | 0.25rem (4px) |
space-2 | 0.5rem (8px) |
space-3 | 0.75rem (12px) |
space-4 | 1rem (16px) |
space-5 | 1.5rem (24px) |
space-6 | 2rem (32px) |
space-7 | 2.5rem (40px) |
space-8 | 3rem (48px) |
space-9 | 4rem (64px) |
space-10 | 6rem (96px) |
Typography
| Token | Value |
|---|---|
font-sans | system-ui, -apple-system, "Segoe UI", sans-serif |
font-mono | ui-monospace, "SF Mono", "Cascadia Code", monospace |
font-size-xs | 0.688rem (11px) |
font-size-caption | 0.75rem (12px) |
font-size-sm | 0.875rem (14px) |
font-size-base | 1rem (16px) |
font-size-lg | 1.125rem (18px) |
font-size-h4 | 1.188rem (19px) |
font-size-h3 | 1.438rem (23px) |
font-size-h2 | 1.75rem (28px) |
font-size-h1 | clamp(1.75rem, 1.25rem + 1.5vw, 2.063rem) |
font-size-display | 2.5rem (40px) |
font-weight-regular | 400 |
font-weight-medium | 500 |
font-weight-semibold | 600 |
font-weight-bold | 700 |
| Swatch | Token | CSS var | Value |
|---|---|---|---|
| bg | --ds-bg | ||
| fg | --ds-fg | ||
| heading | --ds-heading | ||
| muted | --ds-muted | ||
| border | --ds-border | ||
| surface | --ds-surface | ||
| white | --ds-white | ||
| on-accent | --ds-on-accent | ||
| primary | --ds-primary | ||
| primary-hover | --ds-primary-hover | ||
| primary-light | --ds-primary-light | ||
| primary-900 | --ds-primary-900 | ||
| link | --ds-link | ||
| focus | --ds-focus | ||
| overlay | --ds-overlay | ||
| disabled-bg | --ds-disabled-bg | ||
| disabled-text | --ds-disabled-text | ||
| success-bg | --ds-success-bg | ||
| success-border | --ds-success-border | ||
| success-text | --ds-success-text | ||
| warning-bg | --ds-warning-bg | ||
| warning-border | --ds-warning-border | ||
| warning-text | --ds-warning-text | ||
| error-bg | --ds-error-bg | ||
| error-border | --ds-error-border | ||
| error-text | --ds-error-text | ||
| info-bg | --ds-info-bg | ||
| info-border | --ds-info-border | ||
| info-text | --ds-info-text |
| Token | CSS var | Value | Visual |
|---|---|---|---|
| space-1 | --ds-space-1 | ||
| space-2 | --ds-space-2 | ||
| space-3 | --ds-space-3 | ||
| space-4 | --ds-space-4 | ||
| space-5 | --ds-space-5 | ||
| space-6 | --ds-space-6 | ||
| space-7 | --ds-space-7 | ||
| space-8 | --ds-space-8 | ||
| space-9 | --ds-space-9 | ||
| space-10 | --ds-space-10 |
| Token | CSS var | Resolved value |
|---|---|---|
| font-sans | --ds-font-sans | |
| font-mono | --ds-font-mono |
Font sizes
| Token | CSS var | Value | Sample |
|---|---|---|---|
| radius-none | --ds-radius-none | ||
| radius-sm | --ds-radius-sm | ||
| radius-md | --ds-radius-md | ||
| radius-lg | --ds-radius-lg | ||
| radius-xl | --ds-radius-xl |
Semantic tokens
Map base tokens to meaning. Components reference these.
Color
| Token | Maps to | Purpose |
|---|---|---|
color-primary | {accent-600} | Primary actions, links |
color-primary-hover | {accent-700} | Primary hover |
color-primary-light | {accent-50} | Tinted backgrounds |
color-bg | {white} | Page background |
color-surface | {gray-100} | Cards, sections |
color-fg | {gray-700} | Body text |
color-heading | {gray-900} | Headings |
color-muted | {gray-500} | Hints, labels |
color-border | {gray-200} | Dividers |
color-focus | {accent-600} | Focus ring |
color-success | {green-700} | Success |
color-warning | {yellow-600} | Warning |
color-error | {red-600} | Error |
color-info | {info-600} | Information |
Spacing
| Token | Maps to | Purpose |
|---|---|---|
spacing-xs | {space-1} | Tight gaps, icon margins |
spacing-sm | {space-2} | Inside compact elements |
spacing-md | {space-4} | Default component padding |
spacing-lg | {space-6} | Section separation |
spacing-xl | {space-8} | Page-level sections |
Typography
| Token | Maps to | Purpose |
|---|---|---|
text-body | {font-size-base} (1rem/16px) | Default body text (system-ui) |
text-sm | {font-size-sm} (0.875rem/14px) | Secondary info, metadata |
text-caption | {font-size-caption} (0.75rem/12px) | Timestamps, helper text |
text-heading | {font-weight-bold} | Heading weight |
text-label | {font-weight-semibold} | Labels, nav items |
Component tokens
Scope semantic tokens to individual components.
Button
| Token | Maps to |
|---|---|
button-bg-primary | {color-primary} |
button-bg-primary-hover | {color-primary-hover} |
button-text-primary | {white} |
button-bg-secondary | {white} |
button-border-secondary | {color-primary} |
button-bg-danger | {red-600} |
button-bg-danger-hover | {red-700} |
button-bg-disabled | {gray-300} |
button-text-disabled | {gray-500} |
Input
| Token | Maps to |
|---|---|
input-bg | {color-bg} |
input-border | {color-border} |
input-border-focus | {color-primary} |
input-border-error | {color-error} |
input-text | {color-heading} |
input-placeholder | {color-muted} |
Notice / Feedback
| Token | Maps to |
|---|---|
notice-info-bg | {info-50} |
notice-info-border | {info-400} |
notice-info-text | {info-800} |
notice-success-bg | {green-50} |
notice-success-border | {green-400} |
notice-success-text | {green-800} |
notice-warning-bg | {yellow-50} |
notice-warning-border | {yellow-400} |
notice-warning-text | {yellow-900} |
notice-error-bg | {red-50} |
notice-error-border | {red-400} |
notice-error-text | {red-800} |
State tokens
Interaction states are applied via prefixed utility classes.
| State | CSS prefix | Example |
|---|---|---|
| Hover | hover: | hover:bg-primary-hover |
| Focus | focus: | focus:ring-focus |
| Active | active: | active:bg-primary-hover |
| Disabled | disabled: | disabled:bg-disabled |
Component library integration
The Senco DS uses shadcn (base-nova style) as the underlying component library. A CSS variable bridge maps shadcn/Tailwind tokens to Senco semantic tokens within the .ds-layout scope:
| shadcn variable | Maps to Senco token |
|---|---|
--primary | --ds-primary (#0F62FE) |
--primary-foreground | #ffffff |
--background | --ds-bg (white) |
--foreground | --ds-fg (gray-700) |
--card | --ds-white |
--card-foreground | --ds-heading (gray-900) |
--muted | --ds-surface (gray-100) |
--muted-foreground | --ds-muted (gray-500) |
--destructive | --ds-red-600 |
--border | --ds-border (gray-200) |
--ring | --ds-primary |
--radius | 0.5rem |
This bridge lives in ds.css, so shadcn components pick up Senco branding without any overrides.
Responsive breakpoint tokens
| Token | Value | Usage |
|---|---|---|
--ds-bp-mobile | 600px | Mobile portrait and below |
--ds-bp-tablet | 1024px | Tablet portrait to landscape |
--ds-bp-desktop | 1440px | Standard desktop and above |
Rules
- Never hard-code raw values in component styles
- Always reference semantic or component tokens
- Base tokens exist only to be referenced by higher layers
- Changing a base token cascades through semantic and component layers
- State tokens follow the prefix pattern:
{state}:{property}-{value} - All interactive elements must define hover, focus, and disabled states
- shadcn components inherit Senco tokens via the CSS bridge — do not override individually