# Design System — Renfield

This file is the source of truth for visual + interaction decisions in Renfield. Every UI change should reference it. If a decision feels missing, add it here before writing the code that needs it.

Generated by `/design-consultation` on 2026-04-19.

---

## Product Context

- **What this is:** A self-hosted, fully offline-capable digital assistant for households. Voice satellites in every room. Multi-user from day one. Local LLMs via Ollama.
- **Who it's for:** Households (not productivity workers at desks). Multi-generational, multi-user. The kitchen is a primary interaction surface.
- **Space/industry:** Personal AI / household assistant / second-brain. Adjacent: Home Assistant, Mem.ai, Reflect, Obsidian, Tana, Capacities. None of those are direct competitors — Renfield is the only one that is voice-first, multi-user, and household-scoped.
- **Project type:** Web app (React + Vite + Tailwind CSS 4) + PWA + voice satellite hardware. Frontend serves as both the admin/management surface AND the chat UI.
- **Strategic direction:** Becoming the framework for both Home + Enterprise (Reva). Tier-agnostic access model with optional federation between Renfield instances.

---

## Aesthetic Direction

- **Direction:** **WARM EDITORIAL** — household-modernist with serif gravitas
- **Decoration level:** INTENTIONAL — light grain on cream surfaces, no decorative blobs / gradients / icons-in-circles
- **Mood:** Should feel like opening a well-worn family recipe book — warm, intentional, slightly precious. NOT clinical productivity SaaS.

**Why this differentiates:** Every PKM/second-brain product (Mem.ai, Reflect, Tana, Capacities, Craft, Bear) converges on clinical sans-serif aesthetics designed for individual knowledge workers at desks. Renfield's user is in the kitchen with their family asking about Granny's recipe. The product lives in the home, not at a desk. Crimson + cream + Cormorant serif is the competitive moat — leaning into warmth signals "this is for HOME, not work" instantly.

**Reference points (NOT to copy, to compare against):**
- Apple Books (warm reading aesthetic, serif in app UI)
- Bear notes (intentional warmth, not clinical)
- Craft (polished, but more clinical than we want)
- Mem.ai (design-forward, but clinical sans)
- Home Assistant 2026.x dashboard (the household-product positioning we share)

---

## Typography

Tokens live in `src/frontend/src/index.css`.

| Role | Font | CSS variable | Notes |
|---|---|---|---|
| Display / headings ≥24px | **Cormorant Variable** (serif) | `--font-display` | Premium, warm, NOT generic. Falls back to Georgia → Times New Roman → serif |
| Body / paragraph / chat / atom text | **DM Sans Variable** (sans) | `--font-sans` | Highly readable at all sizes; also used for UI controls. Falls back to system-ui → -apple-system → sans-serif |
| UI controls (buttons, labels, form fields) | **DM Sans Variable** | `--font-sans` | Same as body. NEVER serif on controls — serifs render badly at small sizes |
| Data / tables / numeric displays | **DM Sans Variable** with `font-variant-numeric: tabular-nums` | `--font-sans` + utility class | Tabular numerals for aligned columns |
| Code / pre / inline code | **JetBrains Mono** (recommended; not yet loaded — add via `@import` or self-host) | TBD `--font-mono` | Add when first code-rendering surface ships |

### Type scale (4px base, modular)

```
xs    12px   captions, badges, tertiary text
sm    14px   body small, dense lists
base  16px   body default
lg    18px   intro paragraphs, emphasized body
xl    24px   subheadings — Cormorant kicks in here
2xl   30px   page titles — Cormorant
3xl   36px   hero subheadings — Cormorant
4xl   48px   marketing hero — Cormorant
5xl   64px   marketing hero, large displays — Cormorant
```

### Weight + style

- Cormorant: 400 (regular) for most display, 500-600 (medium) for emphasis, 700 (bold) only for marketing hero. Italic Cormorant is gorgeous — use sparingly for editorial pull-quotes.
- DM Sans: 400 (regular) body, 500 (medium) labels and emphasis, 700 (bold) reserved for buttons + critical UI.

### Rules

- **Cormorant ONLY at 24px+.** Below that, serifs render thin and lose legibility.
- Body NEVER uses serif — DM Sans always.
- Don't mix more than 2 type families on a single screen (Cormorant + DM Sans is the system; JetBrains Mono only when actually rendering code).
- Tabular nums for any data table or counter ("237 atoms").

---

## Color

Tokens live in `src/frontend/src/index.css`. NEVER hardcode hex values in components. Always reference CSS variables or Tailwind utility classes.

### Brand palette (already locked in code)

**Primary — Crimson** (warm, emotional, household-warm)
```
50   #fef2f3   lightest pink, hover backgrounds
100  #fde6e8
200  #fbd0d5
300  #f7a4ae
400  #f06e7e
500  #e63e54   ★ BRAND PRIMARY — buttons, links, branding moments
600  #c41e3a
700  #a5162f   ★ TIER 0 (self) — deepest crimson, most intimate
800  #8a162c
900  #76162b   darkest, rarely used
```

**Accent — Turquoise** (cool counterpoint, "open" semantic)
```
50   #edfff9   lightest mint, hover backgrounds
100  #d5fff1
200  #aefee4
300  #71fbd0   ★ TIER 3 (extended) — light turquoise
400  #00ffd0
500  #00e4b8   ★ ACCENT — focus rings, info highlights
600  #00ba98
700  #00937c   ★ TIER 4 (public) — deep turquoise, most open
800  #007464
900  #005f53
```

**Neutral — Cream + Tailwind grays**
```
cream  #f0e6d3   ★ TIER 2 (household) — hearth, warmth-of-home
       Also used for: surface backgrounds in light mode, cards, calm panels
```

For UI backgrounds beyond cream + crimson + turquoise, use Tailwind's neutral gray scale (`gray-50`..`gray-900` from Tailwind 4 defaults). NO new gray scale invented.

### Semantic colors (derived from existing palette — no new hues)

| State | Color | Variable | Rationale |
|---|---|---|---|
| **Success** | `--color-accent-600` #00ba98 | deep turquoise | Healthy/complete maps to the open/cool axis |
| **Info** | `--color-accent-500` #00e4b8 | brand turquoise | Same axis, brighter for informational |
| **Warning** | `--color-primary-300` #f7a4ae on `--color-cream` background, with `--color-primary-700` text | light crimson + cream | Attention without alarm. Soft pink alert against warm background. |
| **Error** | `--color-primary-700` #a5162f text on `--color-primary-50` #fef2f3 background | deep crimson on lightest pink | Visceral red for stop/danger. |

This is a **2-axis semantic system** (warm = stop/attention; cool = success/info). Distinct from the dominant 4-color (red/yellow/green/blue) convention but coherent with the brand palette.

### Tier visual language (per second-brain-circles design)

5 concentric privacy tiers, mapped to the existing palette + symbols (color is NEVER alone — always with symbol + label):

| Tier | Symbol | Color | Variable | Meaning |
|---|---|---|---|---|
| 0 SELF | `█` | `--color-primary-700` #a5162f | deep crimson | most private, owner-only |
| 1 TRUSTED | `●` | `--color-primary-500` #e63e54 | brand crimson | 1-3 closest people |
| 2 HOUSEHOLD | `○` | `--color-cream` #f0e6d3 | hearth cream | family/housemates |
| 3 EXTENDED | `◐` | `--color-accent-300` #71fbd0 | light turquoise | named outsiders (grandparents, friends) |
| 4 PUBLIC | `◯` | `--color-accent-700` #00937c | deep turquoise | anyone |

Direction: warm/inner → cool/outer. Depth = warmth + saturation contrast.

**Dark mode:** Tier 2 cream flips to `--color-gray-200` (#e5e7eb) for contrast. Others have sufficient contrast in both modes (verify with WCAG-AA contrast checker before shipping).

---

## Dark Mode Strategy

- All components MUST use Tailwind `dark:` variants. Hardcoded colors are forbidden (per CLAUDE.md rule).
- Strategy: REDESIGN surfaces, don't just invert. Cream becomes deep warm gray (`gray-900` with slight warm tint if possible). Crimson stays approximately the same hue but shifts to `--color-primary-400` for primary actions in dark mode (more vibrant against dark surfaces). Turquoise accent stays.
- Saturation reduction: dark mode generally drops saturation 10-20% to avoid eye strain.
- Test every new component in BOTH modes. Mockups should show both side-by-side.

---

## Spacing

**Base unit: 4px. Density: COMFORTABLE.**

```
2xs   2px    hairline, micro adjustments
xs    4px    icon padding, tight grouping
sm    8px    chip padding, list item internal
md    16px   default content spacing, between paragraphs
lg    24px   between sections within a card
xl    32px   between cards, between major content blocks
2xl   48px   page section breaks
3xl   64px   page hero / above-the-fold whitespace
4xl   96px   marketing site rhythm
```

**Why comfortable not compact:** Renfield is content-rich (atoms, KG facts, conversation history) AND uses serif headlines. Both want breathing room. Compact spacing fights both.

---

## Layout

- **Approach:** HYBRID — editorial for marketing site (renfield.de), grid-disciplined for the app (`/brain`, `/settings/circles`, all 19 existing pages).
- **Grid:** 12-column for desktop, 6-column for tablet, 1-column for mobile (Tailwind defaults).
- **Max content width:** 1280px for app pages (existing convention); 1080px for marketing-style content (longer-form reading).
- **Sidebar nav width:** 280px desktop, drawer on tablet/mobile.
- **NEVER center body content.** Marketing hero text can be center-aligned; app content is left-aligned (per AI slop blacklist #4).

### Border radius scale

```
none   0px      modals' top edge, harsh transitions
sm     4px     buttons, form inputs, badges
md     8px     cards, secondary surfaces
lg     12px   primary cards, atom rows, prominent containers
xl     16px   feature panels, hero cards
full   9999px tier badges (circles), avatars, pills
```

NEVER use uniform-bubbly-large-radius on every element (AI slop pattern #5). Differentiate intentionally: small things get small radius; large things get bigger; circles are for round things.

### Shadow scale

```
none    no shadow
sm      0 1px 2px 0 rgb(0 0 0 / 0.05)         subtle elevation, hover states
md      0 4px 6px -1px rgb(0 0 0 / 0.1)       cards, dropdowns
lg      0 10px 15px -3px rgb(0 0 0 / 0.1)     modals, prominent elevation
xl      0 20px 25px -5px rgb(0 0 0 / 0.1)     overlays, hero panels
2xl     0 25px 50px -12px rgb(0 0 0 / 0.25)   deep modals, focused dialogs
```

Reuse Tailwind's defaults — they're well-calibrated. Don't invent decorative shadows.

---

## Motion

- **Approach:** INTENTIONAL — purposeful entrance + state transitions, no scroll-driven theatrics.

### Existing animation tokens (in `index.css` — DON'T re-define)

| Token | Use case |
|---|---|
| `--animate-pulse-slow` | Idle state of voice-active satellite indicators |
| `--animate-slide-in-right` | Atom row expand-on-hover (per circles design) |
| `--animate-fade-slide-in` | Brain Review Queue card entrance, list item arrival |
| `--animate-typing-dot` | Federated query progress chrome ("asking Mom's brain..."), chat thinking states |
| `--animate-gentle-pulse` | Subtle attention indicator (e.g., new captured atom in queue) |
| `--animate-stagger` | Sequential entrance for list items (50ms cascade) |

### New tokens to add (gap-fill)

```css
/* Easing */
--ease-enter:  cubic-bezier(0, 0, 0.2, 1);     /* ease-out — things appearing */
--ease-exit:   cubic-bezier(0.4, 0, 1, 1);     /* ease-in — things leaving */
--ease-move:   cubic-bezier(0.4, 0, 0.2, 1);   /* ease-in-out — things repositioning */

/* Duration */
--dur-micro:   75ms;    /* hover state changes, instant feedback */
--dur-short:   200ms;   /* atom row expand, tier picker selection */
--dur-medium:  350ms;   /* modal open, page transition */
--dur-long:    600ms;   /* major state change, celebration moments */

/* Tier promotion celebration (NEW — per circles design Pass 7) */
--animate-tier-promote: tier-promote var(--dur-short) var(--ease-enter);
@keyframes tier-promote {
  0%   { transform: scale(1);    opacity: 1; }
  50%  { transform: scale(1.05); opacity: 0.9; }
  100% { transform: scale(1);    opacity: 1; }
}
```

### Rules

- Respect `prefers-reduced-motion: reduce` — already wired in `index.css` for the existing tokens; new tokens MUST follow the same pattern.
- No scroll-jacking. Scroll-linked animation is allowed for marketing pages only and only for parallax-style depth, not content-blocking effects.
- Never animate `width` or `height` directly (use `transform: scale` instead — GPU accelerated).

---

## Component Vocabulary

Existing component classes in `src/frontend/src/index.css` (per CLAUDE.md):
- `.card`
- `.input`
- `.btn-primary`
- `.btn-secondary`

### New component classes to add (per circles design + this DESIGN.md)

```css
.tier-badge       /* small filled circle with tier symbol; 12px diameter; full radius */
.tier-ring        /* 4px-wide left-edge tier color accent on atom rows */
.tier-picker      /* 5-segment selector with symbol + label per segment */
.atom-row         /* list-row pattern with hover-expand affordance */
.atom-row--expanded  /* expanded state — full text + tier picker + actions */
.activity-feed-item  /* federation activity feed entry */
.pairing-qr-modal /* 3-step pairing handshake modal container */
.toast            /* undo toast (5s window for destructive actions) */
.empty-state      /* empty state container — warm copy + primary CTA pattern */
```

Each new class MUST: (a) use only DESIGN.md tokens, (b) have explicit `dark:` variants, (c) honor `prefers-reduced-motion`, (d) be referenced by ONE name throughout the codebase (no `.atom-card` and `.atom-row` fighting for the same concept).

---

## Internationalization

- Languages: German (`de`) + English (`en`). Files: `src/frontend/src/i18n/locales/de.json` and `en.json`.
- New i18n keys MUST be added to BOTH files in the same commit (per CLAUDE.md rule).
- Tier labels render from i18n keys (`circle.tier.0` through `circle.tier.4`), NEVER stored in DB rows.
- German is the primary language for development (per project memory: user prefers gehobeneres Deutsch, Fachtermini beibehalten).

---

## Accessibility

Non-negotiable for every new component.

- **Color is never the only signal** — symbol + label + ARIA description always co-present (especially for tier visual).
- **Touch targets ≥44×44px** on all interactive elements.
- **WCAG-AA contrast** verified for every color pair (especially crimson on cream — verify with axe DevTools or Chrome Lighthouse before shipping).
- **Keyboard nav** for everything. Drag-drop has a keyboard alternative (e.g., "Move to..." button opens picker).
- **Focus indicators** use `--color-accent-500` turquoise (high contrast against crimson + cream).
- **ARIA roles + landmarks** correctly applied. Use semantic HTML first, ARIA second.
- **Screen reader announcements** for streaming progress chunks via `aria-live="polite"` (debounce to once per ~2s to avoid noise).
- **`prefers-reduced-motion`** respected — animations degrade gracefully or omit.
- **`prefers-color-scheme`** respected — dark mode auto-detects + manual toggle.

---

## AI Slop Blacklist (NEVER include in any Renfield UI)

Per the design-review skill's catalog. If you find any of these in our code, rip them out.

1. **Purple/violet/indigo gradients** as backgrounds or color schemes — alien to our crimson/turquoise/cream identity
2. **3-column feature grid** with icons in colored circles repeated symmetrically — most recognizable AI-slop pattern
3. **Icons in colored circles** as section decoration (we use tier badges, which ARE filled circles, but they're FUNCTIONAL not decorative)
4. **Centered everything** (`text-align: center` on all body content) — left-aligned for app, optional center for marketing hero text only
5. **Uniform bubbly border-radius** on every element — use the differentiated scale above
6. **Decorative blobs / floating circles / wavy SVG dividers** — if a section feels empty, fix the content
7. **Emoji as design elements** in headings or as bullet points — content-only emoji where actually useful, never as decoration
8. **Colored left-border on cards** as a generic "accent" — different from our intentional 4px tier-color left edge on atom rows (which IS the access signal)
9. **Generic hero copy** ("Welcome to Renfield", "Unlock the power of...", "Your all-in-one solution for...") — write specific, product-grounded copy
10. **Cookie-cutter section rhythm** (hero → 3 features → testimonials → pricing → CTA) on marketing pages — write content first, then arrange

---

## Decisions Log

| Date | Decision | Rationale |
|---|---|---|
| 2026-04-19 | Initial DESIGN.md created from existing implicit system | `/design-consultation` formalized what was already in `index.css`. No pivot — locked in crimson + turquoise + cream + Cormorant + DM Sans. Added gap-fills: spacing scale, radius/shadow scale, motion tokens, semantic colors derived from existing palette, tier visual language, AI slop blacklist. |
| 2026-04-19 | Eureka: Renfield's warm-editorial aesthetic differentiates from clinical PKM/second-brain category | Every PKM app converges on Inter + minimal-color. Renfield is a household product, not a desktop product. Lean into warmth as competitive moat. (Logged to `~/.gstack/analytics/eureka.jsonl`) |
| 2026-04-19 | Semantic colors derived from existing palette (no new hues) | User instruction: "use what we have already." 2-axis system (warm = stop/attention, cool = success/info) instead of conventional 4-color. |
| 2026-04-19 | Tier visual language locked: 5 concentric tiers with symbol + color + label | Per second-brain-circles design review. Color never alone (WCAG-AA + colorblind-safe). |
| 2026-04-19 | Cormorant restricted to 24px+ display only | Below 24px serifs lose legibility on screens. Body always DM Sans. |

---

## How to use this file

- **Before any UI change:** read DESIGN.md.
- **Before adding a color, font, animation, or component pattern:** check if it exists here. If yes, use the token. If no, ask whether it belongs here BEFORE writing the code that needs it.
- **In code reviews:** `/review` and `/plan-design-review` skills both reference this file. Deviations from DESIGN.md should be flagged.
- **In QA mode:** `/design-review` and `/qa` skills check live UI against DESIGN.md.
- **When this file feels wrong:** update it (ideally via `/design-consultation` rerun or `/plan-design-review`). Don't deviate silently.
