# HTW Design System

**Source of Truth**: `docs/design-tokens.json`
**Visual Reference**: `/public/htw-design-system.html`
**Last Updated**: Apr 2026

---

## 1. Color Palette

### 1a. Brand Colors (Core)

8 colors derived from King Kalakaua's Royal Standard + tech accent.

| Name | Hex | Tailwind Class | Role |
|------|-----|----------------|------|
| **HTW Navy** | `#04153D` | `htw-navy` | Primary brand color (logo). Headers, dark backgrounds, text on light. |
| **Royal Navy** | `#002868` | `htw-royal-navy` | Heritage blue. Gradient base, alternate dark backgrounds. |
| **Royal Gold** | `#FFB81C` | `htw-gold` | Primary CTA buttons, highlights, Hawaiian warmth. |
| **Royal Gold Hover** | `#FFC843` | `htw-gold-hover` | Gold hover/active state. |
| **Royal Green** | `#1B7A5A` | `htw-green` | Nature accent, success states, land (aina). |
| **Neon Cyan** | `#00D4FF` | `htw-cyan` | Tech energy, focus rings, links on dark. |
| **Royal Red** | `#CE1126` | `htw-red` | Error states, destructive actions. Sacred to alii. |
| **White** | `#FFFFFF` | `white` | Primary neutral. Text on dark, backgrounds, breathing room. |

> Use with any Tailwind prefix: `bg-htw-navy`, `text-htw-gold`, `border-htw-cyan`, `from-htw-royal-navy`, etc.

### 1b. Background Colors

| Name | Hex | Tailwind Class | Usage |
|------|-----|----------------|-------|
| **White** | `#FFFFFF` | `bg-white` | Primary page background — default for long-form marketing pages |
| **Solar Cream** | `#FFFAEC` | `bg-htw-sand` | Sparse warm surface for a single contained moment (e.g. a card, callout, or one proof block) — **not** for alternating section bands |
| **HTW Navy** | `#04153D` | `bg-htw-navy` | Heroes, immersive full-bleed moments, and intentional dark CTAs — **not** every other section |
| **Royal Navy** | `#002868` | `bg-htw-royal-navy` | Gradients and deep overlays on dark imagery |

**Section backgrounds (critical):** Do **not** pace a page by alternating white / sand / navy section bands. That reads as brochure wallpaper, not craft. Default to a continuous white (or near-white) canvas. Create rhythm with typography scale, photography, spacing, and emptiness. Use navy or sand only when the reader’s job truly changes (e.g. full-bleed hero, one dark immersive beat, final CTA) — never as a repeating stripe pattern.

### 1c. Neutrals — Light Mode

These are available as Tailwind utility classes: `text-neutral-text-primary`, `bg-neutral-surface-elevated`, `border-neutral-border`, etc.

| Token | Hex | Usage |
|-------|-----|-------|
| `neutral-bg` | `#FFFFFF` | Primary background |
| `neutral-bg-subtle` | `#FFFAEC` | Solar Cream — sparse warm surface, not page-stripe wallpaper |
| `neutral-surface` | `#FFFFFF` | Cards, panels |
| `neutral-surface-elevated` | `#F8FAFC` | Dropdowns, modals, elevated surfaces |
| `neutral-text-primary` | `#0B1220` | Primary text |
| `neutral-text-secondary` | `#334155` | Secondary text |
| `neutral-text-muted` | `#64748B` | Helper text, captions |
| `neutral-border` | `#CBD5E1` | Standard borders |
| `neutral-border-subtle` | `#F1F5F9` | Subtle dividers |

### 1d. Neutrals — Dark Mode

| Token | Hex | Usage |
|-------|-----|-------|
| `neutral-bg` | `#071A2B` | Ocean 900 — primary dark background |
| `neutral-bg-subtle` | `#0B243C` | Ocean 800 — alternate dark background |
| `neutral-surface` | `#0B243C` | Cards, panels |
| `neutral-surface-elevated` | `#12314E` | Elevated surfaces |
| `neutral-text-primary` | `#FFFFFF` | Primary text |
| `neutral-text-secondary` | `#CFE3EE` | Secondary text |
| `neutral-text-muted` | `#5F8FA9` | Helper text |
| `neutral-border` | `#12314E` | Standard borders |
| `neutral-border-subtle` | `#0B243C` | Subtle dividers |

### 1e. Accent Colors

| Name | Light Mode | Dark Mode | Usage |
|------|-----------|-----------|-------|
| **Ocean** | `#007C91` (Deep Teal) | `#22D3EE` (Bright Cyan) | Ocean/water accent |
| **Futuristic** | `#7C3AED` (Ultraviolet) | `#C4B5FD` (Light Violet) | Tech/innovation accent |
| **Warm** | `#F06A6A` (Coral) | `#F06A6A` (Coral) | Warm accent (same both modes) |

### 1f. Status Colors

Available as Tailwind utility classes: `text-status-error`, `bg-status-success`, `border-status-warning`, etc.

| State | Light Mode | Dark Mode | Source |
|-------|-----------|-----------|--------|
| **Success** | `#1B7A5A` | `#5BC6A6` | Royal Green / Light Mint |
| **Warning** | `#F59E0B` | `#FBBF24` | Amber |
| **Error** | `#CE1126` | `#F06A6A` | Royal Red / Coral |
| **Info** | `#00B7D6` | `#22D3EE` | Reef Cyan / Bright Cyan |

### 1g. Calendar Category Colors

Available as Tailwind utility classes (badge usage):  
`bg-calendar-category-*-bg text-calendar-category-*-text border-calendar-category-*-border`

| Category | Background | Text | Border | Notes |
|----------|------------|------|--------|-------|
| Panel / Talk | `#E9F0FF` | `#002868` | `#BFD3FF` | Royal navy-derived |
| Networking / Mixer | `#EAF7F2` | `#1B7A5A` | `#BFE6D5` | Royal green-derived |
| Workshop / Masterclass | `#FFF4D6` | `#8A5A00` | `#FFE19C` | Gold-derived, dark text for contrast |
| Activity / Social | `#FDE8EA` | `#9B1020` | `#F6C8CF` | Royal red-derived |
| Demo / Experiential | `#E3F9FF` | `#007C91` | `#B7EEF9` | Cyan/ocean-derived |
| Hackathon / Pitch | `#E8EDFA` | `#04153D` | `#C8D5F2` | HTW navy-derived |
| Summit / Conference | `#F1EAFF` | `#5B21B6` | `#DCCAFF` | Futuristic accent-derived |

### 1h. Gradient

**Ocean Sunrise** — hero overlays and dark section backgrounds:

```
linear-gradient(90deg, #002868 0%, #0052A3 25%, #5B9FD8 50%, #93C5FD 75%, rgba(147, 197, 253, 0.1) 100%)
```

| Stop | Hex | Note |
|------|-----|------|
| 0% | `#002868` | Royal Navy (brand color) |
| 25% | `#0052A3` | Gradient-only (not a standalone brand color) |
| 50% | `#5B9FD8` | Gradient-only |
| 75% | `#93C5FD` | Gradient-only |
| 100% | `rgba(147, 197, 253, 0.1)` | Fade to transparent |

---

## 2. Typography

### Font Families

| Token | Value | Usage |
|-------|-------|-------|
| `font-inter` | Inter, system-ui, sans-serif | All text (loaded via next/font/google in layout.tsx) |

> Body text uses Inter via the `body` font-family declaration in globals.css. `font-inter` class is available for explicit use.

### Heading Scale

| Level | Mobile | Desktop | Weight | Classes |
|-------|--------|---------|--------|---------|
| **H1** | 48px (`text-5xl`) | 72px (`text-7xl`) | Bold | `text-5xl md:text-7xl font-bold font-inter` |
| **H2** | 30px (`text-3xl`) | 36px (`text-4xl`) | Bold | `text-3xl md:text-4xl font-bold font-inter mb-12` |
| **H3** | 20px (`text-xl`) | 24px (`text-2xl`) | Bold | `text-xl md:text-2xl font-bold font-inter` |

### Body Text (CSS Utility Classes)

| Class | Size | Color | Usage |
|-------|------|-------|-------|
| `.htw-body` | `text-base md:text-lg` | `text-neutral-text-secondary` | Standard paragraphs |
| `.htw-body-sm` | `text-sm md:text-base` | `text-neutral-text-secondary` | Captions, metadata |
| `.htw-section-intro` | `text-lg md:text-xl` | `text-neutral-text-secondary` | Intro text below H2 |
| `.htw-section-intro-xl` | `text-xl md:text-2xl` | `text-neutral-text-secondary` | Large "pop" intro sections |
| `.htw-blockquote` | `text-lg md:text-xl` | `text-neutral-text-secondary italic` | Testimonials, pull quotes |

### Card Geometry

Card proportions are part of the design system and should not be left to content height.

| Card Type | Ratio | Media/Text Split | Usage |
|-----------|-------|------------------|-------|
| Speaker/profile image cards | `4:5` portrait | Overlay text | Speaker grids, carousels, headshots |
| Non-speaker media cards | `5:4` horizontal | `65%` image / `35%` text when separate bands are used | About cards, Experience tiles, Get Involved cards, featured media |
| Proof/testimonial cards | `5:4` horizontal | `65%` quote / `35%` attribution | Testimonial rails and proof cards |

Implementation rules:
- Use `aspect-[4/5]` only for speaker/profile cards.
- Use `aspect-[5/4]` for non-speaker site cards unless a specific component has an approved exception.
- If a `5:4` card has a separate image and copy band, the image must stay between `60%` and `67%` of the card height; copy/action space should stay between `33%` and `40%`.
- Do not let text content determine card height in card decks. Edit copy, clamp text, or reduce text scale before breaking the card ratio.

### Testimonial Card Component

Use `src/components/TestimonialCard.tsx` for reusable testimonial proof cards on the homepage, sponsor pages, reports, and future proof sections.

| Element | Mobile/Base | Desktop | Notes |
|---------|-------------|---------|-------|
| Card | `aspect-[5/4] w-[min(82vw,320px)]` | `aspect-[5/4] w-[400px]` | Locked horizontal proof card |
| Quote row | `65%` | `65%` | Quote is the primary proof content |
| Attribution row | `35%` | `35%` | Avatar/name/title/company/logo live here |
| Quote | `text-sm leading-relaxed` | `text-base leading-relaxed` | Quote is clipped by the fixed row if too long |
| Avatar | `36px` | `40px` | Optional; falls back to initials/name when available |
| Logo box | `84px × 32px` | `104px × 36px` | Optional; strict box prevents layout breakage |
| Logo max | `80px × 24px` | `100px × 28px` | `object-contain`; no overflow |

Component contract:
- `quote` is required.
- `name`, `title`, `company`, `avatarUrl`, `companyLogoUrl`, and `initials` are optional.
- Missing optional fields must not change card dimensions or break the footer.
- Company logo is a secondary proof mark; keep company name as text when present.

### Hero Heading Utility

| Class | Usage |
|-------|-------|
| `.htw-hero-heading` | Applied to all inner-page hero H1s (About, Speakers, Partners, etc.). Change the font in this one class to swap the hero font site-wide. |

### Line Heights

| Token | Value | Usage |
|-------|-------|-------|
| Tight | 1.25 | Headings |
| Normal | 1.5 | Body text |
| Relaxed | 1.625 | Long-form content |

### Font Weights

| Token | Value |
|-------|-------|
| Normal | 400 |
| Semibold | 600 |
| Bold | 700 |

---

## 3. Buttons

### 3a. Variants

| Variant | Background | Text | Border | Usage |
|---------|-----------|------|--------|-------|
| **Primary** | `#FFB81C` (Royal Gold) | `#04153D` (HTW Navy) | `#FFB81C` (color-matched) | Main CTA. Max 1 per section. |
| **Primary Hover** | `#FFC843` | `#04153D` | `#FFC843` | |
| **Secondary Light** | transparent | `#FFFFFF` | `#FFFFFF` | Supporting action on dark backgrounds |
| **Secondary Light Hover** | `#FFFFFF` | `#04153D` | `#FFFFFF` | |
| **Secondary Dark** | `#04153D` | `#FFFFFF` | `#04153D` | Supporting action on light backgrounds |
| **Secondary Dark Hover** | `#04153D/90` | `#FFFFFF` | `#04153D/90` | |
| **Tertiary** | transparent | `#04153D` / `#FFFFFF` | `#04153D` / `#FFFFFF` | Ghost. Cancel, back, low priority. |
| **Tertiary Hover** | `#04153D` | `#FFFFFF` | `#04153D` | Fills on hover. |
| **Outline** | transparent | inherited | `neutral-border` | Subtle supporting action. |
| **Ghost** | transparent | inherited | transparent | Minimal action, no border. |
| **Destructive** | `#CE1126` | `#FFFFFF` | `#CE1126` (color-matched) | Dangerous actions. |

> **Box-model rule**: Every variant uses `border-2` (2px). Solid-fill variants (primary, secondary-dark, destructive) use color-matched borders. This ensures all buttons of the same `size` have identical outer dimensions regardless of variant.

### 3b. Sizes

| Size | Padding | Min Height | Font Size | Usage |
|------|---------|------------|-----------|-------|
| **sm** | `px-5 py-2` (20px / 8px) | 36px | 16px (`text-base`) | Header nav, compact spaces |
| **md** | `px-6 py-3` (24px / 12px) | 44px | 16px (`text-base`) | Default. Most buttons. |
| **lg** | `px-8 py-4` (32px / 16px) | 52px | 18px (`text-lg`) | Hero CTAs, prominent actions |

### 3c. Shared Properties

| Property | Value |
|----------|-------|
| Font weight | 600 (semibold) |
| Text transform | UPPERCASE |
| Border radius | 4px |
| Border width | 2px on ALL variants (solid-fill buttons use color-matched or transparent borders for uniform box-model sizing) |
| Focus ring | `#00D4FF` (Neon Cyan), 2px offset |

---

## 4. Spacing

### Section Padding (Vertical)

| Context | Mobile | Desktop | Classes |
|---------|--------|---------|---------|
| Standard section | 64px | 80px | `py-16 md:py-20` |
| Hero section | 85vh min | 100vh min | `min-h-[85vh] md:min-h-screen` |
| Compact hero | 96px | 96px | `py-24` |

### Container

| Property | Value | Classes |
|----------|-------|---------|
| Max width | 1152px | `max-w-6xl mx-auto` |
| Horizontal padding (mobile) | 16px | `px-4` |
| Horizontal padding (desktop) | 24px | `sm:px-6` |

### Grid Gaps

| Token | Value | Classes |
|-------|-------|---------|
| Default gap | 32px | `gap-8` |
| Large gap | 48px | `gap-12` |

---

## 5. Border Radius

| Token | Value | Usage |
|-------|-------|-------|
| None | 0px | — |
| Button | 4px | All buttons |
| Card | 8px | Cards, modals, panels |
| Large | 12px | Large containers, hero cards |

### Shape System Governance (Rounded vs Squared)

- **Source of truth**: radius decisions are controlled by tokens in `docs/design-tokens.json` (`radius.none`, `radius.button`, `radius.card`, `radius.large`).
- **Implementation order**: update tokens first, then shared components (`Button`, card primitives, `SpeakerProfileCard`), then any page-level one-off classes.
- **Default policy**: avoid hardcoding `rounded-*` values in page code when a shared tokenized component exists.
- **If we switch to squared corners**:
  1. Set relevant radius tokens to `0px` in `docs/design-tokens.json`
  2. Ensure shared components consume tokenized radius values (or `rounded-none`)
  3. Sweep page-level overrides and remove legacy `rounded-lg`/`rounded-xl` classes
  4. Re-validate visual regressions in key surfaces (buttons, cards, modals, hero blocks)

---

## 6. Shadows

| Token | Value | Usage |
|-------|-------|-------|
| **sm** | `0 1px 2px 0 rgba(0,0,0,0.05)` | Subtle depth |
| **base** | `0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06)` | Default cards |
| **md** | `0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06)` | Elevated cards |
| **lg** | `0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05)` | Modals, dropdowns |
| **xl** | `0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04)` | Hero cards, featured |

---

## 7. Transitions & Animation

### Durations

| Token | Value | Usage |
|-------|-------|-------|
| Fast | 150ms | Micro-interactions (hover color change) |
| Base | 300ms | Standard transitions (card lift, button) |
| Slow | 500ms | Complex animations (page transitions) |

### Easing Curves

| Token | Value |
|-------|-------|
| Default | `cubic-bezier(0.4, 0, 0.2, 1)` |
| Ease In | `cubic-bezier(0.4, 0, 1, 1)` |
| Ease Out | `cubic-bezier(0, 0, 0.2, 1)` |
| Ease In-Out | `cubic-bezier(0.4, 0, 0.2, 1)` |

### Scroll Animations

| Element | Animation | Duration | Delay |
|---------|-----------|----------|-------|
| Section headings | Fade up (20px) | 600ms | 0ms |
| Card grids | Staggered fade-in | 600ms | 50ms per card (up to 12) |
| Text blocks | Fade in | 600ms | 0ms |
| Images | Fade + scale (0.95 → 1) | 600ms | 0ms |

### Card Hover States

| Type | Effect | Classes |
|------|--------|---------|
| **Interactive** (clickable) | Lift + border + scale | `hover:-translate-y-2 hover:border-htw-green hover:scale-[1.02] transition-all duration-300` |
| **Featured** (non-linked) | Lift + border | `hover:-translate-y-2 hover:border-htw-green transition-all duration-300` |
| **Informational** (low-priority) | Border change | `hover:border-neutral-border transition-colors duration-200` |
| **Image** (photos, logos) | Scale + brightness | `hover:scale-105 hover:brightness-110 transition-all duration-300` |

---

## 8. Breakpoints

| Token | Width | Tailwind Prefix |
|-------|-------|-----------------|
| sm | 640px | `sm:` |
| md | 768px | `md:` |
| lg | 1024px | `lg:` |
| xl | 1280px | `xl:` |
| 2xl | 1536px | `2xl:` |

---

## 9. Z-Index Scale

| Token | Value | Usage |
|-------|-------|-------|
| Base | 0 | Default stacking |
| Dropdown | 10 | Click-outside backdrops (below sticky) |
| Sticky | 20 | Fixed header, sticky filter bars, FAB buttons, ShareBar |
| Dropdown-on-sticky | 30 | Dropdowns opening from sticky elements (Header menu, filter dropdowns) |
| Backdrop | 40 | Visual overlays (sidebar backdrop) |
| Modal | 50 | Dialogs, sheets, popovers, preview banners |
| Toast | 100 | Toast notifications |

---

## 10. Grid Layouts

| Layout | Classes |
|--------|---------|
| Two column | `grid lg:grid-cols-2 gap-12` |
| Three column | `grid md:grid-cols-2 lg:grid-cols-3 gap-8` |

---

## 11. Components

### Custom HTW Components

| Component | File | Usage |
|-----------|------|-------|
| **Button** | `src/components/ui/button.tsx` | HTW-branded button with `asChild` support. Variants: primary, secondary, secondary-dark, tertiary, link, outline, ghost, destructive. Sizes: sm, md, lg, icon. Use `asChild` with `<Link>` or `<a>` for navigation. |
| **SpeakerProfileCard** | `src/components/SpeakerProfileCard.tsx` | Reusable speaker card system. Variants: `overlay` (portrait image with text overlay + optional social hover icons), `horizontal` (left image + right metadata + optional social row). |
| **ImageWithFallback** | `src/components/ImageWithFallback.tsx` | All images (.avif + .png fallback, lazy loading) |
| **Header** | `src/components/Header.tsx` | Shared site header |
| **Footer** | `src/components/Footer.tsx` | Shared site footer |

### Forms (React Hook Form + shadcn)

**Stack:** [React Hook Form](https://react-hook-form.com/) for client UX, [shadcn/ui Form primitives](https://ui.shadcn.com/docs/components/form) (`FormProvider` as `Form`, `FormField`, `FormItem`, `FormLabel`, `FormControl`, `FormMessage`) wired to RHF, **typed validation helpers** in `src/lib/validation/`, and **route handlers or Server Actions** that validate again before writing to the DB. Prefer **single-column** field stacks on marketing flows unless a spec calls for multi-column layouts.

| Area | Location | Role |
|------|----------|------|
| **Form UI + RHF wiring** | `src/components/ui/form.tsx` | shadcn-style `Form` / `FormField` / `FormMessage` (HTW error + label styling). |
| **Marketing field building blocks** | `src/components/forms/htw-marketing-fields.tsx` | `HtwMarketingTextField`, `HtwMarketingTextareaField`, `HtwMarketingWebsiteField`, `HtwSubmitButton` — compose shadcn `Input` + tokens. |
| **Layout shell** | `src/components/forms/form-shell.tsx` | `<form noValidate>` + section spacing. |
| **Helper copy** | `src/components/forms/field-hint.tsx` | Neutral secondary hint text. |
| **Shared field styles** | `src/lib/forms/htw-marketing-field-styles.ts` | HTW borders/focus rings (error vs OK). |
| **Validation** | `src/lib/validation/*.ts` | Plain functions (e.g. `validate…FormClient`, `validate…Server`) aligned with client + API routes. |

**Rules**

1. Centralize **min/max length, required, URL shape, enums** in `src/lib/validation/`; keep `maxLength` on inputs aligned.
2. **Client:** `useForm` + submit handler that runs validators and `setError`; show errors via `FormMessage`.
3. **Server:** validate POST bodies in route handlers; return `400` with a clear message when invalid.
4. **Files / cross-field rules** (e.g. “logo required if no existing asset”) may use manual `setError` after base field validation.

**Reference implementation:** sponsor onboarding — `src/lib/validation/sponsor-onboard.ts` (`validateSponsorOnboardFormClient`, `validateSponsorOnboardFullServer`, `validateSponsorOnboardPartialServer`) and `src/app/(landing)/sponsor/onboard/page.tsx`.

### shadcn/ui Components (Radix-based)

Located in `src/components/ui/`:

| Component | File | Current Usage |
|-----------|------|---------------|
| Accordion | `accordion.tsx` | FAQ page |
| Badge | `badge.tsx` | Calendar filters |
| Card | `card.tsx` | Available |
| Carousel | `carousel.tsx` | Available |
| Command | `command.tsx` | Available |
| Dialog | `dialog.tsx` | Available |
| Form | `form.tsx` | RHF + shadcn forms (see Forms above) |
| Input | `input.tsx` | Available |
| Label | `label.tsx` | Available |
| Popover | `popover.tsx` | Available |
| Sheet | `sheet.tsx` | Header mobile menu |
| Sonner | `sonner.tsx` | Brand Kit toasts |
| Tabs | `tabs.tsx` | Calendar filters |

### shadcn Theme Variables (How HTW colors flow into shadcn primitives)

shadcn/ui primitives read CSS custom properties from `:root` (light) and `.dark` (dark) — `--primary`, `--border`, `--ring`, `--destructive`, etc. In `src/styles/globals.css` these are **bound directly to HTW design tokens** so primitives render HTW-correct without per-page overrides.

| shadcn variable | Bound to | Resolves to (light) | Used by |
|---|---|---|---|
| `--background` | `--neutral-bg` | `#FFFFFF` | Body, full-page surfaces |
| `--foreground` | `--neutral-text-primary` | `#0B1220` | Default text |
| `--card`, `--popover` | `--neutral-surface` / `-elevated` | `#FFFFFF` / `#F8FAFC` | `Card`, `Dialog`, `Popover` bg |
| `--primary` | `--brand-primary` | `#04153D` (HTW Navy) | Checkbox-checked fill, switch-on, calendar selected day, default `Button` bg |
| `--secondary`, `--muted`, `--accent` | `--neutral-border-subtle` | `#F1F5F9` | Subtle fills, hover surfaces |
| `--muted-foreground` | `--neutral-text-muted` | `#64748B` | Helper / placeholder text |
| `--destructive` | `--status-error` | `#CE1126` (Royal Red) | `aria-invalid` ring, destructive Button |
| `--border`, `--input` | `--neutral-border` | `#CBD5E1` | All shadcn primitive borders |
| `--ring` | `--focus-ring` | `#00D4FF` (HTW Cyan) | Focus rings on inputs, buttons, links |

**Important: `--primary` is Navy, not Gold.** shadcn uses `--primary` for *selection-fill* semantics (checkbox checked, switch on, etc.) where high contrast on white matters. The HTW Gold CTA aesthetic lives in our **custom `Button` component** (`src/components/ui/button.tsx`) via `variant="primary"`, which uses Tailwind classes (`bg-htw-gold`) directly — independent of `--primary`. Don't try to make shadcn `--primary` Gold; you'll break checkbox/switch contrast.

**Rules**

1. **Don't duplicate token stacks on individual pages.** If you find yourself writing `border-neutral-border focus:ring-htw-cyan` to make a shadcn primitive look HTW-branded, the work is already done — drop the overrides. The marketing flows currently keep them via `htw-marketing-fields.tsx` for layout reasons (`h-11`, `text-sm`, `rounded-lg`); those layout-only tweaks are fine, but **color/border/focus overrides are no longer necessary**.
2. **HTW tokens are the source of truth.** If you need to change a brand color, update the relevant `--brand-*` / `--neutral-*` / `--status-*` token in the `@theme inline` block. shadcn vars will follow automatically via the `var()` references in `:root`.
3. **For new shadcn primitives**, add them with `npx shadcn add` (or copy from upstream) and they'll inherit HTW styling on first render. No tweaks required.

---

## 12. Page Structure

Every page follows this order:

1. `<Head>` — SEO (title, description, OG tags)
2. `<Header />` — shared site header
3. Hero section (if applicable)
4. Content sections (`py-16 md:py-20`, `max-w-6xl mx-auto px-4 sm:px-6`)
5. `<Footer />` — shared site footer

**Pacing:** Prefer one continuous canvas. Do not invent visual rhythm by striping `bg-white` / `bg-htw-sand` / `bg-htw-navy` section after section. Hierarchy comes from type, image, and space — see §1b.

---

## 13. How to Add or Change a Color

1. **Define in `docs/design-tokens.json`** — add the color with `value`, `type`, and `description`. This is the source of truth.
2. **Add to `src/styles/globals.css`** — add a `--color-<name>: #hex;` line inside the `@theme inline` block. This creates Tailwind utility classes (`bg-<name>`, `text-<name>`, `border-<name>`, etc.).
3. **Update this file** (`DESIGN_SYSTEM.md`) — document the new color in the relevant section above.
4. **Check contrast** — verify WCAG AA compliance (4.5:1 for text, 3:1 for UI) using [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/).
5. **Test** — run `npm run build` to verify, then check visually in the browser.

To remove a color, search the codebase first (`rg "color-name" src/`), then reverse steps 1-3.

---

## Quick Reference

| Task | Reference |
|------|-----------|
| All token values | `docs/design-tokens.json` |
| Visual preview | `/public/htw-design-system.html` |
| Feature specs | `docs/spec-template.md` |
