--- feature: DesignTokenSystem date: 2026-05-26 status: planned project: crash-test-dev tags: [tokens, system, color, typography, spacing, layout] related: [AESTHETIC-GUIDE.md] --- # Design Token System — Crash Test Dev ## User's Spark (preserved) > A well-used workshop. Not a pristine showroom — the one where someone actually builds things. > Tools are organized because disorganization wastes time. The wood has warmth. > The light is good because you need to see details. There's a coffee cup somewhere. **Metaphor:** The workbench, not the gallery. **Materials vocabulary:** Paper, ink, wood, stone, iron. **Personality:** Dry warmth. Quiet confidence. Evidence over performance. --- ## Complete Token System ```json { "colors": { "_meta": { "temperature": "warm across all values — no blue-grays, no cool neutrals", "philosophy": "Aged paper, brown-black ink, fired earth, tarnished brass. Every color drawn from the workbench vocabulary: materials that have been used, heated, and cooled." }, "surface": { "base": { "value": "#F5F0E8", "description": "Page background. Heavy unbleached paper stock — warm off-white, not pure white, not yellow." }, "card": { "value": "#FEFCF7", "description": "Reading surface. White card stock laid on the paper base — for article bodies, elevated panels." }, "code": { "value": "#EEEAE2", "description": "Code block background. Heavier paper weight — subtle warm-gray shift from prose background." }, "inset": { "value": "#E8E3DA", "description": "Callout/aside background. Slightly recessed surface, like a different stock weight." } }, "text": { "primary": { "value": "#2B2421", "description": "Body text. Warm near-black — brown-black ink, NOT blue-black digital default.", "contrastOnBase": "13.44:1 (AAA)", "contrastOnCard": "14.87:1 (AAA)" }, "secondary": { "value": "#6B5F55", "description": "Metadata, captions, bylines. Warm mid-gray with stone undertone.", "contrastOnBase": "5.46:1 (AA)", "contrastOnCard": "6.04:1 (AA)" }, "tertiary": { "value": "#948880", "description": "Timestamps, tags, disabled text. Lighter warm gray.", "contrastOnBase": "3.04:1 (AA-UI)", "contrastOnCard": "3.36:1 (AA-UI)" } }, "accent": { "primary": { "value": "#A0522D", "description": "Links, emphasis, code block left-edge accent. Muted terracotta/sienna — fired earth, not bright red.", "contrastOnBase": "4.95:1 (AA)", "contrastOnCard": "5.48:1 (AA)" }, "primaryHover": { "value": "#8B4726", "description": "Link hover state. Darker rust — the terracotta after more firing.", "contrastOnBase": "6.12:1 (AA)" }, "secondary": { "value": "#7D6C2F", "description": "Special callouts, highlights. Tarnished brass/dark gold — aged metal.", "contrastOnBase": "4.56:1 (AA)", "contrastOnCard": "5.05:1 (AA)" }, "secondaryHover": { "value": "#6B5C28", "description": "Brass hover state. Darker, more patinated." } }, "code": { "text": { "value": "#3D342E", "description": "Code text. Warm dark brown, slightly lighter than body text for the different register.", "contrastOnCode": "10.12:1 (AAA)" } }, "border": { "subtle": { "value": "#DDD7CD", "description": "Decorative score lines, faint dividers. Barely there — like a fold in paper. No contrast requirement (decorative)." }, "default": { "value": "#C2BAA9", "description": "General-purpose separators, card edges. Visible but quiet." }, "strong": { "value": "#8E857A", "description": "Functional UI borders (form inputs, focused elements). Meets 3:1 on both base and card.", "contrastOnBase": "3.20:1 (AA-UI)", "contrastOnCard": "3.54:1 (AA-UI)" } }, "focus": { "ring": { "value": "#A0522D", "description": "Keyboard focus indicator. Terracotta — visible, warm, consistent with accent.", "contrastOnBase": "4.95:1 (AA-UI)" } }, "state": { "success": { "bg": { "value": "#E8EDDF", "description": "Warm sage green tint." }, "text": { "value": "#4A5E3A", "description": "Dark moss green.", "contrastOnBg": "5.96:1 (AA)" }, "border": { "value": "#B5C4A0", "description": "Muted sage border." } }, "warning": { "bg": { "value": "#F2E8D0", "description": "Warm amber tint." }, "text": { "value": "#7A5C1F", "description": "Dark warm amber.", "contrastOnBg": "5.10:1 (AA)" }, "border": { "value": "#D4BC7C", "description": "Muted gold border." } }, "error": { "bg": { "value": "#F2DED6", "description": "Warm rose/clay tint." }, "text": { "value": "#8B3A2A", "description": "Dark terracotta.", "contrastOnBg": "5.92:1 (AA)" }, "border": { "value": "#CFA090", "description": "Muted clay border." } }, "info": { "bg": { "value": "#E5E2DA", "description": "Warm neutral tint." }, "text": { "value": "#4A4540", "description": "Warm dark gray.", "contrastOnBg": "7.32:1 (AAA)" }, "border": { "value": "#B8B2A8", "description": "Warm mid gray border." } } }, "shadow": { "color": { "value": "rgba(43, 36, 33, 0.06)", "description": "Warm-toned shadow base. Derived from text-primary. Barely-there desk shadow." } } }, "typography": { "_meta": { "philosophy": "Three voices, three jobs. Serif for prose (Ken's voice). Sans for structure (navigation, headings). Mono for evidence (code, proof). The reader always knows which voice is speaking.", "scaleRatio": 1.25, "scaleName": "Major Third", "scaleBase": "18px" }, "families": { "prose": { "value": "'Source Serif 4', 'Source Serif Pro', Georgia, 'Times New Roman', serif", "role": "Reading voice — body text, blockquotes, long-form prose" }, "structure": { "value": "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", "role": "Navigation voice — headings, UI labels, metadata" }, "evidence": { "value": "'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, monospace", "role": "Proof voice — code blocks, terminal output, file paths" } }, "scale": { "xs": { "value": "0.75rem", "px": 12, "step": -2, "use": "footnotes, legal text" }, "sm": { "value": "0.875rem", "px": 14, "step": -1, "use": "captions, meta, timestamps, tags" }, "base": { "value": "1.125rem", "px": 18, "step": 0, "use": "body prose" }, "lg": { "value": "1.375rem", "px": 22, "step": 1, "use": "h4 headings" }, "xl": { "value": "1.75rem", "px": 28, "step": 2, "use": "h3 headings" }, "2xl": { "value": "2.25rem", "px": 36, "step": 3, "use": "h2 headings — section titles" }, "3xl": { "value": "2.75rem", "px": 44, "step": 4, "use": "h1 headings — article title" } }, "lineHeight": { "tight": { "value": 1.15, "use": "display headings (h1)" }, "snug": { "value": 1.25, "use": "headings (h2, h3)" }, "heading": { "value": 1.35, "use": "smaller headings (h4)" }, "normal": { "value": 1.5, "use": "UI text, captions" }, "relaxed": { "value": 1.6, "use": "code blocks, blockquotes" }, "prose": { "value": 1.7, "use": "body prose — generous for dense technical narrative" } }, "weight": { "regular": { "value": 400, "use": "body prose, code" }, "medium": { "value": 500, "use": "UI labels, caption emphasis" }, "semibold": { "value": 600, "use": "headings, inline emphasis in prose" }, "bold": { "value": 700, "use": "h1 title, strong emphasis" } }, "styles": { "body": { "fontFamily": "prose", "fontSize": "1.125rem", "fontWeight": 400, "lineHeight": 1.7, "letterSpacing": "normal", "description": "Ken's voice on the page. 18px Source Serif 4 at generous line-height for sustained technical reading." }, "bodySmall": { "fontFamily": "prose", "fontSize": "0.875rem", "fontWeight": 400, "lineHeight": 1.6, "letterSpacing": "0.005em", "description": "Footnotes, secondary prose passages. Still serif — still Ken's voice, just quieter." }, "h1": { "fontFamily": "structure", "fontSize": "2.75rem", "fontWeight": 700, "lineHeight": 1.15, "letterSpacing": "-0.02em", "description": "Article title. 44px Inter Bold — confident, unhurried. Negative tracking tightens at display size." }, "h2": { "fontFamily": "structure", "fontSize": "2.25rem", "fontWeight": 600, "lineHeight": 1.25, "letterSpacing": "-0.015em", "description": "Section heading. 36px Inter Semibold — chapter breaks in the narrative." }, "h3": { "fontFamily": "structure", "fontSize": "1.75rem", "fontWeight": 600, "lineHeight": 1.3, "letterSpacing": "-0.01em", "description": "Subsection heading. 28px Inter Semibold — organizes without competing with prose." }, "h4": { "fontFamily": "structure", "fontSize": "1.375rem", "fontWeight": 600, "lineHeight": 1.35, "letterSpacing": "-0.005em", "description": "Minor heading. 22px Inter Semibold — just enough hierarchy shift to signal structure." }, "blockquote": { "fontFamily": "prose", "fontSize": "1.25rem", "fontWeight": 400, "lineHeight": 1.6, "letterSpacing": "normal", "fontStyle": "italic", "description": "Pull quotes, cited text. 20px Source Serif 4 italic — a gentle size step up signals 'someone else's words' without shouting." }, "caption": { "fontFamily": "structure", "fontSize": "0.875rem", "fontWeight": 500, "lineHeight": 1.5, "letterSpacing": "0.01em", "description": "Image captions, metadata labels, timestamps, tags. 14px Inter Medium — the structure voice at small scale." }, "codeInline": { "fontFamily": "evidence", "fontSize": "0.9em", "fontWeight": 400, "lineHeight": "inherit", "letterSpacing": "normal", "description": "Inline code within prose. 0.9em relative to parent — the evidence voice embedded in narrative." }, "codeBlock": { "fontFamily": "evidence", "fontSize": "1rem", "fontWeight": 400, "lineHeight": 1.6, "letterSpacing": "normal", "description": "Code blocks. 16px JetBrains Mono — factual, verifiable, this-is-what-actually-happened." } } }, "spacing": { "_meta": { "base": "8px", "philosophy": "The page breathes like a well-set book. Generous vertical rhythm for dense technical narrative. Space above H2 is a full breath — section breaks are chapter breaks." }, "scale": { "0": { "value": "0", "px": 0 }, "px": { "value": "1px", "px": 1 }, "0.5":{ "value": "0.25rem", "px": 4, "gridMultiple": "0.5x" }, "1": { "value": "0.5rem", "px": 8, "gridMultiple": "1x" }, "1.5":{ "value": "0.75rem", "px": 12, "gridMultiple": "1.5x" }, "2": { "value": "1rem", "px": 16, "gridMultiple": "2x" }, "2.5":{ "value": "1.25rem", "px": 20, "gridMultiple": "2.5x" }, "3": { "value": "1.5rem", "px": 24, "gridMultiple": "3x" }, "4": { "value": "2rem", "px": 32, "gridMultiple": "4x" }, "5": { "value": "2.5rem", "px": 40, "gridMultiple": "5x" }, "6": { "value": "3rem", "px": 48, "gridMultiple": "6x" }, "8": { "value": "4rem", "px": 64, "gridMultiple": "8x" }, "10": { "value": "5rem", "px": 80, "gridMultiple": "10x" }, "12": { "value": "6rem", "px": 96, "gridMultiple": "12x" } }, "semantic": { "paragraphGap": { "value": "1.5rem", "px": 24, "note": "~1.33em at 18px body. Generous — lets ideas land." }, "headingAboveH2": { "value": "4rem", "px": 64, "note": "Section breaks are chapter breaks. Full breath between sections." }, "headingBelowH2": { "value": "1rem", "px": 16, "note": "Tight — the heading belongs to its content, not the space above." }, "headingAboveH3": { "value": "2.5rem", "px": 40, "note": "Sub-section breath. Less than H2, still generous." }, "headingBelowH3": { "value": "0.75rem", "px": 12, "note": "Snug — content follows immediately." }, "headingAboveH4": { "value": "2rem", "px": 32, "note": "Minor heading spacing." }, "headingBelowH4": { "value": "0.5rem", "px": 8, "note": "Very tight — H4 is almost inline with its content." }, "codeBlockVertical": { "value": "2.5rem", "px": 40, "note": "Code blocks as exhibited artifacts — generous vertical clearance." }, "codeBlockPadding": { "value": "1.5rem", "px": 24, "note": "Internal padding of code blocks." }, "codeBlockAccentWidth": { "value": "3px", "note": "Left-edge accent line on code blocks." }, "listItemGap": { "value": "0.5rem", "px": 8, "note": "Breathing room between list items." }, "blockquoteIndent": { "value": "1.5rem", "px": 24, "note": "Left indent/border offset for blockquotes." }, "sectionDivider": { "value": "3rem", "px": 48, "note": "Vertical space when using a horizontal rule." } } }, "rounded": { "_meta": { "philosophy": "Workshop surfaces have worn edges, not machined radii. Just enough softness to not feel sharp, not enough to feel 'designed.'" }, "none": { "value": "0" }, "sm": { "value": "2px", "use": "inline code, small tags, badges" }, "md": { "value": "4px", "use": "code blocks, buttons, small elements" }, "lg": { "value": "6px", "use": "cards, callout boxes" }, "xl": { "value": "8px", "use": "larger panels, modals (if ever needed)" }, "full": { "value": "9999px", "use": "pills, avatars, toggle tracks" } }, "layout": { "_meta": { "philosophy": "Prose lives in a reading column. Code breaks wider. The width shift signals the register change from narrative to evidence." }, "prose": { "value": "45rem", "px": 720, "approxCh": "~65ch at 18px serif", "description": "Reading column max-width. Sweet spot for sustained reading." }, "codeBreak": { "value": "52.5rem", "px": 840, "description": "Code block max-width. Wider breakout creates narrow-wide-narrow rhythm." }, "container": { "value": "68.75rem","px": 1100, "description": "Outer container max-width. Provides margin for the prose column." }, "sideGutter": { "value": "1.5rem", "px": 24, "description": "Minimum horizontal padding on small screens." } }, "shadows": { "_meta": { "philosophy": "Nothing gleams. Nothing floats. If something casts a shadow, it's the small soft shadow of a card sitting on a desk — barely there." }, "sm": { "value": "0 1px 3px rgba(43, 36, 33, 0.04)", "use": "Subtle lift — barely perceptible. Cards at rest." }, "md": { "value": "0 2px 8px rgba(43, 36, 33, 0.06)", "use": "Card on a desk — the maximum depth in this system." }, "none": { "value": "none", "use": "Explicit no-shadow override." } }, "motion": { "_meta": { "philosophy": "Fast, barely-there. The confidence of something that doesn't need to announce itself. Reduce to zero for prefers-reduced-motion." }, "duration": { "instant": { "value": "0ms", "use": "Reduced motion fallback." }, "fast": { "value": "100ms", "use": "Color transitions (hover, focus)." }, "normal": { "value": "150ms", "use": "Standard interactions — the site's default." }, "slow": { "value": "250ms", "use": "Layout shifts, expand/collapse (rare)." } }, "easing": { "default": { "value": "cubic-bezier(0.25, 0.1, 0.25, 1.0)", "use": "Standard ease — smooth, natural deceleration." }, "inOut": { "value": "cubic-bezier(0.45, 0.05, 0.55, 0.95)", "use": "Symmetric transitions." } }, "reducedMotion": { "rule": "@media (prefers-reduced-motion: reduce)", "behavior": "All durations set to 0ms. All transitions disabled. Non-negotiable." } }, "rationale": { "colorPhilosophy": { "title": "Why these specific colors", "explanation": [ "The surface-base (#F5F0E8) was tuned to sit precisely between 'warm' and 'yellow.' Its RGB channels (245, 240, 232) taper from R→G→B, placing the warmth in the red channel without letting it become cream or beige. It reads as 'good light on heavy paper' — the brief's exact intent.", "Text-primary (#2B2421) avoids the blue-black of browser defaults (which typically live around #1a1a2e or #333). The brown-black comes from keeping R > G > B at the dark end: (43, 36, 33). This is ink with warmth, not ink with coldness.", "The accent-primary (#A0522D, CSS 'sienna') is a historically grounded earth pigment — literally fired earth. At 4.95:1 contrast on base, it passes AA for body text and works as link color without being 'red' or 'alarming.' The hover state (#8B4726) darkens toward the earth rather than toward black.", "Accent-secondary (#7D6C2F) captures tarnished brass — the green-gold of aged copper alloy, not the bright gold of decoration. It needed darkening from the first candidate to meet AA (4.56:1), but the constraint improved the color: real tarnished brass IS darker than you'd first guess.", "State colors (success, warning, error, info) were designed within the warm palette. No saturated primaries. Success uses sage-moss (#4A5E3A on #E8EDDF), warning uses amber (#7A5C1F on #F2E8D0), error uses deeper terracotta (#8B3A2A on #F2DED6). Even the info state avoids blue entirely — it's warm neutral (#4A4540 on #E5E2DA)." ] }, "contrastStrategy": { "title": "How we exceeded WCAG requirements", "explanation": [ "The brief demanded WCAG AAA (7:1) for body text on base. We achieved 13.44:1 — nearly double the requirement. This provides comfortable reading even in imperfect lighting conditions or on devices with lower contrast ratios.", "Secondary text at 5.46:1 (AA requires 4.5:1) gives comfortable headroom. Tertiary text at 3.04:1 meets AA-UI (3:1) — appropriate since it's used only for supplementary information like timestamps and tags, never for essential content.", "Code text (#3D342E) on the code surface (#EEEAE2) achieves 10.12:1 (AAA). Code is evidence — it must be maximally readable.", "Border tokens are split into three tiers: subtle (decorative, no contrast requirement — the 'score line'), default (separators), and strong (#8E857A at 3.20:1, for functional UI elements). This acknowledges that a publishing site's dividers are decorative, not interactive, while still providing accessible borders when needed." ] }, "typographyRationale": { "title": "Three voices, mathematically grounded", "explanation": [ "The Major Third ratio (1.25) was chosen because the brief explicitly asked for conservative hierarchy. At 1.25, the jump from body (18px) to H4 (22px) is perceptible but not dramatic — the family change from serif to sans does most of the work. Weight and family, not size, create the hierarchy.", "Heading sizes round to clean values: 22, 28, 36, 44px. Each pair's ratio stays within 1.17-1.29 of true Major Third — close enough for mathematical coherence, rounded enough for pixel clarity.", "The 18px body base was set by the brief, and it's correct for sustained technical reading in a serif face. At 1.125rem, it inherits browser zoom gracefully.", "Code at 16px (1rem / 0.9em of body) respects the 'different register' described in the aesthetic guide. JetBrains Mono at 16px with 1.6 line-height gives comfortable code reading without competing with the prose voice.", "Letter-spacing uses negative tracking for headings (-0.02em at h1, tapering to -0.005em at h4) because Inter at display sizes needs tightening to feel intentional. Body prose and code use normal tracking — the fonts were designed for these sizes.", "Blockquote at 20px italic is the only off-scale value — sitting between base (18) and lg (22). This is deliberate: a pull quote should feel like a different register, not a heading. The italic + size shift + left border treatment (defined in spacing) makes the voice unmistakable." ] }, "spacingRationale": { "title": "Book typography meets code breakout", "explanation": [ "The 8px grid provides the full range from fine-grain (4px component padding) to macro (96px section spacing). All semantic tokens map onto grid multiples.", "H2 above-spacing (64px / 4rem) creates the 'chapter break' the aesthetic guide describes. At nearly 4x the paragraph gap, it creates a decisive pause in the scroll. H2 below-spacing (16px / 1rem) is deliberately tight — the heading belongs to what follows, not what precedes it.", "Paragraph gap (24px) is ~1.33em at 18px base — within the 1.2-1.5em range specified, and landing on the 8px grid (3x base).", "Code block vertical margin (40px / 2.5rem) positions code as 'exhibited artifacts' — clearly separated from prose without creating visual gaps. The 3px left accent line in terracotta signals the register change from narrative to evidence.", "The prose column at 720px (45rem) produces ~65 characters per line at 18px Source Serif 4 — the typographic sweet spot for sustained reading. Code breaks to 840px (52.5rem) creating the narrow-wide-narrow rhythm described in the aesthetic guide." ] }, "borderRadiusRationale": { "title": "Worn edges, not machined radii", "explanation": [ "Four meaningful stops: 2px (inline code), 4px (code blocks, buttons), 6px (cards), 8px (larger panels). The progression feels like increasingly worn edges on workshop materials — slight softening, never roundness.", "No radius exceeds 8px except 'full' (pills/avatars). Nothing on this site should look like a mobile app button or a glassmorphism card." ] }, "motionRationale": { "title": "Fast, barely-there, respectful", "explanation": [ "150ms is the site's default transition — fast enough to feel instant, slow enough to not be jarring. Color transitions (hover, focus) at 100ms. Layout transitions at 250ms (rare — this is a reading site, not an app).", "prefers-reduced-motion reduces all durations to 0ms, no exceptions. This is non-negotiable.", "Only GPU-accelerated properties (transform, opacity) should be animated. Color transitions are the exception — they're so fast (100ms) that the CPU cost is negligible." ] }, "whatWeDidNotDo": { "title": "Intentional omissions", "explanation": [ "No dark mode tokens. The aesthetic guide explicitly says 'Ken's work happens in daylight.' Dark mode can be added later if needed — the semantic naming makes it straightforward.", "No elevation system. The brief says 'nothing floats.' Two shadow tokens (sm, md) are the maximum depth vocabulary.", "No animation choreography. A publishing site doesn't need entrance animations, scroll-triggered effects, or page transitions. Links change color. That's it.", "No breakpoint tokens. The layout is a single column that narrows gracefully. The prose column (720px) and code breakout (840px) handle their own responsive behavior within the 1100px container.", "No z-index scale. Nothing overlaps. The page is flat paper with ink on it." ] } } } ``` --- ## Contrast Audit Results Every text/background pairing was tested computationally. Full results: ### Body Text (WCAG AAA — 7:1 required) | Pairing | Ratio | Result | |---|---|---| | `text-primary` (#2B2421) on `surface-base` (#F5F0E8) | **13.44:1** | PASS | | `text-primary` (#2B2421) on `surface-card` (#FEFCF7) | **14.87:1** | PASS | | `text-primary` (#2B2421) on `surface-code` (#EEEAE2) | **12.71:1** | PASS | | `text-primary` (#2B2421) on `surface-inset` (#E8E3DA) | **11.93:1** | PASS | ### Secondary Text (WCAG AA — 4.5:1 required) | Pairing | Ratio | Result | |---|---|---| | `text-secondary` (#6B5F55) on `surface-base` (#F5F0E8) | **5.46:1** | PASS | | `text-secondary` (#6B5F55) on `surface-card` (#FEFCF7) | **6.04:1** | PASS | | `text-secondary` (#6B5F55) on `surface-code` (#EEEAE2) | **5.16:1** | PASS | ### Tertiary Text (WCAG AA UI — 3:1 required) | Pairing | Ratio | Result | |---|---|---| | `text-tertiary` (#948880) on `surface-base` (#F5F0E8) | **3.04:1** | PASS | | `text-tertiary` (#948880) on `surface-card` (#FEFCF7) | **3.36:1** | PASS | ### Accent Links (WCAG AA — 4.5:1 required) | Pairing | Ratio | Result | |---|---|---| | `accent-primary` (#A0522D) on `surface-base` (#F5F0E8) | **4.95:1** | PASS | | `accent-primary` (#A0522D) on `surface-card` (#FEFCF7) | **5.48:1** | PASS | | `accent-primary` (#A0522D) on `surface-code` (#EEEAE2) | **4.68:1** | PASS | | `accent-primaryHover` (#8B4726) on `surface-base` (#F5F0E8) | **6.12:1** | PASS | | `accent-secondary` (#7D6C2F) on `surface-base` (#F5F0E8) | **4.56:1** | PASS | | `accent-secondary` (#7D6C2F) on `surface-card` (#FEFCF7) | **5.05:1** | PASS | ### Code Text (WCAG AAA — 7:1 required) | Pairing | Ratio | Result | |---|---|---| | `code-text` (#3D342E) on `surface-code` (#EEEAE2) | **10.12:1** | PASS | ### State Colors (WCAG AA — 4.5:1 required) | Pairing | Ratio | Result | |---|---|---| | `success-text` (#4A5E3A) on `success-bg` (#E8EDDF) | **5.96:1** | PASS | | `warning-text` (#7A5C1F) on `warning-bg` (#F2E8D0) | **5.10:1** | PASS | | `error-text` (#8B3A2A) on `error-bg` (#F2DED6) | **5.92:1** | PASS | | `info-text` (#4A4540) on `info-bg` (#E5E2DA) | **7.32:1** | PASS | ### Functional Borders (WCAG AA UI — 3:1 required) | Pairing | Ratio | Result | |---|---|---| | `border-strong` (#8E857A) on `surface-base` (#F5F0E8) | **3.20:1** | PASS | | `border-strong` (#8E857A) on `surface-card` (#FEFCF7) | **3.54:1** | PASS | **Note:** `border-subtle` and `border-default` are decorative (score lines, separators) and do not carry WCAG contrast requirements per [WCAG 1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html) — decorative borders that don't convey information are exempt. `border-strong` is provided for any functional UI borders that DO need 3:1. --- ## Implementation Notes ### CSS Custom Properties (recommended structure) ```css :root { /* Surfaces */ --surface-base: #F5F0E8; --surface-card: #FEFCF7; --surface-code: #EEEAE2; --surface-inset: #E8E3DA; /* Text */ --text-primary: #2B2421; --text-secondary: #6B5F55; --text-tertiary: #948880; /* Accents */ --accent-primary: #A0522D; --accent-primary-hover: #8B4726; --accent-secondary: #7D6C2F; --accent-secondary-hover: #6B5C28; /* Code */ --code-text: #3D342E; /* Borders */ --border-subtle: #DDD7CD; --border-default: #C2BAA9; --border-strong: #8E857A; /* Focus */ --focus-ring: #A0522D; /* State: Success */ --success-bg: #E8EDDF; --success-text: #4A5E3A; --success-border: #B5C4A0; /* State: Warning */ --warning-bg: #F2E8D0; --warning-text: #7A5C1F; --warning-border: #D4BC7C; /* State: Error */ --error-bg: #F2DED6; --error-text: #8B3A2A; --error-border: #CFA090; /* State: Info */ --info-bg: #E5E2DA; --info-text: #4A4540; --info-border: #B8B2A8; /* Shadows */ --shadow-sm: 0 1px 3px rgba(43, 36, 33, 0.04); --shadow-md: 0 2px 8px rgba(43, 36, 33, 0.06); /* Typography families */ --font-prose: 'Source Serif 4', 'Source Serif Pro', Georgia, 'Times New Roman', serif; --font-structure: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --font-evidence: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, monospace; /* Spacing */ --space-0: 0; --space-px: 1px; --space-0-5: 0.25rem; --space-1: 0.5rem; --space-1-5: 0.75rem; --space-2: 1rem; --space-2-5: 1.25rem; --space-3: 1.5rem; --space-4: 2rem; --space-5: 2.5rem; --space-6: 3rem; --space-8: 4rem; --space-10: 5rem; --space-12: 6rem; /* Border radius */ --rounded-none: 0; --rounded-sm: 2px; --rounded-md: 4px; --rounded-lg: 6px; --rounded-xl: 8px; --rounded-full: 9999px; /* Layout */ --width-prose: 45rem; --width-code: 52.5rem; --width-container: 68.75rem; --gutter: 1.5rem; /* Motion */ --duration-fast: 100ms; --duration-normal: 150ms; --duration-slow: 250ms; --ease-default: cubic-bezier(0.25, 0.1, 0.25, 1.0); --ease-in-out: cubic-bezier(0.45, 0.05, 0.55, 0.95); } @media (prefers-reduced-motion: reduce) { :root { --duration-fast: 0ms; --duration-normal: 0ms; --duration-slow: 0ms; } } ``` ### Font Loading (recommended) ```html ``` --- ## Success Criteria - **Functional:** All tokens resolve to concrete CSS values. Zero undefined variables. - **Aesthetic:** Every color reads warm. The page feels like paper and ink under good light. - **Accessibility:** AAA body text (13.44:1), AA secondary (5.46:1), AA accent links (4.95:1). All verified. - **Performance:** Three fonts, minimal weights. No heavy shadow/blur calculations. - **Longevity:** Nothing here will look dated in 5 years. Paper, ink, and careful spacing don't go out of style.