Semantic Design Tokens
SisterShield uses a semantic token system that maps meaning to color, not color to component. Tokens are defined as CSS custom properties in HSL, wired through Tailwind CSS configuration, and consumed by shadcn/ui components and custom UI.
Token Architecture
The pipeline flows in three stages:
- CSS Custom Properties (
src/app/globals.css) — define raw HSL values for light and dark mode. - Tailwind Config (
tailwind.config.ts) — map properties to named utility classes viahsl(var(--token)). - Component Usage — components reference Tailwind classes (
bg-primary,text-safety-exit,border-brand-soft-border).
This separation means a single token change in globals.css propagates to every component that uses it without touching component code.
Token Categories
Core Neutrals
| Token | Light Value (HSL) | Dark Value (HSL) | Purpose |
|---|---|---|---|
--background | 0 0% 100% | 222.2 84% 4.9% | Page background |
--foreground | 222.2 84% 4.9% | 210 20% 98% | Primary text |
--card | 0 0% 100% | 222.2 84% 4.9% | Card surfaces |
--card-foreground | 222.2 84% 4.9% | 210 20% 98% | Card text |
--popover | 0 0% 100% | 222.2 84% 4.9% | Popover/dropdown surfaces |
--popover-foreground | 222.2 84% 4.9% | 210 20% 98% | Popover text |
--muted | 210 40% 96.1% | 217.2 32.6% 17.5% | Muted backgrounds |
--muted-foreground | 215.4 16.3% 46.9% | 215 20.2% 65.1% | Secondary/muted text |
--secondary | 210 40% 96.1% | 217.2 32.6% 17.5% | Secondary surfaces |
--secondary-foreground | 222.2 47.4% 11.2% | 210 20% 98% | Secondary text |
--border | 214.3 31.8% 91.4% | 217.2 32.6% 17.5% | Default borders |
--input | 214.3 31.8% 91.4% | 217.2 32.6% 17.5% | Input borders |
--accent | 210 40% 96.1% | 217.2 32.6% 17.5% | Accent surfaces |
--accent-foreground | 222.2 47.4% 11.2% | 210 20% 98% | Accent text |
Brand Accent (Purple — restricted use)
| Token | Light Value | Dark Value | Purpose |
|---|---|---|---|
--primary | 262.1 83.3% 57.8% | 263.4 70% 50.4% | Primary CTA buttons, active focus rings |
--primary-foreground | 210 20% 98% | 210 20% 98% | Text on primary surfaces |
--ring | 262.1 83.3% 57.8% | 263.4 70% 50.4% | Focus ring color (matches primary) |
Brand Soft (Light purple tints)
| Token | Light Value | Dark Value | Purpose |
|---|---|---|---|
--brand-soft | 270 100% 98% | 270 30% 12% | Chip backgrounds, sidebar highlights, selected states |
--brand-soft-border | 269 97% 85% | 269 40% 30% | Borders on brand-soft surfaces |
Progress
| Token | Light Value | Dark Value | Purpose |
|---|---|---|---|
--progress-fill | 215 14% 72% | 215 14% 45% | Progress bar fill (in progress — neutral gray) |
--progress-fill-complete | 142 71% 45% | 142 71% 35% | Progress bar fill (completed — green) |
Safety
| Token | Light Value | Dark Value | Purpose |
|---|---|---|---|
--safety-exit | 0 84.2% 60.2% | 0 62.8% 30.6% | Quick Exit button text and hover background (red) |
--safety-exit-border | 0 72% 51% | 0 62.8% 40% | Quick Exit button border |
Destructive
| Token | Light Value | Dark Value | Purpose |
|---|---|---|---|
--destructive | 0 84.2% 60.2% | 0 62.8% 30.6% | Destructive actions (delete, reject) |
--destructive-foreground | 210 20% 98% | 210 20% 98% | Text on destructive surfaces |
State-Based CTA Styling
Course cards and action buttons use different visual treatments based on the student’s completion status. This prevents “purple everywhere” and gives each state a distinct meaning.
| State | Completion Status | Button Variant | Visual Treatment |
|---|---|---|---|
| Continue | IN_PROGRESS | Solid primary | Solid purple background, white text. This is the only solid purple button. |
| Start | NOT_STARTED | Outline with primary border | Purple border, purple text, transparent background. |
| Review | COMPLETED | Outline with green tint | Green border, green text, transparent background. |
Why This Matters
Purple is the brand accent color. If every button were solid purple, the design would lose hierarchy and the primary CTA would not stand out. By reserving solid purple for the single highest-priority action (“Continue where you left off”), the design creates a clear visual hierarchy.
Component Token Usage
| Component | Tokens Used | Notes |
|---|---|---|
| Page background | background, foreground | Applied via body base styles |
| Cards | card, card-foreground, border | Standard card surfaces |
| Primary buttons | primary, primary-foreground | Solid purple, reserved for primary CTA |
| Secondary buttons | secondary, secondary-foreground | Neutral gray buttons |
| Sidebar highlights | brand-soft, brand-soft-border | Active nav items, selected chips |
| Progress bars | progress-fill, progress-fill-complete | Gray while in progress, green when done |
| Quick Exit | safety-exit, safety-exit-border | Red themed for urgency |
| Get Help | brand-soft, brand-soft-border | Region selector uses soft brand tokens |
| Destructive actions | destructive, destructive-foreground | Delete, reject buttons |
| Focus rings | ring | Matches primary for keyboard accessibility |
| Input fields | input, border | Standard input borders |
Anti-Creep Rules
To maintain the intentional design hierarchy, follow these rules:
- Solid purple (
bg-primary) is only for the single highest-priority CTA on a page. Do not add solid purple to secondary actions, nav links, or decorative elements. - Use
brand-softfor selected/active states, notprimary. Sidebar highlights, chips, and toggles should use the soft tint, not solid purple. - Progress indicators use neutral gray (
progress-fill) while in progress. Purple would falsely suggest completion or urgency. - Safety components use red (
safety-exit), never purple. The Quick Exit must be visually distinct from all other UI elements. - New components default to neutral tokens (
secondary,muted,border). Only promote toprimaryorbrand-softwith intentional design justification.
Dark Mode
Dark mode tokens are defined in the .dark CSS class block in globals.css. Tailwind’s darkMode: ['class'] configuration means dark mode is toggled by adding the dark class to the <html> element.
Key dark mode adjustments:
- Background inverts from white to near-black (
222.2 84% 4.9%). - Primary purple shifts slightly darker (
263.4 70% 50.4%) for reduced glare. - Brand-soft shifts from a near-white tint (
270 100% 98%) to a dark tint (270 30% 12%). - Progress and safety tokens reduce saturation for comfortable contrast on dark backgrounds.
Technical Rationale
- Scalability: Adding a new semantic meaning (e.g., “warning”) requires adding one token to
globals.cssand one mapping intailwind.config.ts. No component changes needed. - Maintainability: Changing the brand color from purple to blue requires updating only the
--primaryand--ringHSL values. All components update automatically. - Meaning-to-color mapping: Tokens encode intent (
safety-exit,progress-fill-complete), not appearance (red-500,green-400). This makes the design system self-documenting and prevents arbitrary color choices.