# Mini-EPD Style Guide & UX

> Geëxtraheerd uit de mini-epd-prototype codebase. Gebruik dit document om dezelfde look & feel in een ander project toe te passen.

---

## 1. Tech Stack & Tooling

| Categorie | Keuze | Versie |
|---|---|---|
| Framework | Next.js (App Router) | 14.2 |
| Taal | TypeScript | 5.x |
| Styling | Tailwind CSS | 3.4 |
| Component variants | `class-variance-authority` (CVA) | 0.7 |
| Class merging | `tailwind-merge` | 3.4 |
| Animaties | `tailwindcss-animate` + Framer Motion | 1.0 / 12.x |
| UI primitives | Radix UI | diverse |
| Iconen | Lucide React | 0.553 |
| State management | Zustand | 5.x |
| Formulieren | React Hook Form + Zod | 7.x / 4.x |
| Rich text | TipTap | 3.x |

### Utility helper

```ts
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
```

---

## 2. Kleurensysteem

### 2.1 Basiskleuren

| Token | Hex | Gebruik |
|---|---|---|
| `app-background` | `#F8FAFC` | Pagina-achtergrond (slate-50) |
| `surface` | `#FFFFFF` | Cards, panels |
| `surface-sub` | `#F1F5F9` | Secundaire achtergrond (slate-100) |
| `text-primary` | `#0F172A` | Primaire tekst (slate-900) |
| `text-secondary` | `#475569` | Secundaire/meta-tekst (slate-600) |
| `border` | `#E2E8F0` | Standaard borders (slate-200) |

### 2.2 Brand (Teal-first)

De primaire brandkleur is **teal**. Alle interactieve elementen, focus-states en links gebruiken deze kleur.

| Token | Hex | Ratio | Gebruik |
|---|---|---|---|
| `brand-50` | `#F0FDFA` | — | Subtiele achtergrond |
| `brand-100` | `#CCFBF1` | — | Info-subtiel |
| `brand-200` | `#99F6E4` | — | Lichte tint |
| `brand-400` | `#2DD4BF` | — | Decoratief |
| `brand-500` | `#14B8A6` | — | Accent |
| `brand-600` | `#0D9488` | 3:1 | UI-componenten (non-text) |
| **`brand-700`** | **`#0F766E`** | **5.47:1** | **Primaire tekst & CTA (WCAG AA) ✓** |
| `brand-800` | `#115E59` | — | Hover state |
| `brand-900` | `#134E4A` | — | Donkerste tint |

```css
/* CSS custom properties */
--color-brand: #0F766E;
--color-brand-hover: #115E59;
--color-brand-active: #0D9488;
--color-brand-subtle: #F0FDFA;
```

### 2.3 AI Features (Amber)

AI-gerelateerde acties worden visueel onderscheiden door een **amber** kleurenpalet.

| Token | Hex | Gebruik |
|---|---|---|
| `ai-50` | `#FFFBEB` | Subtiele AI-achtergrond |
| `ai-500` | `#F59E0B` | Primaire AI-kleur |
| `ai-600` | `#D97706` | AI-tekst (WCAG AA large) |
| `ai-700` | `#B45309` | AI hover |

### 2.4 Module-accenten

Verschillende modules hebben een eigen kleurig accent:

| Module | Achtergrond | Accent | Border |
|---|---|---|---|
| Afspraken | `#E8F8EF` | `#16A34A` (groen) | `#CDECDC` |
| Medicatie | `#FEF6DC` | `#F59E0B` (amber) | `#F6E7B6` |
| Lab | `#FFEBDC` | `#F97316` (oranje) | `#FFD2B8` |

### 2.5 Status & Feedback

| Status | Kleur | Subtiel |
|---|---|---|
| Success | `#16A34A` | `#ECFDF5` |
| Warning | `#EAB308` | `#FEFCE8` |
| Error | `#DC2626` | `#FEF2F2` |
| Info | `#0F766E` (teal) | `#CCFBF1` |

### 2.6 Severity Badges (DSM-light)

| Ernst | Achtergrond | Tekst |
|---|---|---|
| Low | `#E5E7EB` | `#374151` |
| Medium | `#FEF3C7` | `#92400E` |
| High | `#FEE2E2` | `#991B1B` |

### 2.7 Dark Mode

Dark mode is optioneel geïmplementeerd (MVP = licht thema):

```css
.dark {
  --color-bg: #0a0a0a;
  --color-surface: #1a1a1a;
  --color-text: #ededed;
  --color-text-secondary: #a1a1a1;
  --color-border: #333333;
}
```

---

## 3. Typografie

### 3.1 Font Families

Drie fonts worden lokaal geladen via `next/font/local`:

| Variabele | Font | Gewichten | Gebruik |
|---|---|---|---|
| `--font-serif` | **Lora** | 400, 400i, 600 | Long-form content, manifesto teksten |
| `--font-sans` | **Roboto** | 400, 500, 600 (+italic) | UI, navigatie, metadata, body |
| `--font-mono` | **Source Code Pro** | 400, 600 | Code, technische details, nummers |

**Body default:** `var(--font-sans), system-ui, -apple-system, sans-serif`

### 3.2 Typografische Schaal

| Token | Waarde | Toepassing |
|---|---|---|
| `--text-hero` | `clamp(2.5rem, 6vw, 4rem)` | Hero quotes |
| `--text-h1` | `clamp(2rem, 5vw, 3rem)` | Sectie-koppen |
| `--text-h2` | `clamp(1.5rem, 4vw, 2.5rem)` | Subsecties |
| `--text-body` | `1.25rem` | Content, lopende tekst |
| `--text-small` | `0.875rem` | Metadata, labels |

### 3.3 Line Heights

| Token | Waarde | Gebruik |
|---|---|---|
| `--line-height-tight` | `1.2` | Headings |
| `--line-height-relaxed` | `1.8` | Body/content |

---

## 4. Shadows & Border Radius

### Shadows

| Token | Waarde |
|---|---|
| `shadow-sm` | `0 1px 2px rgba(15,23,42,0.06)` |
| `shadow-md` | `0 2px 6px rgba(15,23,42,0.08)` |
| `shadow-lg` | `0 8px 20px rgba(15,23,42,0.10)` |

> Alle shadows zijn gebaseerd op **slate-900** alpha — geen hard zwart.

### Border Radius

| Token | Waarde |
|---|---|
| `--radius` | `0.625rem` (10px) |
| `rounded-lg` | `var(--radius)` |
| `rounded-md` | `calc(var(--radius) - 2px)` ≈ 8px |
| `rounded-sm` | `calc(var(--radius) - 4px)` ≈ 6px |

---

## 5. Formulieren

| State | Property | Waarde |
|---|---|---|
| Default | bg | `#FFFFFF` |
| Default | border | `#CBD5E1` |
| Default | tekst | `#0F172A` |
| Placeholder | kleur | `#94A3B8` |
| Hover | border | `#94A3B8` |
| Focus | ring/border | `#0F766E` (teal-700) |
| Disabled | bg | `#F1F5F9` |
| Disabled | tekst | `#94A3B8` |
| Invalid | border | `#DC2626` |
| Invalid | tekst | `#B91C1C` |

**Input component patroon:**
```tsx
<input className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1
  text-base shadow-sm transition-colors placeholder:text-muted-foreground
  focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
  disabled:cursor-not-allowed disabled:opacity-50 md:text-sm" />
```

---

## 6. Component Patronen

### 6.1 Component Architectuur

- Alle componenten gebruiken **`React.forwardRef`** voor ref-forwarding
- Varianten via **`class-variance-authority`** (CVA)
- Styling via Tailwind classes + `cn()` utility
- Radix UI als headless primitives (Dialog, Tabs, Select, Popover, etc.)
- **Default = server component**; `"use client"` alleen wanneer interactiviteit vereist is

### 6.2 Button

| Variant | Stijl |
|---|---|
| `default` | `bg-primary text-primary-foreground hover:bg-primary/90` |
| `destructive` | `bg-destructive text-destructive-foreground hover:bg-destructive/90` |
| `outline` | `border border-input bg-background hover:bg-accent` |
| `secondary` | `bg-secondary text-secondary-foreground hover:bg-secondary/80` |
| `ghost` | `hover:bg-accent hover:text-accent-foreground` |
| `link` | `text-primary underline-offset-4 hover:underline` |

| Size | Afmetingen |
|---|---|
| `default` | `h-10 px-4 py-2` |
| `sm` | `h-9 px-3` |
| `lg` | `h-11 px-8` |
| `icon` | `h-10 w-10` |

### 6.3 AI Button

Speciaal component voor AI-acties. Visueel onderscheiden door **amber gradient**.

| Variant | Stijl |
|---|---|
| `default` | Amber gradient (`from-amber-600 to-amber-700`) + witte tekst |
| `outline` | `border-2 border-amber-500`, tekst `amber-700` |
| `ghost` | Transparant, tekst `amber-700`, hover `amber-50` |

Features:
- Sparkle-icoon (✨) als visuele AI-indicator
- Loading state met `Loader2` spinner
- Drie maten: `sm`, `md`, `lg`

### 6.4 Card

```
┌─────────────────────────────┐
│ CardHeader      (p-6)       │
│   CardTitle     (semibold)  │
│   CardDescription (muted)  │
│ CardContent     (p-6 pt-0) │
│ CardFooter      (p-6 pt-0) │
└─────────────────────────────┘
```
- `rounded-xl`, `border`, `bg-card`, `shadow`

### 6.5 Badge

Varianten: `default`, `secondary`, `destructive`, `outline`  
Base: `rounded-md`, `px-2.5 py-0.5`, `text-xs font-semibold`

### 6.6 Tabs

- `TabsList`: `rounded-lg bg-muted p-1`
- `TabsTrigger`: `rounded-md px-3 py-1 text-sm font-medium`
- Active state: `bg-background text-foreground shadow`

### 6.7 Toast

- Positie: top op mobile, bottom-right op desktop
- Swipe-to-dismiss ondersteuning
- Slide-in animatie (top op mobile, bottom op desktop)
- Varianten: `default` en `destructive`

---

## 7. Layout & Navigatie

### 7.1 App Shell

```
┌──────────────────────────────────────┐
│ ┌──────────┐ ┌─────────────────────┐ │
│ │          │ │                     │ │
│ │ Sidebar  │ │   Main Content      │ │
│ │ (fixed)  │ │   (scrollable)      │ │
│ │          │ │                     │ │
│ │          │ │                     │ │
│ └──────────┘ └─────────────────────┘ │
└──────────────────────────────────────┘
```

- **Container**: `min-h-screen bg-slate-50 flex`
- **Sidebar**: fixed, `w-78` open / `w-28` collapsed
- **Main content**: flex-grow, scrollable

### 7.2 Sidebar UX

| Eigenschap | Waarde |
|---|---|
| Desktop breedte (open) | `w-78` (312px) |
| Desktop breedte (collapsed) | `w-28` (112px) |
| Achtergrond | `bg-white` |
| Border | `border-r border-slate-200` |
| Transition | `duration-300 ease-in-out` |
| Mobile | Full overlay met `bg-black/40 backdrop-blur-sm` |

**Active nav item**: `bg-teal-50 text-teal-700` + icoon `text-teal-600`  
**Inactive nav item**: `text-slate-600 hover:bg-slate-50 hover:text-slate-900`

**Collapsed state**: tooltips verschijnen links met een pijl-indicator (`bg-slate-800 text-white`)

**Profiel sectie**: avatar cirkel, naam, rol, online-indicator (`bg-green-500` dot)  
**Logout**: `text-red-600 hover:bg-red-50`

---

## 8. Animaties

### 8.1 Float Animatie

Subtiele zweef-animatie voor badges of decoratieve elementen:

```css
@keyframes float {
  0%, 100% { transform: translateY(0px) rotate(0deg); }
  25%      { transform: translateY(-5px) rotate(0.5deg); }
  50%      { transform: translateY(-3px) rotate(-0.5deg); }
  75%      { transform: translateY(-7px) rotate(0.3deg); }
}
.animate-float { animation: float 5s ease-in-out infinite; }
```

### 8.2 Artifact Slide-in

Panel slide-in van rechts:

```css
@keyframes artifact-enter {
  from { transform: translateX(100%); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}
.artifact-enter { animation: artifact-enter 200ms ease-out; }
```

### 8.3 Transition Defaults

- Navigatie / sidebar: `transition-all duration-300 ease-in-out`
- Buttons / interactie: `transition-colors` of `transition-all duration-200`
- Toasts: slide-in + fade via `tailwindcss-animate`

### 8.4 Reduced Motion

Volledige `prefers-reduced-motion` ondersteuning:

```css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.02ms !important;
    transition-duration: 0.03ms !important;
    scroll-behavior: auto !important;
  }
}
```

---

## 9. Toegankelijkheid (A11y)

| Aspect | Implementatie |
|---|---|
| Focus indicator | `outline: 2px solid var(--color-brand)`, `outline-offset: 2px` |
| Focus ring (components) | `ring-2 ring-ring ring-offset-2` |
| Skip to main | Verborgen link, zichtbaar bij focus |
| Kleurcontrast | Brand teal-700 = 5.47:1 op wit (WCAG AA ✓) |
| ARIA labels | Alle interactieve elementen (toggle buttons, sidebar) |
| Reduced motion | Alle animaties gerespecteerd |
| Iconen | `aria-hidden="true"` op decoratieve iconen |
| Taal | `<html lang="nl">` |

---

## 10. AI UX Conventies

AI-functies worden visueel onderscheiden van standaard UI:

| Element | Conventie |
|---|---|
| Kleur | Amber-palet (geel/goud), nooit teal |
| Button | `AIButton` component met Sparkle-icoon (✨) |
| Highlight | `.ai-source-highlight` — lichtgeel (`#fef08a`) met `border-radius: 2px` |
| Loading | `Loader2` spinner (animatie: `animate-spin`) |
| Feedback | Confidence indicators bij AI-gegenereerde content |

---

## 11. Quick-Start Checklist

Om deze stijl in een nieuw project over te nemen:

1. **Installeer dependencies:**
   ```bash
   pnpm add class-variance-authority clsx tailwind-merge tailwindcss-animate
   pnpm add lucide-react framer-motion
   pnpm add @radix-ui/react-dialog @radix-ui/react-tabs @radix-ui/react-select
   # + overige Radix primitives naar behoefte
   ```

2. **Kopieer fonts** (Lora, Roboto, Source Code Pro) naar `public/fonts/` en configureer in `layout.tsx`

3. **Kopieer CSS custom properties** uit `globals.css` (sectie `:root`)

4. **Kopieer Tailwind config** — met name `colors`, `boxShadow`, `borderRadius` extensies

5. **Kopieer `cn()` utility** naar `lib/utils.ts`

6. **Kopieer UI components** uit `components/ui/` (shadcn-patroon met CVA)

7. **Zet `antialiased`** op de `<body>` tag

8. **Zet `lang="nl"`** op de `<html>` tag

---

*Gegenereerd op basis van de mini-epd-prototype codebase (maart 2026).*
