Design Tokens

Last updated on 2026-08-27

The Email Marketing Kit uses an Operator design profile -- dense, information-rich layouts with flat surfaces, hairline borders, and a restrained color palette. All tokens are defined in app/globals.css using the oklch color space for perceptually uniform color manipulation.

Design Profile: Operator

The Operator profile is optimized for data-heavy dashboards and tool interfaces:

  • Flat surfaces with hairline borders (no drop shadows)
  • Dense information layouts with compact spacing
  • Neutral-dominant palette with a single accent hue
  • Monospace data for numerical values
  • High contrast for readability at small font sizes

oklch Color System

All colors use the oklch color space, which provides perceptually uniform lightness and chroma values:

oklch(lightness chroma hue)
  • Lightness (0-1): 0 is black, 1 is white
  • Chroma (0-0.4): 0 is gray, higher values are more saturated
  • Hue (0-360): color wheel angle

Primary Accent: Hue 115 (Chartreuse-Green)

The primary accent color uses hue 115, a chartreuse-green that provides strong visibility against neutral backgrounds.

Token Light Mode Dark Mode
--primary oklch(0.48 0.14 115) oklch(0.72 0.14 115)
--primary-foreground oklch(0.98 0.005 115) oklch(0.13 0.02 115)

Neutral Palette

Neutrals are pinned to hue 250-255 with near-zero chroma:

Token Light Mode Dark Mode Purpose
--background oklch(0.985 0.002 250) oklch(0.13 0.012 255) Page background
--foreground oklch(0.145 0.015 255) oklch(0.96 0.005 250) Primary text
--card oklch(1 0 0) oklch(0.17 0.014 255) Card surfaces
--muted oklch(0.96 0.004 250) oklch(0.22 0.015 255) Muted backgrounds
--muted-foreground oklch(0.4 0.02 250) oklch(0.7 0.02 250) Secondary text
--accent oklch(0.94 0.008 250) oklch(0.25 0.02 255) Hover/active states
--border oklch(0.92 0.004 250) oklch(1 0 0 / 12%) Borders
--input oklch(0.92 0.004 250) oklch(1 0 0 / 15%) Input borders

Secondary Accent

A purple secondary accent at hue 286:

Token Light Mode Dark Mode
--secondary oklch(0.78 0.08 286) oklch(0.72 0.08 286)
--secondary-foreground oklch(0.25 0.04 286) oklch(0.18 0.04 286)

Status Tokens

Status colors encode meaning beyond color alone -- each status is paired with text labels and icons throughout the UI.

Token Light Mode Dark Mode Usage
--success oklch(0.55 0.15 150) oklch(0.7 0.15 150) Active, sent, verified
--success-foreground oklch(0.98 0.01 150) oklch(0.16 0.03 150) Text on success
--warning oklch(0.6 0.14 75) oklch(0.75 0.14 80) Scheduled, sending, pending
--warning-foreground oklch(0.2 0.05 75) oklch(0.2 0.05 80) Text on warning
--destructive oklch(0.58 0.22 27) oklch(0.704 0.191 22.216) Bounced, failed, error
--info oklch(0.55 0.16 240) oklch(0.65 0.15 240) Draft, informational
--info-foreground oklch(0.98 0.01 240) oklch(0.15 0.03 240) Text on info

Chart Colors

Five chart colors for Recharts visualizations, anchored to distinct hues:

Token Light Mode Dark Mode Hue
--chart-1 oklch(0.48 0.14 115) oklch(0.72 0.14 115) 115 (green, matches primary)
--chart-2 oklch(0.65 0.08 286) oklch(0.65 0.08 286) 286 (purple)
--chart-3 oklch(0.6 0.08 1) oklch(0.6 0.08 1) 1 (red)
--chart-4 oklch(0.55 0.08 181) oklch(0.6 0.08 181) 181 (teal)
--chart-5 oklch(0.62 0.08 51) oklch(0.65 0.08 51) 51 (orange)

Typography

The kit uses three font families loaded via next/font/google:

Font Variable Usage Loaded Weights
Familjen Grotesk --font-familjen Headings (--font-heading) Variable
Inter Tight --font-inter-tight Body text (--font-sans) Variable
IBM Plex Mono --font-plex-mono Code and data (--font-mono) 400, 500

Font Application

/* globals.css */
--font-sans: var(--font-inter-tight), ui-sans-serif, system-ui, sans-serif;
--font-heading: var(--font-familjen), var(--font-inter-tight), ui-sans-serif, system-ui, sans-serif;
--font-mono: var(--font-plex-mono), ui-monospace, monospace;

Typography Scale

Element Font Weight Letter Spacing Line Height
Body Inter Tight 400 -0.011em 1.6
Headings (h1-h6) Familjen Grotesk 600 -0.025em 1.2
Code / Data IBM Plex Mono 400-500 Default Default

Base Font Size

The body font size is set to 0.875rem (14px) -- smaller than typical defaults, consistent with the Operator profile's dense layout.


Border Radius

The radius system uses a base value with multipliers:

Token Multiplier Computed Value (base: 0.375rem)
--radius-sm 0.6x 0.225rem
--radius-md 0.8x 0.3rem
--radius-lg 1.0x (base) 0.375rem
--radius-xl 1.4x 0.525rem
--radius-2xl 1.8x 0.675rem
--radius-3xl 2.2x 0.825rem
--radius-4xl 2.6x 0.975rem

The base radius of 0.375rem (6px) produces subtle rounding consistent with the Operator profile's flat, precise aesthetic.


Surface Treatment

Surfaces follow the Operator profile: flat with hairline borders, no shadows.

  • Cards use --card background with --border hairline border
  • Popovers use --popover background with border
  • Sidebar uses --sidebar background with --sidebar-border
  • No box-shadow is applied to surfaces

Dark Mode Strategy

Dark mode is implemented via class-based toggling with next-themes:

// app/layout.tsx
<ThemeProvider
  attribute="class"
  defaultTheme="system"
  enableSystem
  disableTransitionOnChange
>

Key Dark Mode Decisions

  1. System-aware -- defaults to the user's OS preference
  2. Class-based -- the .dark class is toggled on <html>
  3. No transitions -- disableTransitionOnChange prevents flash during toggle
  4. Inverted lightness -- dark mode tokens invert lightness while preserving hue and chroma
  5. Alpha borders -- dark mode borders use oklch(1 0 0 / 12%) for semi-transparent white borders
  6. Boosted chroma -- primary and status colors get slightly higher lightness in dark mode for readability
Token Light Dark
--sidebar oklch(0.975 0.004 250) oklch(0.15 0.014 255)
--sidebar-primary oklch(0.48 0.14 115) oklch(0.72 0.14 115)
--sidebar-accent oklch(0.93 0.008 250) oklch(0.22 0.018 255)
--sidebar-border oklch(0.92 0.004 250) oklch(1 0 0 / 12%)

Custom CSS Utilities

Selection Color

::selection {
  background: oklch(from var(--primary) l c h / 0.25);
  color: var(--foreground);
}

Custom Scrollbar

.custom-scrollbar {
  scrollbar-width: thin;
  scrollbar-color: oklch(from var(--muted-foreground) l c h / 0.25) transparent;
}

Keyboard Badge

kbd {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  background: var(--muted);
  border: 1px solid var(--border);
}

Animation Tokens

Class Animation Duration
.animate-fade-in-up Fade in + translate up 20px 0.5s ease-out
.animate-fade-in Fade in 0.4s ease
.animate-scale-in Fade in + scale from 0.95 0.3s ease
.animate-float Gentle vertical float 6s infinite
.animate-shimmer Loading shimmer gradient 1.5s infinite
.stagger-1 through .stagger-6 Stagger delays 100ms increments

All animations respect prefers-reduced-motion:

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; }
}