File size: 23,063 Bytes
0d73e33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
---
name: พระไตรปิฎก มจร.  Tipitaka Reader
description: Digital reader for the MCU Pali Tipitaka canon with full-text search and AI assistance
colors:
  primary: "#c8860a"
  primary-deep: "#9a6307"
  primary-light: "#e8b84a"
  indigo-bg: "#1a1a2e"
  indigo-deep: "#0f0f1e"
  indigo-surface: "#222242"
  neutral-cream: "#fdfaf5"
  neutral-cream-dark: "#f5edd8"
  neutral-paper: "#faf7f2"
  neutral-warm-white: "#f8f6f0"
  text-dark: "#1a1a1a"
  text-soft: "#555555"
  text-muted: "#888888"
  text-light: "#e0e0e0"
  border-light: "#e0d0b0"
  border-dark: "#3a3a5e"
  highlight-bg: "#fff3cd"
  success-bg: "#e8f5e9"
  info-bg: "#e3f2fd"
typography:
  display:
    fontFamily: "Sarabun, 'Noto Serif Thai', 'Noto Sans Thai Looped', sans-serif"
    fontSize: "clamp(1.2rem, 2vw, 1.6rem)"
    fontWeight: 700
    lineHeight: 1.3
    letterSpacing: "0.02em"
  body:
    fontFamily: "Sarabun, 'Noto Serif Thai', 'Noto Sans Thai Looped', sans-serif"
    fontSize: "17px"
    fontWeight: 400
    lineHeight: 2.1
    letterSpacing: "normal"
  label:
    fontFamily: "Sarabun, 'Noto Sans Thai Looped', sans-serif"
    fontSize: "0.82em"
    fontWeight: 600
    lineHeight: 1.4
    letterSpacing: "0.04em"
rounded:
  sm: "4px"
  md: "6px"
  lg: "8px"
  xl: "12px"
spacing:
  xs: "4px"
  sm: "8px"
  md: "16px"
  lg: "24px"
  xl: "32px"
components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.neutral-warm-white}"
    rounded: "{rounded.md}"
    padding: "10px 20px"
  button-secondary:
    backgroundColor: "transparent"
    textColor: "{colors.text-light}"
    rounded: "{rounded.md}"
    padding: "10px 20px"
  button-secondary-hover:
    backgroundColor: "{colors.indigo-surface}"
    textColor: "{colors.primary}"
    rounded: "{rounded.md}"
  card:
    backgroundColor: "{colors.neutral-cream}"
    textColor: "{colors.text-dark}"
    rounded: "{rounded.md}"
    padding: "8px 12px"
  reader-panel:
    backgroundColor: "{colors.neutral-cream}"
    textColor: "{colors.text-dark}"
    rounded: "{rounded.lg}"
    padding: "24px 32px"
    maxWidth: "70ch"
    lineHeight: 2.1
  page-marker:
    textAlign: "center"
    textColor: "{colors.text-muted}"
    fontSize: "0.82em"
    margin: "32px 0"
    letterSpacing: "0.04em"
  nav-drawer:
    width: "320px"
    widthMobile: "100%"
    backgroundColor: "{colors.indigo-bg}"
    tabs: ["toc", "search", "overview"]
    animation: "slide-in from left"
  ai-fab:
    size: "56px"
    shape: "circle"
    position: "fixed bottom-24px right-24px"
    backgroundColor: "{colors.primary}"
    iconColor: "{colors.neutral-warm-white}"
    hoverScale: 1.05
    activeScale: 0.95
  ai-popup:
    width: "420px"
    maxHeight: "70vh"
    position: "fixed above ai-fab"
    bottomOffset: "96px"
    rightOffset: "24px"
    draggable: true
    minimizable: true
    backgroundColor: "{colors.neutral-paper}"
    rounded: "{rounded.lg}"
  ai-message-user:
    backgroundColor: "{colors.info-bg}"
    textColor: "{colors.text-dark}"
    rounded: "{rounded.xl}"
    padding: "8px 12px"
  ai-message-assistant:
    backgroundColor: "{colors.success-bg}"
    textColor: "{colors.text-dark}"
    rounded: "{rounded.xl}"
    padding: "8px 12px"
  right-toolbar:
    width: "44px"
    position: "fixed right-0"
    backgroundColor: "{colors.indigo-surface}"
    buttonSize: "44px"
    iconColorRest: "{colors.text-muted}"
    iconColorActive: "{colors.primary}"
    dividerColor: "{colors.border-dark}"
    opacityScrolling: 0.2
    opacityRest: 1.0
    scrollStopDelay: "1.5s"
    hoverZone: "60px"
themes:
  dark:
    description: "Default — Indigo Midnight shell, Parchment reader"
    shell: "{colors.indigo-bg}"
    nav: "{colors.indigo-bg}"
    reader: "{colors.neutral-cream}"
    ai-panel: "{colors.indigo-deep}"
  light:
    description: "Warm white shell, paper reader"
    shell: "{colors.neutral-warm-white}"
    nav: "{colors.neutral-cream-dark}"
    reader: "{colors.neutral-paper}"
    ai-panel: "{colors.neutral-cream-dark}"
  classic:
    description: "Parchment throughout — closest to printed scripture"
    shell: "{colors.neutral-cream-dark}"
    nav: "{colors.neutral-cream}"
    reader: "{colors.neutral-cream}"
    ai-panel: "{colors.neutral-paper}"
---

# Design System: พระไตรปิฎก มจร. — Tipitaka Reader

## 1. Overview

**Creative North Star: "The Dhamma Light" (แสงแห่งธรรม)**

A digital scripture reader that feels like light illuminating ancient wisdom. The interface is a quiet chamber — indigo walls, warm golden accents, and cream-paper reading surfaces. Every design decision bends toward one purpose: making the sacred text the most prominent thing on screen.

This system explicitly rejects:
- SaaS dashboard aesthetics (cards with badges, data-heavy chrome, progress bars)
- AI-first UIs where the chatbot dominates the experience
- Dark mode as a gamer-aesthetic choice (dark surfaces exist but are subdued, not dramatic)
- Anything that competes with readability — animated backgrounds, neon accents, decorative floating elements

The app has two modes of being: **reading** (the user is deep in text — controls fade, AI is closed) and **exploring** (the user is searching or browsing — panels open, navigation is present). The design prioritizes the reading state.

### Key Characteristics

- **Tonal layering, not shadows.** Depth is conveyed through shifts in background lightness, not drop shadows. The reader surface is the lightest layer; navigation panels are progressively darker.
- **Typography-led hierarchy.** Scale and weight contrast carry the information architecture. Color is supplementary, not structural.
- **Generous rhythm.** Line height, padding, and margins are spacious — this is text meant for slow, contemplative reading, not rapid scanning.
- **The accent is earned.** Gold appears on interactive elements, highlights, and active states — never as decoration. Its rarity signals "this is actionable."

## 2. Colors: The Indigo & Gold Palette

The palette pairs a deep indigo architecture (nav, sidebar, backgrounds) with warm cream for reading surfaces and gold for interaction. The contrast between cool indigo and warm cream+gold creates a serene, focused atmosphere.

### Primary

- **Dhamma Gold** (`#c8860a` / oklch(0.62 0.12 68)): The sole accent color. Used for active states, hover borders, icons, highlight markers, and page pills. Never applied to more than 10% of any surface. Its golden warmth echoes the ink of illuminated manuscripts.

### Neutral

- **Indigo Midnight** (`#1a1a2e` / oklch(0.18 0.04 280)): App shell and navigation background. A very dark blue-black that reads as black but has subtle cool character.
- **Indigo Void** (`#0f0f1e` / oklch(0.12 0.03 280)): The deepest layer — AI panel, footer areas. Conveys depth below the navigation layer.
- **Indigo Surface** (`#222242` / oklch(0.22 0.05 280)): Hover state for navigation items, secondary card backgrounds.
- **Parchment Cream** (`#fdfaf5` / oklch(0.96 0.01 75)): The reading surface. Warm off-white reminiscent of aged paper. Used for reader panel and cards in classic/light mode.
- **Cream Dark** (`#f5edd8` / oklch(0.93 0.02 75)): Hover state for reading-surface items. Also used for active result cards.
- **Warm Paper** (`#faf7f2` / oklch(0.95 0.01 75)): Alternative reading background, slightly cooler than Parchment Cream. Used for AI panel and secondary surfaces.

### Semantic

- **Text Dark** (`#1a1a1a`): Primary body text on light surfaces.
- **Text Soft** (`#555555`): Secondary text, section headers.
- **Text Muted** (`#888888`): Metadata, timestamps, page numbers.
- **Text Light** (`#e0e0e0`): Text on dark surfaces.
- **Border Cream** (`#e0d0b0`): Borders on light/classic surfaces.
- **Border Indigo** (`#3a3a5e`): Borders on dark surfaces.
- **Highlight Yellow** (`#fff3cd`): Search result highlighting in text.
- **Message User Blue** (`#e3f2fd`): User chat bubble background.
- **Message Assistant Green** (`#e8f5e9`): AI chat bubble background.

### Named Rules

**The Gold Rarity Rule.** Gold appears on ≤5% of any given screen. Its role is signal, not ornament. If an element is not interactive or active, it should not be gold.

**The Parchment Priority Rule.** The reader surface is always the lightest element on screen, regardless of theme. Even in dark mode, the reader background lifts by one tonal step.

## 3. Typography

**Display & Body Font:** Sarabun (with 'Noto Serif Thai', 'Noto Sans Thai Looped' fallback)

Sarabun is a modern Thai sans-serif with excellent readability at body sizes. Its open counters and generous ascenders accommodate Thai tone marks and Pali diacritics without crowding. The font is native to the Thai web ecosystem (Google Fonts) and renders reliably across platforms.

**Character:** Warm, legible, undistracting. Sarabun at 17px with 2.1 line-height creates a rhythm that matches the cadence of Pali chanting — spacious enough for the eye to rest between lines.

### Hierarchy

- **Display** (700, clamp(1.2rem, 2vw, 1.6rem), 1.3): Volume titles, section headings in the TOC. Large enough to anchor a panel, never dramatic.
- **Headline** (600, 1.2rem, 1.4): Panel headers ("ผลการค้นหา", "เลือกเล่มที่ต้องการอ่าน").
- **Title** (600, 1rem, 1.4): Card titles, result headers.
- **Body** (400, 17px / 1rem, 2.1): The primary reading size. Capped at 70ch max-width on the reader panel. Line height of 2.1 is deliberate — Thai script needs vertical breathing room for tone marks above and below characters.
- **Label** (600, 0.82em, 1.4, 0.04em letter-spacing): Metadata, page numbers, section references. Uppercase in Thai context via CSS text-transform.

### Named Rules

**The Sarabun Solitude Rule.** No secondary font. Sarabun serves every role from display to label. Mixing fonts would add visual chatter to a system whose job is to disappear.

## 4. Elevation

The system uses **tonal layering exclusively** — depth is conveyed by varying background lightness, never by box shadows. This is deliberate: shadows create the illusion of floating cards, which contradicts the manuscript-like reading experience. Instead, surfaces feel like stacked paper.

The z-order from deepest to lightest:
1. **AI panel / background chrome** — darkest indigo (`#0f0f1e`)
2. **Sidebar / navigation** — dark indigo (`#1a1a2e`)
3. **Card / hover surfaces** — indigo surface (`#222242`) on dark; cream dark (`#f5edd8`) on light
4. **Reader panel** — lightest cream (`#fdfaf5`) — always the brightest surface

### Named Rules

**The Flat-By-Default Rule.** Every surface is flat at rest. Tonal shifts appear only in response to state — hover, active, focus. No card shadows, no floating elements, no elevated buttons.

## 5. Components

### Buttons

- **Shape:** Rounded rectangle with 6px radius. Consistent across all variants.
- **Primary:** Gold fill (`#c8860a`), white text. Used for the primary action on any panel — "ค้นหา", "ส่งคำถาม". Hover: deeper gold (`#9a6307`). Height: 44px minimum.
- **Secondary:** Transparent fill, border matching current theme's border color. Used for navigation, toggle, and utility actions. Hover: gold border + indigo surface background. Active: translateY(-1px) micro-motion.
- **Icon-only:** Transparent, same geometry. Used in sidebar icon mode. Active variant uses gold border.
- **Ghost (TOC/List items):** Full-width, text-align left, transparent. Hover: gold text + tinted background.

### Cards (Search Results / TOC)

- **Shape:** 6px radius, 1px border matching theme border color. Left border is not used as accent (avoiding side-stripe anti-pattern per design law).
- **Resting:** Transparent or panel-matching background. Text at body weight.
- **Active:** Gold border + lighter background tint. No shadow.
- **Internal spacing:** 8px top/bottom, 12px left/right.

### Reader Panel

- **Shape:** 8px radius, no border (breathes within its column). Background is always the lightest surface on screen.
- **Header:** Section title + volume/page pill in gold. Separated from text by a thin border.
- **Typography:** 17px body, 2.1 line-height, 70ch max-width. Content is left-aligned (Thai/Pali reads left-to-right).
- **Search highlighting:** `mark` element with highlight yellow background + gold underline.

### AI Chat Panel (inside AIPopup)

- **Container:** 8px radius popup, floating above the FAB — never a permanent column.
- **User message bubble:** Light blue (`#e3f2fd`) background, 12px radius (bottom-right corner flattened to 4px).
- **Assistant message bubble:** Light green (`#e8f5e9`) background, 12px radius (bottom-left corner flattened to 4px).
- **Thinking indicator:** Italic, muted text above assistant messages when in reasoner mode.
- **Input:** Full-width text input with 44px height, gold focus ring.

### Right Reading Toolbar

Vertical strip fixed to the right edge of the viewport. The sole home for all reading-flow controls. Never in the NavDrawer — these need to be reachable without opening a panel.

**Layout (top to bottom):**

```
┌────────┐
│ หน้า N │  ← page pill (current page, tappable to jump)
│  / 532 │  ← total pages, muted
├────────┤
│   ^    │  ← previous page
│   v    │  ← next page
├────────┤
│   ↑    │  ← scroll to top
│  A+    │  ← increase font size
│  A−    │  ← decrease font size
│  ☀/🌙 │  ← cycle theme (dark → light → classic)
└────────┘
```

- **Width:** 44px. Each button is 44 × 44px (touch minimum).
- **Background:** Indigo Surface (`#222242`) in dark theme — one step lighter than the shell, reads as a contained strip.
- **Dividers:** 1px `border-dark` (`#3a3a5e`) between groups. No divider between A+ and A−.
- **Icon color:** Text Muted (`#888888`) at rest; Dhamma Gold (`#c8860a`) on hover/active.
- **Page pill:** Gold text on dark surface. Tapping opens an inline number input for direct page jump (no modal).
- **Auto-hide:** Fades to 20% opacity when the user is actively scrolling. Returns to full opacity on scroll-stop (1.5s) or when cursor enters the 60px right edge zone.
- **No shadow.** Sits flush against the right viewport edge — tonal contrast with the reader panel is sufficient separation.
- **Theme toggle icon:** Changes to reflect current theme — ☀ (dark), 🌙 (light), 📜 (classic).

### Page Marker (Continuous Scroll Divider)

Appears between pages in the continuous scroll reading experience. It is purely informational — never a control.

- **Layout:** Centered, full reader-column width.
- **Text:** "— หน้า N —" in Text Muted (`#888888`), label scale (0.82em), 0.04em letter-spacing.
- **Margin:** 32px top and bottom — generous breathing room signals a boundary without breaking rhythm.
- **No border, no rule.** The text alone is sufficient. A horizontal rule would add visual weight where only a pause is needed.

### NavDrawer (Navigation Sidebar)

Three tabs: **TOC** (table of contents), **Search**, **Overview**. Slides in from the left.

- **Width:** 320px on desktop; 100% viewport width on mobile with an overlay backdrop.
- **Background:** Indigo Midnight (`#1a1a2e`) in dark/default theme — one tonal step lighter than the app shell.
- **Tabs:** Full-width tab strip at top, gold underline on active tab. No icon-only tab bar — labels are always visible.
- **Behavior:** On desktop, the drawer can push the reader or overlay it (user preference). On mobile, always overlays with a semi-transparent backdrop.
- **Close target:** The backdrop itself is tappable to close on mobile; a ✕ button is present at top-right for keyboard users.

### AI Floating Action Button (FAB)

The sole entry point to the AI assistant. Presence at bottom-right is persistent when AI is closed; it disappears when the popup is open (replaced by the popup's close control).

- **Size:** 56 × 56px circle. Minimum touch target met without padding hacks.
- **Background:** Dhamma Gold (`#c8860a`). This is the only gold surface in the UI — it earns its prominence.
- **Icon:** Lotus or spark glyph in warm white. No text label (position and color are sufficient affordance).
- **Hover:** scale(1.05), color deepens to `#9a6307`. Ease-out-quart, 150ms.
- **Active:** scale(0.95), 80ms. Communicates physical press.
- **Unread indicator:** 8px dot in amber at top-right of button. Only when the AI has a response the user hasn't seen.
- **No shadow.** Tonal layering rule applies — the gold surface against the indigo background creates sufficient contrast without elevation.

### AI Popup

Opens above the FAB. Draggable by its title bar. Never full-screen on desktop.

- **Default position:** `bottom: 96px; right: 24px` (24px gap above FAB).
- **Size:** 420px wide, max-height 70vh. On mobile: 100vw − 16px margin each side, anchored to bottom.
- **Draggable:** Title bar drag handle (cursor: grab). Constrained to viewport bounds.
- **States:** Open (full), Minimized (title bar only, ~48px tall), Closed (FAB only).
- **Background:** Warm Paper (`#faf7f2`) — lighter than indigo shell, slightly darker than reader panel. Reads as a floating layer without a shadow.
- **Title bar:** "✨ ผู้ช่วยธรรมะ" left-aligned, minimize (—) and close (✕) right-aligned.
- **Quick Actions:** Shown on first open, before any message. Four preset buttons in a 2×2 grid: อธิบายให้เข้าใจง่าย, สรุปใจความสำคัญ, วิเคราะห์หลักธรรม, ประยุกต์ใช้ในชีวิต. Plus a free-text input below.
- **Mode toggle:** fast / reasoner — compact toggle in title bar area. Not prominent; scholars who need it will find it.

### Highlight / Mark

- **Shape:** 3px radius, no padding for inline highlights.
- **Color:** Highlight yellow (`#fff3cd`) background in light mode, amber-gold (`#4a3c10`) in dark mode.
- **Weight:** Bolded to distinguish from surrounding text.
- **Animation:** Subtle pulse-in on appearance (400ms ease-out-quart).

## 6. Themes

Three named themes. Dark is the default — the physical scene is a scholar at a desk in a dim monastery library, warm lamp to the right, the screen the primary light source.

| Token | Dark (default) | Light | Classic |
|---|---|---|---|
| Shell | Indigo Midnight `#1a1a2e` | Warm White `#f8f6f0` | Cream Dark `#f5edd8` |
| NavDrawer | Indigo Midnight `#1a1a2e` | Cream Dark `#f5edd8` | Parchment Cream `#fdfaf5` |
| Reader | Parchment Cream `#fdfaf5` | Warm Paper `#faf7f2` | Parchment Cream `#fdfaf5` |
| AI Panel | Indigo Void `#0f0f1e` | Cream Dark `#f5edd8` | Warm Paper `#faf7f2` |
| Body text | Text Dark `#1a1a1a` | Text Dark `#1a1a1a` | Text Dark `#1a1a1a` |
| Nav text | Text Light `#e0e0e0` | Text Dark `#1a1a1a` | Text Soft `#555555` |

**Switching:** Via the theme toggle button (☀/🌙/📜) in the Right Reading Toolbar — bottom of the toolbar strip, always visible.

## 7. Do's and Don'ts

| Do | Don't |
|---|---|
| Use gold sparingly — only for interactive/active elements | Add gold borders to every card "for consistency" |
| Keep the reader panel as the lightest surface | Use shadows to elevate the reader above the background |
| Let typography carry the hierarchy | Rely on color alone to distinguish headings from body |
| Use generous line height (2.1) for Thai/Pali text | Squeeze text to fit more content on screen |
| Close AI panel when not in active use | Let the AI panel dominate the layout |
| Use tonal layering to indicate depth | Add drop shadows anywhere |
| Keep navigation compact and predictable | Add animations that delay reading |
| Show the page number prominently in gold | Hide navigation controls in hamburger menus |
| Test every color combination at WCAG AA | Assume dark theme text on dark backgrounds is readable |
| Prefer inline/panel alternatives to modals | Use modals for search results or text selection |

## 8. Animation & Motion

All animations serve function — they orient the user or confirm an action. No animation exists for decoration.

**Global:** Respect `prefers-reduced-motion: reduce` — all animations collapse to instant state changes.

### Easing & Duration Tokens

| Token | Value | Usage |
|-------|-------|-------|
| `ease-standard` | `cubic-bezier(0.4, 0, 0.2, 1)` | Most transitions (panels, opacity) |
| `ease-out-quart` | `cubic-bezier(0.25, 1, 0.5, 1)` | Elements entering view (drawer, popup) |
| `ease-in-quart` | `cubic-bezier(0.5, 0, 0.75, 0)` | Elements exiting view |
| `duration-fast` | `150ms` | Micro-interactions (hover, active) |
| `duration-normal` | `250ms` | Panel transitions, state changes |
| `duration-slow` | `400ms` | Large-area transitions (drawer, popup) |

### Component Animations

| Component | Trigger | Animation | Duration | Easing |
|-----------|---------|-----------|----------|--------|
| **NavDrawer** | Open | `translateX(-100%) → translateX(0)` | `duration-slow` | `ease-out-quart` |
| **NavDrawer** | Close | `translateX(0) → translateX(-100%)` | `duration-normal` | `ease-in-quart` |
| **NavDrawer backdrop** | Open | `opacity: 0 → 0.5` | `duration-slow` | `ease-standard` |
| **AI FAB** | Hover | `scale(1) → scale(1.05)`, color deepens | `duration-fast` | `ease-out-quart` |
| **AI FAB** | Active | `scale(1) → scale(0.95)` | `80ms` | `ease-standard` |
| **AI FAB** | Unread pulse | Subtle ring pulse (opacity 0.4→0→0.4) | `2000ms` loop | `ease-standard` |
| **AI Popup** | Open | `opacity: 0, translateY(16px) → opacity: 1, translateY(0)` | `duration-slow` | `ease-out-quart` |
| **AI Popup** | Close | `opacity: 1 → 0, translateY(0) → translateY(8px)` | `duration-normal` | `ease-in-quart` |
| **Search results** | Appear | Stagger children: `opacity: 0 → 1`, delay `50ms × index` (max 8 items) | `duration-normal` | `ease-out-quart` |
| **Highlight mark** | Appear | Background pulse-in (0→100% opacity) | `duration-slow` | `ease-out-quart` |
| **Page marker** | Enter viewport | No animation — static text, appears naturally via scroll | — | — |
| **Right Toolbar** | Scroll start | `opacity: 1 → 0.2` | `duration-normal` | `ease-standard` |
| **Right Toolbar** | Scroll stop (1.5s) | `opacity: 0.2 → 1` | `duration-normal` | `ease-standard` |
| **Theme switch** | Toggle | Cross-fade backgrounds: `opacity` swap | `duration-slow` | `ease-standard` |
| **Loading skeleton** | Pulse | Background shimmer left→right | `1500ms` loop | `ease-standard` |

### Named Rules

**The No-Bounce Rule.** No spring or bounce physics anywhere. The aesthetic is calm, not playful — overshooting motion contradicts the contemplative reading environment.

**The Stagger Cap Rule.** List animations stagger at most 8 items (8 × 50ms = 400ms max). Beyond 8, remaining items appear instantly. Long stagger chains feel sluggish.