# Design System ## Principles kami's aesthetic compresses into one sentence: **warm parchment canvas, ink-blue accent, serif carries hierarchy, avoid cool grays and hard shadows**. This is not a UI framework. It is a constraint system for print, designed to keep pages stable, clear, and readable. **The ten invariants** (each has a real cost, think before overriding): 1. Page background parchment `#f5f4ed`, never pure white 2. Single accent: ink-blue `#1B365D`, no second chromatic color 3. All grays warm-toned (yellow-brown undertone), no cool blue-grays 4. English: serif for everything (headlines and body). Chinese: serif headlines, sans body. Sans only for UI elements (labels, eyebrows, meta) in both 5. Serif weight locked at 500, no bold 6. Line-heights: tight headlines 1.1-1.3, dense body 1.4-1.45, reading body 1.5-1.55 7. Letter-spacing: Chinese body 0.3pt for comfortable reading; English body 0; tracking only for short labels and overlines 8. Tag backgrounds must be solid hex, never rgba (WeasyPrint renders a double rectangle) 9. Depth via ring shadow or whisper shadow, never hard drop shadows 10. **No italic anywhere**. No `font-style: italic` in any template or demo. No italic @font-face declarations needed This system is a fusion of Anthropic's visual language and real Chinese / English resume iteration. Details below. --- ## 1. Color **Single accent, warm neutrals only, zero cool tones** - this is the core. ### Brand ```css --brand: #1B365D; /* Ink Blue - the only chromatic color. CTAs, accents, section-title left bar. */ --brand-light: #2D5A8A; /* Ink Light - brighter variant, for links on dark surfaces. */ ``` **Rule**: ink-blue covers ≤ **5% of document surface area**. More than that is ornament, not restraint. ### Surface ```css --parchment: #f5f4ed; /* Page background - warm cream, the emotional foundation */ --ivory: #faf9f5; /* Card / lifted container - brighter than parchment */ --warm-sand: #e8e6dc; /* Button default / interactive surface */ --dark-surface: #30302e; /* Dark-theme container - warm charcoal */ --deep-dark: #141413; /* Dark-theme page background - not pure black, slight olive undertone */ ``` **Never**: `#ffffff` pure white as page background. `#f8f9fa` / `#f3f4f6` or any cool-gray surface. ### Text ```css --near-black: #141413; /* Primary text - deepest but not pure black, warm olive undertone */ --dark-warm: #3d3d3a; /* Secondary text, table headers, links */ --olive: #504e49; /* Subtext - descriptions, captions. JA override: #4d4c48 (YuMincho thin strokes need darker text) */ --stone: #6b6a64; /* Tertiary - dates, metadata */ ``` Four levels: near-black (primary) > dark-warm (secondary) > olive (subtext) > stone (tertiary). No fifth level needed. **Mnemonic**: every gray has a **yellow-brown undertone**. In `rgb()`, warm gray is R ≈ G > B (or R > G > B with small gaps). Cool gray is R < G < B or R = G = B (neutral). ### Border ```css --border: #e8e6dc; /* Primary border - section dividers, table headers, card borders */ --border-soft: #e5e3d8; /* Secondary border - row separators, subtle dividers */ ``` ### Translucent -> Solid conversion (TAGS MUST BE SOLID) **Why**: WeasyPrint's alpha compositing for padding vs glyph areas produces a visible double rectangle on zoom. See `production.md` Part 4 Pitfall #1. Ink Blue `#1B365D` over parchment `#f5f4ed`: | rgba alpha | Solid hex | |---|---| | 0.08 | `#EEF2F7` | | 0.14 | `#E4ECF5` | | **0.18** | **`#E4ECF5`** ← default tag | | 0.22 | `#D0DCE9` | | 0.30 | `#D6E1EE` | --- ## 2. Typography ### Stacks ```css /* Single serif per page. --sans always equals var(--serif). */ /* English */ font-family: Charter, Georgia, Palatino, "Times New Roman", serif; /* Chinese */ font-family: "TsangerJinKai02", "Source Han Serif SC", "Noto Serif CJK SC", "Songti SC", "STSong", Georgia, serif; /* Japanese */ font-family: "YuMincho", "Yu Mincho", "Hiragino Mincho ProN", "Noto Serif CJK JP", "Source Han Serif JP", "TsangerJinKai02", Georgia, serif; /* Mono, with CJK fallback for comments and labels */ font-family: "JetBrains Mono", "SF Mono", "Fira Code", Consolas, Monaco, "TsangerJinKai02", "Source Han Serif SC", monospace; ``` Any font-family that may render Chinese or Japanese must include a CJK fallback, including `@page` footer text, `pre`, `code`, and SVG labels. A pure mono stack can render missing glyph boxes in WeasyPrint. ### Size scale (pt for print A4, px for screen) **Print:** | Role | Size | Weight | Line-height | Use | |---|---|---|---|---| | Display | 36pt | 500 | 1.10 | Cover title, one-pager hero | | H1 Section | 22pt | 500 | 1.20 | Chapter titles | | H2 | 16pt | 500 | 1.25 | Subsection | | H3 | 13pt | 500 | 1.30 | Item titles | | Body Lead | 11pt | 400 | 1.55 | Intro paragraphs | | Body | 10pt | 400 | 1.55 | Reading body | | Body Dense | 9.2pt | 400 | 1.42 | Dense body (resume, one-pager) | | Caption | 9pt | 400 | 1.45 | Notes, figure captions | | Label | 9pt | 600 | 1.35 | Small labels, corner tags | | Tiny | 9pt | 400 | 1.40 | Footer, minor metadata | **Screen (px)** ≈ pt × 1.33 (9pt ≈ 12px, 18pt ≈ 24px). **Minimum floor**: web text >= 12px, PDF text >= 9pt. ### Weight - **Serif body**: 400 (W04 font file) - **Serif headings**: 500 (W05 font file, real bold, not synthetic) - **Sans body**: 400 default - **Sans labels / small titles**: 500 or 600 - **Forbidden**: 900 black, 100 thin **Design principle**: Serif uses only two weights (400/500), no synthetic bold (600/700), maintaining restrained typography. - `strong { font-weight: 500 }` in long-doc templates locks bold to W05, preventing browsers from synthesizing 700 on top of W05 - **Web only**: W04 covers weight 400-500 (single `font-weight: 400 500` declaration); W05 is PDF-only because WeasyPrint cannot synthesize bold ### Line-height Print documents are **tighter** than English web body. English web typically runs 1.6-1.75; in print at pt sizes that feels loose and floats. | Tier | Value | Use | |---|---|---| | Tight headline | 1.10-1.30 | Display, H1, H2 | | Dense body | 1.40-1.45 | Resume, one-pager, dense information | | Reading body | 1.50-1.55 | Long-doc chapters, letters | | Label / caption | 1.30-1.40 | Small labels, multi-line metadata | **Forbidden**: - 1.60+ - loose feel, web rhythm, not print - 1.00-1.05 - lines collide except at extreme display sizes ### Letter-spacing - Body text: **0** - Chinese and Japanese body text with TsangerJinKai02: **0.1–0.2pt** to compensate for the font's natural density; section titles and Mincho samples: **0** - Chinese lede text (14–22pt) with TsangerJinKai02: **0.03–0.06em** to open up large-body paragraphs without breaking density; EN and JA lede: **0** (only TsangerJinKai02 needs density compensation) - Chinese and Japanese display text (24pt+): **0.2–1pt** optical spacing for visual breathing room at large sizes; scale with font size - English headings may use subtle optical tightening when needed; keep it localized, never inherited by body copy - Small labels (< 10pt): +0.2 to +0.5pt for readability - All-caps overlines: +0.5 to +1pt mandatory - **Slide-specific**: print tracking x0.5 at slide scale. Eyebrow max 3px (not 8px), display titles -0.5pt. Large type at 40pt+ will look scattered at print tracking values --- ## 3. Spacing ### Base unit: 4pt (4px on screen) | Tier | Value | Use | |---|---|---| | xs | 2-3pt | Inline adjacent elements | | sm | 4-5pt | Tag padding, dense layout | | md | 8-10pt | Component interior | | lg | 16-20pt | Between components / card padding | | xl | 24-32pt | Section-title margins | | 2xl | 40-60pt | Between major sections | | 3xl | 80-120pt | Between chapters (long docs) | ### Page margins (A4) | Document | Top | Right | Bottom | Left | |---|---|---|---|---| | Resume (dense) | 11mm | 13mm | 11mm | 13mm | | One-Pager | 15mm | 18mm | 15mm | 18mm | | Long Doc | 20mm | 22mm | 22mm | 22mm | | Letter | 25mm | 25mm | 25mm | 25mm | | Portfolio | 12mm | 15mm | 12mm | 15mm | **Rule**: denser = smaller margins, more formal (letter) = larger margins. ### Slide-scale spacing Print uses mm/pt; slides (screen) use px. The scale relationships differ: ```css --slide-pad: 80px; /* slide four-side padding baseline */ ``` **Key rules**: - Slide padding-top: 72-80px (print is 96-120px; slides are more compact) - Slide letter-spacing = print value / 2 (8px tracking "falls apart" on screen; halve it) - Macro scale (font size, padding): multiply print pt values by ~1.6 - Micro scale (letter-spacing, border, radius): multiply by ~0.6 --- ## 4. Components ### Cards / Containers ```css .card { background: var(--ivory); border: 0.5pt solid var(--border-cream); border-radius: 8pt; padding: 16pt 20pt; } .card-featured { border-radius: 16pt; box-shadow: 0 4pt 24pt rgba(0,0,0,0.05); /* whisper shadow */ } ``` Radius scale: 4pt -> 6pt -> 8pt (default) -> 12pt -> 16pt -> 24pt -> 32pt (hero containers). ### Buttons ```css /* Primary - brand-colored */ .btn-primary { background: var(--brand); color: var(--ivory); padding: 8pt 16pt; border-radius: 8pt; box-shadow: 0 0 0 1pt var(--brand); /* ring shadow */ } /* Secondary - warm-sand */ .btn-secondary { background: var(--warm-sand); color: var(--dark-warm); padding: 8pt 16pt; border-radius: 8pt; box-shadow: 0 0 0 1pt var(--border); } ``` ### Tags Three tiers from weak to strong visual weight: **Lightest solid** (default, most restrained): ```css .tag { background: #EEF2F7; /* 0.08 solid equivalent */ color: var(--brand); font-size: 9pt; font-weight: 600; padding: 1pt 5pt; border-radius: 2pt; letter-spacing: 0.4pt; text-transform: uppercase; } ``` **Standard solid** (when more contrast needed): ```css .tag { background: #E4ECF5; /* 0.18 solid equivalent */ color: var(--brand); padding: 1pt 6pt; border-radius: 4pt; } ``` **Gradient brush** (only when "hand-painted" feel is required - use sparingly): ```css .tag { background: linear-gradient(to right, #D6E1EE, #E4ECF5 70%, #EEF2F7); color: var(--brand); padding: 1pt 5pt; border-radius: 2pt; } ``` **Philosophy**: tint depth should be one step lighter than what decoration wants. Prefer pale over saturated. In iteration, "gradient brush" often steals focus - lightest solid wins most of the time. **Never**: `background: rgba(201, 100, 66, 0.18)` - WeasyPrint double-rectangle bug. ### Lists ```css ul, ol { padding-left: 16pt; line-height: 1.55; } ul li::marker { color: var(--brand); } ``` Editorial bookish variant - **en-dash instead of bullet**: ```css ul.dash { list-style: none; padding-left: 0; } ul.dash li { padding-left: 14pt; } ul.dash li::before { content: "\2013"; color: var(--brand); } ``` ### Quote ```css .quote { border-left: 2pt solid var(--brand); padding: 4pt 0 4pt 14pt; color: var(--olive); line-height: 1.55; } ``` ### Code ```css .code-block { background: var(--ivory); border: 0.5pt solid var(--border-cream); border-radius: 6pt; padding: 10pt 14pt; font-family: var(--mono); font-size: 9pt; line-height: 1.5; } ``` ### Section Title ```css .section-title { font-family: var(--serif); font-size: 14pt; font-weight: 500; color: var(--near-black); margin: 24pt 0 10pt 0; border-left: 2.5pt solid var(--brand); border-radius: 1.5pt; padding-left: 8pt; } ``` ### Table (kami-table) Unified table component across all templates. Base class applies to bare `
| Category | Q1 | Q2 |
|---|---|---|
| Revenue | $12.4M | $14.1M |
| Total | $12.4M | $14.1M |