# Core Design Knowledge Base

> Five-domain deep knowledge: Typography, Color, Spatial Design, Motion, Interaction. Each domain contains principles, concrete values, DO/DON'T, and code examples. Content focuses on actionable engineering constraints and aesthetic judgment, serving oh-my-design workflows and quality gates.

---

## Domain 1: Typography

### Core Principles

**Typography is the skeleton of design.** A page with perfect color and motion still fails entirely if typography is poor. Typography determines information readability, hierarchy, and emotional tone.

### Modular Type Scale System

Don't arbitrarily pick font sizes. Choose a ratio, use `clamp()` or fixed `rem` to generate a complete scale.

| Level | Usage | Ratio 1.25 | Ratio 1.333 | Notes |
|-------|-------|------------|-------------|-------|
| xs | Auxiliary text, timestamps | 0.64rem (10px) | 0.56rem (9px) | Minimum readable size |
| sm | Secondary labels, caption | 0.8rem (13px) | 0.75rem (12px) | |
| base | Body text | 1rem (16px) | 1rem (16px) | **Minimum body size** |
| lg | Small heading, emphasis | 1.25rem (20px) | 1.333rem (21px) | |
| xl | H3 | 1.563rem (25px) | 1.777rem (28px) | |
| 2xl | H2 | 1.953rem (31px) | 2.369rem (38px) | |
| 3xl | H1 | 2.441rem (39px) | 3.157rem (51px) | |
| 4xl | Hero | 3.052rem (49px) | 4.209rem (67px) | Marketing pages only |

**5 sizes cover 90% of needs**: xs / sm / base / lg / xl (plus one hero if needed)

### Font Pairing Strategy

**Most cases, one font family is enough.** Weight contrast (900 vs 200) is more powerful than font quantity.

When pairing, create contrast across multiple axes:

| Strategy | Heading | Body | Effect |
|----------|---------|------|--------|
| Geometric + Humanist | Space Grotesk | DM Sans | Modern + Warm |
| Serif + Sans-serif | Fraunces | Inter Variable | Elegant + Readable |
| Display + System UI | Clash Display | -apple-system | Strong contrast + Performance |
| Monospace + Sans-serif | JetBrains Mono | Manrope | Technical + General |

**AI Slop Warning**: Avoid Inter + Roboto combo. If you need Inter's neutrality, use Instrument Sans or Plus Jakarta Sans instead.

### Line Height and Line Length

```
Line length 45-75 characters (use ch unit)
  max-inline-size: 65ch;  /* Body ideal value */

Line height inversely proportional to line length:
  Line length 45-55ch → line-height: 1.65
  Line length 55-65ch → line-height: 1.55
  Line length 65-75ch → line-height: 1.45
  Headings have short line length → line-height: 1.1-1.25
```

### Web Font Loading Strategy

```css
/* Correct @font-face declaration */
@font-face {
  font-family: "Satoshi";
  src: url("/fonts/satoshi-var.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap; /* Critical: avoid FOIT */
}

/* size-adjust fallback prevents layout shift */
@font-face {
  font-family: "Satoshi-fallback";
  src: local("Arial");
  size-adjust: 100.06%;
  ascent-override: 95%;
  descent-override: 25%;
  line-gap-override: 0%;
}
```

### Vertical Rhythm

```css
:root {
  --line-height: 1.55;
  --rhythm: calc(1rem * var(--line-height)); /* ~25px — base unit for all vertical spacing */
}

/* All vertical spacing is rhythm multiples */
h2 { margin-block-end: calc(var(--rhythm) * 2); } /* 50px */
p  { margin-block-end: var(--rhythm); }            /* 25px */
section { padding-block: calc(var(--rhythm) * 4); } /* 100px */
```

### OpenType Features

```css
/* Tabular numeric alignment (amounts, data) */
.tabular-data { font-variant-numeric: tabular-nums; }

/* Small caps (labels, categories) */
.label { font-variant-caps: all-small-caps; }

/* Diagonal fractions (recipes, measurements) */
.fraction { font-variant-numeric: diagonal-fractions; }
```

---

## Domain 2: Color

### Core Principles

**Color is the strongest emotional tool.** Limit palette, use OKLCH color space, tint all neutral grays.

### OKLCH Color Space

OKLCH is perceptually uniform. Same chroma change looks consistent across all hues.

```css
:root {
  /* Primary — 3-5 lightness levels */
  --primary-50:  oklch(0.97 0.02 260);
  --primary-100: oklch(0.93 0.04 260);
  --primary-500: oklch(0.55 0.2 260);   /* Brand primary */
  --primary-600: oklch(0.45 0.22 260);
  --primary-900: oklch(0.25 0.12 260);

  /* Neutral grays — 9-11 levels, with brand hue tint */
  --gray-50:  oklch(0.97 0.01 260);  /* Note chroma=0.01, subtle tint */
  --gray-100: oklch(0.93 0.01 260);
  --gray-500: oklch(0.55 0.01 260);
  --gray-900: oklch(0.20 0.01 260);

  /* Semantic colors — 4 colors × 2-3 levels */
  --success: oklch(0.65 0.17 145);
  --warning: oklch(0.75 0.15 80);
  --error:   oklch(0.55 0.22 25);
  --info:    oklch(0.60 0.15 240);
}
```

### Tinted Neutral Grays

This is the watershed between professional and amateur design:

```css
/* Amateur: pure gray */
--gray-500: oklch(0.55 0 0);  /* Lifeless */

/* Professional: with brand hue tint */
--gray-500: oklch(0.55 0.01 260);  /* Subtle blue tone */
```

**Rule**: All neutral grays add 0.005-0.015 chroma of brand hue.

### Palette Structure

```
Primary:       3-5 lightness levels — brand recognition
Neutral:       9-11 levels — backgrounds and text
Semantic:      4 colors × 2-3 levels — status feedback
Surface:       2-3 levels — card/panel depth
```

**Max 2-4 non-neutral colors**. More than 4 colors = palette失控.

### 60-30-10 Rule (Visual Weight, Not Pixel Count)

```
60% — Primary tone (usually neutral/background)
30% — Secondary color (usually primary or surface)
10% — Accent (CTA, important actions, focus)
```

### Dark Mode

**Dark mode is not inverted light mode.**

```css
/* DO */
:root[data-theme="dark"] {
  --bg:      oklch(0.15 0.01 260);  /* Not pure black */
  --surface: oklch(0.20 0.01 260);  /* Brighter surface = closer */
  --text:    oklch(0.90 0.01 260);  /* Not pure white */
  --accent:  oklch(0.65 0.15 260);  /* Desaturate */
  --heading: oklch(0.95 0.01 260);  /* Headings can be brighter */
}

/* DON'T */
/* Pure black background #000 */
/* High-saturation accents */
/* Same font weights as light mode (dark needs -100-200) */
/* Invert all colors */
```

### Alpha Transparency Design Smell

```css
/* Design smell: using alpha overlay instead of explicit color */
background: rgba(0, 0, 255, 0.1);  /* Behaves differently on different backgrounds */

/* Correct approach: define explicit surface colors */
background: var(--primary-50);  /* Consistent on any background */
```

---

## Domain 3: Spatial Design

### Core Principles

**Space is design material, not "whitespace".** Space creates hierarchy, guides attention, conveys quality.

### 4pt Base Spacing System

```
Spacing tokens (semantic naming):
--space-xs:  4px   (0.25rem)  — Icon and text spacing
--space-sm:  8px   (0.5rem)   — Same-group element spacing
--space-md:  16px  (1rem)     — Standard spacing
--space-lg:  24px  (1.5rem)   — Paragraph spacing
--space-xl:  48px  (3rem)     — Section spacing
--space-2xl: 96px  (6rem)     — Large section separation

Why 4pt not 8pt?
8pt is too coarse — can't express 12px tight spacing.
4pt gives 4/8/12/16/20/24/32/48/64/96, covering all needs.
```

### Tight Clustering vs Generous Separation

**Core design rhythm**: Tight between elements (8-12px) expresses "we're a group", generous between groups (48-96px) expresses "this is a new topic".

```
[Heading]       ←── Tight 8px ──→  [Subtitle]
                              ←── Generous 48px ──→
[Next heading]  ←── Tight 8px ──→  [Subtitle]
```

**Squint Test**: Blur your vision, if you can't see white lines separating groups, group spacing isn't large enough.

### Flexbox vs Grid Decision

```
One-dimensional arrangement (row or column) → Flexbox
  Navigation, toolbar, tag group, form row

Two-dimensional layout (rows and columns) → Grid
  Card grid, dashboard, gallery, complex forms

Self-adjusting grid (generic card layout):
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-lg);
```

### Card Overuse

**Not all content needs cards.** Cards are grouping tools, not default layout.

```
Needs cards: Independent content units (products, articles, users)
Doesn't need cards: Continuous content (article body, settings form, timeline)

Alternatives:
- Spacing grouping (adjacent elements tight, distant elements generous)
- Dividers (minimal, not dominating)
- Background color change (surface level change)
```

### Container Queries

```css
/* Component-level responsive — doesn't depend on viewport width */
.card-container {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card { grid-template-columns: 200px 1fr; }
}
```

### Optical Alignment Adjustment

```css
/* Icon visual centering (not mathematical centering) */
.icon { translate: 0 -0.05em; }

/* Text and icon alignment */
.icon + span { translate: -0.1em; }

/* Touch target: Visual 24px, clickable 44px */
.touch-target::before {
  content: "";
  position: absolute;
  inset: -10px;
}
```

---

## Domain 4: Motion Design

### Core Principles

**Motion has purpose: guide attention, confirm actions, maintain context.** Purposeless motion is noise.

### 100/300/500 Duration Rule

| Duration Range | Usage | Example |
|----------------|-------|---------|
| 50-150ms | Instant feedback | Button hover, toggle switch, focus change |
| 150-300ms | State change | Expand/collapse, tab switch, modal open |
| 300-500ms | Layout change | Page transition, list reflow, filter results |
| 500-800ms | Entrance animation | Element first appearance, hero animation |

**Exit ~75% faster than entry**: Close = Open × 0.75

### Easing Curves

```css
/* Default easing — best choice for almost all scenarios */
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);

/* Need stronger deceleration */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);

/* Entrance (sliding in from off-screen) */
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);

/* Never use */
/* bounce, elastic, ease-in (pure ease-in is amateur sign) */
```

### Animation Property Limits

```css
/* Only animate these two properties — GPU accelerated, 60fps guaranteed */
.element {
  transition: transform 0.2s var(--ease-out-quart),
              opacity 0.2s var(--ease-out-quart);
}

/* Need height animation? Use this technique */
.expandable {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.3s var(--ease-out-quart);
}
.expandable.open {
  grid-template-rows: 1fr;
}
```

### Staggered Animation

```css
.list-item {
  animation: fadeIn 0.3s var(--ease-out-quart) both;
  animation-delay: calc(var(--i, 0) * 50ms);
}

/* HTML: <li style="--i: 0">...</li> <li style="--i: 1">...</li> */
```

### Perceived Performance

```
80ms Rule: >80ms without feedback = "lagging"
  → Optimistic update: Update UI first, sync in background
  → Preload: Prefetch on hover
  → Skeleton: Show structure immediately, then fill content

Peak-End Effect:
  → Use ease-in compression at end, perceived faster completion
```

### prefers-reduced-motion (Non-Optional)

```css
/* Must support — affects ~35% of adults over 40 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
```

---

## Domain 5: Interaction Design

### Core Principles

**Interaction is the interface's language.** Every state is a conversation; missing states = ignoring users.

### Eight-State System

| State | Trigger | Required Style | Priority |
|-------|---------|----------------|----------|
| Default | Initial | Base style | Required |
| Hover | Mouse over | Subtle change (shadow/translate/scale) | Required (desktop) |
| Focus | Keyboard focus | Focus ring | Required |
| Active | Pressing | Press effect (scale 0.98 / shadow reduce) | Required |
| Disabled | Not operable | Reduced opacity + cursor: not-allowed | Required |
| Loading | Waiting response | Spinner / skeleton / progress bar | Required |
| Error | Action failed | Red mark + fix instructions | Required |
| Success | Action succeeded | Green confirmation (brief) | Recommended |

### Focus Management

```css
/* Correct focus style */
:focus-visible {
  outline: 2px solid var(--primary-500);
  outline-offset: 2px;
}

/* Don't do this */
/* :focus { outline: none; }  — Never remove focus style without replacement */
/* :focus-visible { outline: none; }  — Equals no focus */

/* Roving Tabindex (in-component keyboard navigation) */
/* radio group, tab list, toolbar internal */
```

### Form Design

```html
<!-- DO: Visible label -->
<label for="email">Email address</label>
<input type="email" id="email" placeholder="you@example.com" />

<!-- DON'T: Placeholder as label -->
<input type="email" placeholder="Email address" />

<!-- Validation timing: validate on blur, not real-time -->
<!-- Error message: Below field, red, explain problem and fix method -->
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="pw-error" />
<p id="pw-error" role="alert">Password needs at least 8 characters. Currently missing 3.</p>
```

### Modal/Dialog

```html
<!-- Use native <dialog> + inert attribute -->
<dialog id="confirm">
  <form method="dialog">
    <p>Confirm deleting this project?</p>
    <button value="cancel">Cancel</button>
    <button value="delete">Delete</button>
  </form>
</dialog>

<!-- When dialog open, background content set to inert -->
<div inert>
  <!-- Main page content becomes non-interactive -->
</div>
```

### Popover API

```html
<!-- Tooltip / Dropdown menu -->
<button popovertarget="menu">Menu</button>
<div id="menu" popover>
  <ul>
    <li><a href="/settings">Settings</a></li>
    <li><a href="/profile">Profile</a></li>
  </ul>
</div>
```

### Undo > Confirmation Dialog

```
User presses "Delete" → Immediately delete + show "Deleted. Undo?"
Better than
User presses "Delete" → Popup "Confirm delete?" → User presses "Confirm" → Delete

Reason: Confirmation dialogs interrupt workflow; most users don't read, just press confirm.
```

### Gesture Discoverability

**Never rely on gestures as sole interaction method.**

```
OK: Swipe delete + Edit button → Delete
Not OK: Only swipe can delete, no visible delete button

OK: Two-finger pinch for large view + Click view button
Not OK: Only two-finger pinch for large view
```

---

## Cross-Domain Integration: Design System Integration

### Token Layers

```
Primitive (Raw)      →  Semantic (Meaning)    →  Component (Usage)
oklch(0.55 0.2 260)  →  --color-primary       →  --button-bg
                      →  --color-interactive   →  --link-color
                      →  --color-danger        →  --alert-bg
```

### When to Use Which Domain

```
Creating new page: Typography first → Spatial layout → Color fill → Interaction complete → Motion embellish
Optimizing existing page: Score → Identify weak domains → Targeted fix → Re-score
Brand upgrade: Color redefine → Typography adjust → Spatial/motion adapt → Interaction upgrade
```