Peony Zine.
A printed quarterly that happens to live on the web. Soft blush-bone surfaces, Fraunces 600 italic display headlines, Geist Mono for marginalia, a single deep plum accent on drop caps and pull-quote bars. Built for journals, newsletters, and slow-content brands that want warmth without preciousness.
The kitchen sink.
Build with Peony Zine.
A complete design system, ready for your AI coding agent. Every primitive, token, and pattern below is generated straight from DESIGN.md — drop the file in your project and ship matching UI in minutes.
Palette
Type scale
Buttons
Form controls
Select & toggle
Labeling
Cards
Prose-first token file — decisions live next to their reasoning.
Tabs & breadcrumb
Spacing scale
Fine micro-scale (1–5px) for pills, editorial scale (12–21px) for the grid.
Border radius scale
The system's own radius tokens — sm for chips and inputs, md for buttons, lg for cards, pill for fully-rounded CTAs.
Depth & elevation
Charts
The states behind the resting style.
Tokens describe the resting state. A real product needs every interaction state. Hover, focus, active, disabled, loading — all derived from the system's resting tokens.
Button
Input
Card
Tab
DESIGN.md
1---2name: "Peony Zine"3description: "A printed quarterly that happens to live on the web. Soft blush-bone surfaces, Fraunces 600 italic display headlines, Geist Mono for marginalia, a single deep plum accent on drop caps and pull-quote bars. Built for journals, newsletters, and slow-content brands that want warmth without preciousness."4tags: [editorial, soft, warm, minimal, premium]5colors:6 primary: "#2a1f24"7 secondary: "#7a6b71"8 tertiary: "#2a1f24"9 neutral: "#f3e9e6"10 surface: "#faf2ee"11typography:12 display: Fraunces13 body: Inter14 mono: "Geist Mono"15 scale:16 hero: "5rem / 0.98 / 600 / -0.03em"17 h1: "3rem / 1.06 / 600 / -0.025em"18 h2: "1.875rem / 1.2 / 500 / -0.018em"19 body: "1.0625rem / 1.7 / 400 / -0.005em"20radius:21 sm: 4px22 md: 10px23 lg: 16px24 pill: 9999px25shadows:26 card: "rgba(42,31,36,0.04) 0 1px 2px"27 button: none28borders:29 card: "1px solid rgba(42,31,36,0.08)"30 divider: rgba(42,31,36,0.10)31buttons:32 primary:33 background: #2a1f2434 color: #faf2ee35 border: none36 shape: rounded37 padding: 12px 22px38 font: 500 / 0.875rem39 secondary:40 background: #f3e9e641 color: #2a1f2442 border: 1px solid rgba(42,31,36,0.10)43 shape: rounded44 padding: 12px 22px45 font: 500 / 0.875rem46 outline:47 background: transparent48 color: #2a1f2449 border: 1px solid rgba(42,31,36,0.18)50 shape: rounded51 padding: 12px 22px52 font: 500 / 0.875rem53 ghost:54 background: transparent55 color: #7a6b7156 border: none57 shape: rounded58 padding: 12px 16px59 font: 500 / 0.875rem60charts:61 variant: "thin-bars"62 stroke_width: 1.2563 fill_opacity: 0.0664 gridlines: false65 bar_gap: 14px66 highlight: single67 dot_marker: true68fonts_url: "https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,500;1,9..144,600&family=Inter:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap"69dependencies: ["lucide-react"]70---71 72# Peony Zine73 74## AI Build Instructions75 76> **Read this section before writing any code.** The rules below77> are non-negotiable. Every value used in the UI must come from this78> file's frontmatter — never substitute, approximate, or invent new79> colors, fonts, radii, or shadows. If a value is missing, ask the80> user before adding one.81 82### 1 · Your role83 84You are building UI for a project that has adopted **Peony Zine** as its85design system. Treat `DESIGN.md` as the single source of truth.86Your job is to translate the user's product requirements into87components and pages that look like they were designed by the same88person who authored this file.89 90### 2 · Token compliance91 92- Pull every color, font family, radius, shadow, and spacing value93 from the frontmatter at the top of this file.94- Use semantic roles (e.g. `primary`, `accent`, `muted`) — never95 hard-code hex values that bypass the system.96- When a token can be expressed as a CSS variable, declare it once97 in your global stylesheet and reference it everywhere downstream.98- The Google Fonts `<link>` is provided in the Typography section.99 Add it to `<head>` before any component renders.100 101### 3 · Component recipes102 103Use these recipes verbatim when building the corresponding component.104 105#### Buttons106 107Four variants are defined. Pick one — never blend variants or invent a fifth.108 109- **Primary** — rounded shape, bg `#2a1f24`, text `#faf2ee`, padding `12px 22px`, weight `500`.110- **Secondary** — rounded shape, bg `#f3e9e6`, text `#2a1f24`, border `1px solid rgba(42,31,36,0.10)`, padding `12px 22px`, weight `500`.111- **Outline** — rounded shape, text `#2a1f24`, border `1px solid rgba(42,31,36,0.18)`, padding `12px 22px`, weight `500`.112- **Ghost** — rounded shape, text `#7a6b71`, padding `12px 16px`, weight `500`.113 114Reach for **primary** as the single dominant CTA per screen.115**Secondary** for the supporting action. **Outline** for tertiary116actions in toolbars. **Ghost** for inline links and table actions.117 118#### Cards119 120- Background: `#faf2ee`121- Border: `1px solid rgba(42,31,36,0.08)`122- Shadow: `rgba(42,31,36,0.04) 0 1px 2px`123- Radius: `radius.lg` (`16px`)124- Internal padding: `20px` for compact cards, `24–28px` for content cards.125 126#### Tabs127 128Variant: `underline`. Flat row of labels. Active tab gets a 2px underline in the accent color — no fill.129 130#### Charts131 132- Bar/line variant: `thin-bars`133- No gridlines — let the bars/lines carry the data.134- Highlight strategy: `single` — emphasize a single bar/point per chart.135 136#### Typography pairings137 138- **Display (`Fraunces`)** — h1, h2, hero headlines, brand wordmarks.139- **Body (`Inter`)** — paragraphs, labels, button text, form inputs.140- **Mono (`Geist Mono`)** — code, eyebrows, metadata, numerals in tables.141 142### 4 · Hard constraints143 144Never do any of the following without explicit instruction from the user:145 146- Introduce a new color, font, radius, or shadow that isn't declared above.147- Mix this system with another (e.g. don't paste in Material or Bootstrap defaults).148- Use generic gradient defaults (purple→blue, peach→pink) — they break the system's voice.149- Reach for emoji icons. Use a consistent icon library and size icons in line with body type.150- Add motion that exceeds the system's restraint — keep transitions short (≤200ms) and subtle.151 152### 5 · Before you finish — verify153 154Run through this checklist for every screen you produce:155 156- [ ] Every color used appears in the Colors table above.157- [ ] Headlines use the display font; body copy uses the body font.158- [ ] Buttons match one of the declared variants exactly (shape, padding, weight).159- [ ] Border-radius values come from `radius.sm` / `radius.md` / `radius.lg` / `radius.pill`.160- [ ] Cards and dividers use the declared border + shadow tokens.161- [ ] No values were invented; if you needed something missing, you stopped and asked.162 163---164 165## 1. Atmosphere166 167Peony Zine is a printed quarterly that happens to live on the web. The page surface is soft blush-bone `#faf2ee` — closer to uncoated cream stock than to white. Headlines run in Fraunces 600 italic at 80px, the soft-cornered serif giving the page a hand-set quality without tipping into preciousness. Body sits in Inter at 17px on a generous 1.7 leading. Marginalia, page numbers, and dateline run in Geist Mono uppercase. The single accent is deep plum `#5b2440` — used only on drop caps and the 2px bar to the left of pull quotes.168 169The discipline is in the warmth: blush over white, plum over magenta, italic display over upright bold.170 171**Signature moves**172- Fraunces 600 italic for the hero — the soft optical-sized italic IS the voice173- Soft blush-bone surface `#faf2ee` (not white, not pink)174- Plum accent `#5b2440` only on drop caps + a 2px pull-quote bar — never as a fill175- Pull quotes set in Fraunces 500 italic at 28px with a 2px plum left bar176- Marginalia in Geist Mono uppercase 0.10em — page numbers, datelines, footnote refs177 178## 2. Palette179 180### Surfaces181- **Blush Bone** `#faf2ee` — page background (warm cream)182- **Blush Lift** `#f3e9e6` — secondary surfaces, secondary button183- **Hairline** `rgba(42,31,36,0.08)` — every divider184 185### Ink186- **Ink** `#2a1f24` — text, headings (warm near-black, never grey)187- **Ink 50** `#7a6b71` — secondary text, mono marginalia188 189### Accent190- **Plum** `#5b2440` — drop caps, pull-quote bar, chart highlight191- **Plum Soft** `rgba(91,36,64,0.12)` — focus ring, hovered tab background192 193## 3. Typography194 195| Role | Font | Size | Weight | Leading | Tracking |196|------|------|------|--------|---------|----------|197| Hero | Fraunces (italic) | 80px | 600 | 0.98 | -0.03em |198| H1 | Fraunces | 48px | 600 | 1.06 | -0.025em |199| H2 | Fraunces | 30px | 500 | 1.2 | -0.018em |200| Pull Quote | Fraunces (italic) | 28px | 500 | 1.3 | -0.015em |201| Body | Inter | 17px | 400 | 1.7 | -0.005em |202| UI | Inter | 13px | 500 | 1.4 | 0 |203| Marginalia | Geist Mono | 11px | 500 | 1.0 | 0.10em uppercase |204 205Fraunces uses optical sizing — at 80px the italic glyphs open up into something almost calligraphic. Hold the italic to display only; body must be upright Inter.206 207## 4. Buttons208 209### Primary (Ink Plum)210```css211background: #2a1f24;212color: #faf2ee;213padding: 12px 22px;214border-radius: 10px;215font-weight: 500;216```217 218### Secondary (Blush Lift)219- `#f3e9e6` background, 1px hairline at 10% ink, ink text — same shape, same padding220 221### Outline & Ghost222- Outline: transparent, 1px hairline at 18% ink223- Ghost: no border, ink-50, hover underlines224 225## 5. Cards226 227```css228background: #faf2ee;229border: 1px solid rgba(42,31,36,0.08);230border-radius: 16px;231box-shadow: rgba(42,31,36,0.04) 0 1px 2px;232```233 234The single 1px shadow is the maximum lift. Featured cards swap to blush-lift surface and add a 2px plum left bar — borrowed from the pull-quote treatment.235 236## 6. Charts237 238Thin precise bars (4px wide, 14px gap). One bar in plum, others in 18% ink. NO gridlines. Line charts at 1.25px ink with a 6% plum fill, ending in a plum dot marker. Y-axis labels in Geist Mono uppercase 11px set in the left margin.239 240## 7. Tabs241 242Underline 1.5px in plum for the active state. Inactive tabs are ink-50 in Inter 500. Hover = plum-soft background wash. Tabs sit on a 1px hairline baseline.243 244## 8. Spacing245 246- Base 4px247- Scale: `4, 8, 12, 16, 20, 24, 32, 48, 64, 96, 128`248- Section padding: 96px desktop, 48px mobile249 250## 9. Do's & don'ts251 252✅ **Do**253- Use Fraunces italic 600 at 80px for the hero — the optical-sized italic is the brand254- Hold the blush-bone surface `#faf2ee` — white kills the warmth, pink reads as gendered255- Reserve plum for drop caps + the 2px pull-quote bar + chart highlight256- Set marginalia in Geist Mono uppercase 0.10em — that's the printed-page voice257 258❌ **Don't**259- Use Fraunces italic in body — italic is reserved for display + pull quotes260- Add a second accent — plum alone, on three specific gestures261- Use sharp 0px radius — soft 10-16px is the zine voice (rounded paper, not posters)262- Use shadows beyond the 1px lift — the page is paper, not glass263 264---265 266## Tokens267 268> Generated from the same source the live preview renders from.269> Treat the values below as the contract — never substitute approximations.270 271### Colors272 273| Role | Value |274|-----------|-------|275| primary | `#2a1f24` |276| secondary | `#7a6b71` |277| tertiary | `#2a1f24` |278| neutral | `#f3e9e6` |279| surface | `#faf2ee` |280 281### Typography282 283- **Display:** Fraunces284- **Body:** Inter285- **Mono:** Geist Mono286 287| Role | size / leading / weight / tracking |288|------|------------------------------------|289| Hero | 5rem / 0.98 / 600 / -0.03em |290| H1 | 3rem / 1.06 / 600 / -0.025em |291| H2 | 1.875rem / 1.2 / 500 / -0.018em |292| Body | 1.0625rem / 1.7 / 400 / -0.005em |293 294### Radius295 296- sm: `4px`297- md: `10px`298- lg: `16px`299- pill: `9999px`300 301### Shadows302 303- **card:** `rgba(42,31,36,0.04) 0 1px 2px`304- **button:** `none`305 306### Borders307 308- **card:** `1px solid rgba(42,31,36,0.08)`309- **divider:** `rgba(42,31,36,0.10)`310 311### Buttons312 313Four variants, each fully tokenized. The preview renders from these exact values.314 315#### Primary316 317| Property | Value |318|----------|-------|319| shape | `rounded` |320| background | `#2a1f24` |321| color | `#faf2ee` |322| border | `none` |323| padding | `12px 22px` |324| fontWeight | `500` |325| fontSize | `0.875rem` |326 327#### Secondary328 329| Property | Value |330|----------|-------|331| shape | `rounded` |332| background | `#f3e9e6` |333| color | `#2a1f24` |334| border | `1px solid rgba(42,31,36,0.10)` |335| padding | `12px 22px` |336| fontWeight | `500` |337| fontSize | `0.875rem` |338 339#### Outline340 341| Property | Value |342|----------|-------|343| shape | `rounded` |344| background | `transparent` |345| color | `#2a1f24` |346| border | `1px solid rgba(42,31,36,0.18)` |347| padding | `12px 22px` |348| fontWeight | `500` |349| fontSize | `0.875rem` |350 351#### Ghost352 353| Property | Value |354|----------|-------|355| shape | `rounded` |356| background | `transparent` |357| color | `#7a6b71` |358| border | `none` |359| padding | `12px 16px` |360| fontWeight | `500` |361| fontSize | `0.875rem` |362 363### Charts364 365| Property | Value |366|----------|-------|367| variant | `thin-bars` |368| strokeWidth | `1.25` |369| fillOpacity | `0.06` |370| gridlines | `false` |371| barGap | `14px` |372| highlight | `single` |373| dotMarker | `true` |374 375---376 377## Pro tokens378 379> Production-fidelity tokens. States, density, motion, elevation,380> content rules and a measured WCAG contract — derived from the381> resting tokens unless explicitly authored.382 383### States384 385#### Button386 387- **hover** — bg: `rgba(42, 31, 36, 0.92)`, shadow: `0 4px 20px -8px rgba(42, 31, 36, 0.4)`388- **focus** — outline: `1.5px solid #2a1f24`, outline-offset: `4px`389- **active** — transform: `translateY(1px)`, filter: `brightness(0.95)`390- **disabled** — opacity: `0.45`391- **loading** — opacity: `0.7`392- **selected** — bg: `#2a1f24`, color: `#faf2ee`393 394#### Input395 396- **hover** — border: `1px solid #2a1f24`397- **focus** — border: `1px solid #2a1f24`, shadow: `0 1px 0 0 #2a1f24`398- **disabled** — opacity: `0.45`399- **error** — border: `1px solid #991B1B`, shadow: `0 1px 0 0 #991B1B`400 401#### Card402 403- **hover** — shadow: `0 8px 24px -12px rgba(15,23,42,0.14)`, transform: `translateY(-1px)`404- **selected** — border: `1px solid #2a1f24`405 406#### Tab407 408- **hover** — color: `#2a1f24`409- **focus** — outline: `1.5px solid #2a1f24`, outline-offset: `3px`410- **selected** — color: `#2a1f24`, border: `0 0 2px 0 solid #2a1f24`411 412### Density413 414| Mode | padding × | row × | body | radius × | Use for |415|------|-----------|-------|------|----------|---------|416| compact | 0.72 | 0.78 | 0.8125rem | 0.85 | Information-dense — tables, IDEs, dashboards |417| comfortable | 1 | 1 | 0.9375rem | — | Default — most product UI |418| spacious | 1.35 | 1.3 | 1rem | 1.15 | Editorial — marketing, long-form, settings |419 420### Motion421 422**Signature — Page turn.** Deliberate, measured motion — like turning a magazine page. Never jerky, never overdone.423 424```css425transition: all 320ms cubic-bezier(0.25, 0.46, 0.45, 0.94);426```427 428| Token | Value |429|-------|-------|430| duration.instant | `80ms` |431| duration.fast | `180ms` |432| duration.base | `320ms` |433| duration.slow | `500ms` |434| easing.standard | `cubic-bezier(0.25, 0.46, 0.45, 0.94)` |435| easing.decelerate | `cubic-bezier(0.0, 0, 0.2, 1)` |436| easing.accelerate | `cubic-bezier(0.4, 0, 1, 1)` |437| easing.spring | `cubic-bezier(0.5, 1.2, 0.6, 1)` |438 439### Elevation440 441Five-level scale, system-specific recipe.442 443| Level | Shadow | Recipe |444|-------|--------|--------|445| level0 | `none` | Hairline only — typical editorial resting state. |446| level1 | `0 1px 2px rgba(15,23,42,0.04)` | Barely visible — list rows, dividers. |447| level2 | `0 8px 24px -12px rgba(15,23,42,0.12)` | Pull-quote, sidebar — soft lift. |448| level3 | `0 16px 40px -16px rgba(15,23,42,0.18)` | Cover story card — clear lift. |449| level4 | `0 32px 80px -24px rgba(15,23,42,0.28)` | Modal — overlays the layout, with scrim. |450 451### Content452 453- **measure:** `60ch` (max line length for body prose)454- **paragraph spacing:** `1.5em`455- **list indent:** `1.75em`456- **list gap:** `0.55em`457- **link:** color `#2a1f24`, underline `always`458- **blockquote:** border `4px solid #2a1f24`, padding `0.4em 0 0.4em 1.5em`459- **code:** background `rgba(42, 31, 36, 0.06)`, color `#2a1f24`460 461### Accessibility (WCAG 2.1)462 463**Overall:** AA464 465| Pair | Ratio | Required | Grade | Suggested fix |466|------|-------|----------|-------|---------------|467| Body text on surface | 14.4:1 | AA | AAA | — |468| Body text on canvas | 13.34:1 | AA | AAA | — |469| Muted text on surface | 4.56:1 | AA | AA | — |470| Accent on surface | 14.4:1 | AA-Large | AAA | — |471| Accent on canvas | 13.34:1 | AA-Large | AAA | — |472 Wire it into your agent.
# CLAUDE.md Reference @DESIGN.md for all styling decisions. Apply tokens strictly — do not introduce colors, fonts, or radii outside the system. When in doubt, prefer the values declared in DESIGN.md frontmatter.Three snippets.
Google Fonts link
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,500;1,9..144,600&family=Inter:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" />Install dependencies
npm install lucide-reactTailwind config
// tailwind.config.jsexport default { theme: { extend: { fontFamily: { display: ['"Fraunces"', 'serif'], sans: ['"Inter"', 'sans-serif'], mono: ['"Geist Mono"', 'monospace'], }, colors: { primary: '#2a1f24', secondary: '#7a6b71', accent: '#2a1f24', neutral: '#f3e9e6', surface: '#faf2ee', }, borderRadius: { sm: '4px', md: '10px', lg: '16px', }, }, },};Try another system.
Neon Y2K
Hot magenta and cyber-lime on absolute black. Oversized monospace, chrome gradients, hard-edged buttons, glowing accents. Built for clubs and clients with attitude.
Signal AI
Modern AI product surface without the clichés. Geist sans across the board, Geist Mono for prompts and metrics, very fine off-white surfaces with a 1px white inset highlight, a single muted electric-indigo accent reserved for the assistant's response state. Built for AI-first products that want to feel premium without leaning on rainbow gradients.