Kingdom.md — Design system (Warm Editorial)

The named-aesthetic spec Task 6 (Blade views) builds against. Produced with Anthropic's frontend-design discipline (commit to a direction before code) and grounded in working/2026-06-16-frontend-design-research.md. Success bar: elegant, minimal, fast. For a read-only markdown viewer, design is the spec.


The commitment (four questions)

  • Purpose — A read-only window into a personal markdown corpus (memory, plans, design notes). The reader is the author, reading their own work; reading comfort is the entire job.
  • ToneWarm Editorial. Paper, not dashboard. It should feel like a well-set journal, not a web app.
  • Constraints — Server-rendered Blade + hand-written CSS (Tailwind reduced to its Preflight reset — see CSS architecture), minimal Alpine; login-less, no server-side persistence (MVP); fast.
  • Differentiation — The markdown is unmistakably the hero; chrome (file tree, kingdom switcher) recedes to near-invisible until reached for. The one thing you remember: it reads like paper.

Reference lineage: Editorial Minimalism (Linear / Swiss-grid — "every pixel earns its place through typography hierarchy, not decoration"), iA Writer ("typography is the interface"), Obsidian's Minimal theme (receding chrome).


Typography

The whole quality ceiling. Get this right and most of the design follows.

  • Body — serif: 'Newsreader', Georgia, serif. 17px, line-height: 1.66, warm-ink color. Auditioned 2026-06-16 against Literata / Source Serif 4 / Lora / Vollkorn / Spectral — Newsreader held.
  • Headings — display serif: 'Spectral', Georgia, serif, font-weight: 500 (h1 600). h1 ~31px, h2 ~21px. Chosen 2026-06-16 as the better general-purpose default; Fraunces was a close, well-liked contender, parked as a theme/display face (see Deferred).
  • Chrome / UI'Figtree', ui-sans-serif, system-ui, sans-serif. The sidebar + topbar voice: a warm humanist sans that recedes as interface, distinct from the serif reading voice. Chosen 2026-06-16, replacing the initial IBM Plex Sans (read a touch cold/corporate).
  • Code / mono'IBM Plex Mono', monospace (an iA Writer nod).
  • Banned (per the frontend-design skill) — Inter, Roboto, Arial, system fonts, and the over-converged defaults (e.g. Space Grotesk). A characterful body face is the single highest- leverage rule.
  • Measure — prose capped at ~66ch (max-width: ~33rem at 17px). The sacred measure; see "Measure & code width" below for the one deliberate exception.

Color & theme

Warm paper throughout, one disciplined accent. "Dominant color + sharp accent beats a timid, evenly-distributed palette." Wire as CSS variables.

Token Value Use
paper #FAF6EF page background
paper-raised #FFFDF8 cards, code surfaces
sidebar #F7F1E7 / #F3ECE0 chrome surfaces
ink #241F1A / #2F2922 headings / body
ink-soft #6B6157 secondary, dir labels
ink-faint #9C9286 hints, resting chrome
accent #9A3B2E claret — active file, title rule, links (used sparingly)
line #E0D7C7 / #E7DFD0 hairline borders

Intentionally a light "paper" surface — a deliberate aesthetic choice, not a theming gap. A dark/sepia variant is a future option, not an MVP requirement.


Layout & chrome

  • Reading column is the hero — centered, held to the sacred measure, generous top/side whitespace.
  • Sidebar recedes — file tree + kingdom switcher sit in muted warm-grays (ink-faint), resolving to ink-soft on hover and accent when active. Quiet until reached for. (Nav mechanics — depth handling, the inline subnav, drill motion — live in nav-design.md.)
  • Frontmatter — rendered as a quiet bordered card (mono, muted) above the article, not a loud banner.
  • Hairline borders (0.5px), full-border rounded corners only (no rounded single-sided accents).

Measure & code width (baked-in decision — 2026-06-16)

"80 columns" and "the sacred measure" govern different content types, so they don't conflict:

  • Prose → the ~66ch sacred measure. Long proportional lines hurt the return sweep; this is a readability fact, and it's the default.
  • Code blocks → their own, wider width, independent of the prose column. Code must never wrap to 66ch (that mangles it). Render code to ~80 monospace columns — which is visibly wider than 66 proportional chars — via a break-out band (code extends past the text column) or horizontal scroll past 80. This is just correct typography, not a compromise, and it lands exactly what the 80-column crowd wants, where it actually matters.

Motion & speed

  • Motion — reserve it for purposeful interactions, not a page-load reveal. (Originally a staggered article fade-up on load; reconsidered — in a server-rendered viewer every doc-open is a page load, so a load reveal would replay on every navigation, which prototyping surfaced as flicker.) The live example is the subnav's directional drill slides. Restraint over flash; this aesthetic earns delight through precision.
  • Speed — server-rendered Blade + minimal Alpine is the fast path (the Sublime Text lesson: fast by doing less). The design job is not to betray it — no heavy client JS.

CSS architecture (decisions — 2026-06-18)

How the styling is authored, and how document types are namespaced.

  • Hand-written CSS + design tokens, not utility classes. The design system lives in plain CSS custom properties in :root (resources/css/app.css), ported from the validated design-prototype.html. This bespoke, art-directed look (paper grain, furl/unfurl animation, the break-out code band, the ~66ch measure) reads better as named semantic CSS than as utility-class strings — and the rendered-markdown HTML comes from CommonMark server-side, so it has no classes to hang utilities on anyway (it must be styled by element selector regardless).
  • Tailwind reduced to its Preflight reset only. app.css imports tailwindcss/preflight.css (the cross-browser base reset the CSS depends on — button font: inherit, margin/box-sizing normalization), not the full tailwindcss (theme tokens + utility engine, both unused). The @tailwindcss/typography plugin was dropped — the .md profile replaced its prose class. Net: CSS bundle ~65→20 KB, and the dependency does exactly one honest job. To bring utilities / @apply / theme() back later, re-import tailwindcss/theme.css + utilities.css (or full tailwindcss); to generate utilities from our palette, move the :root tokens into an @theme block.
  • Per-document-type render profiles; chrome stays type-agnostic. The rendered-document <article> carries a class named for its content type — .md for markdown today, with a future renderer (e.g. JSON) dropping in as a sibling .json profile on the same element, sharing the column/measure from .col/.page. The app chrome does not encode document type: the file-tree row class .row.doc (and .subnav-row.doc) means simply "a file node" (vs .dir), agnostic to extension — a .json file is still a .row.doc. Keep type-specific styling in the render profiles, never in the chrome.
  • Chrome vs prose line-height. <body> is pinned to line-height: 1.5 (the chrome — sidebar/tree/topbar) — a deliberate value, previously inherited by accident from Preflight. The reading pane overrides to the generous 1.66 on .md (the sacred reading rhythm; see Typography).

Set aside (not this aesthetic)

  • Maximalist / motion-heavy families; dark-first defaults; gradient-mesh / neon / heavy-shadow atmospherics. Wrong fit for a calm reading surface.

Deferred (config options — post-Task-6)

  • Prose reading-width preference — a toggle ("Comfortable" ~66ch default / "Wide" ~80+col) for readers who prefer denser prose. Never auto-detected from viewport — a wide screen signals the reader's display, not their preference, and auto-widening prose is exactly the readability anti-pattern the sacred measure prevents. So: the default encodes the recommendation; the option respects autonomy. Implementation: localStorage via Alpine — fully client-side, zero backend, safe under the login-less MVP. Scope beyond Task 6's "beautiful baseline," so tracked here rather than built now. (Surfaced 2026-06-16.)
  • Frontmatter display style — default is the compact tabulated key/value table (aligned label column + values). A "paper-form" variant (tiny uppercase label stacked over a larger serif value, roomy fields — like a filled-in form) was prototyped and liked as an optional alternative, not the default. Candidate reader preference; same client-side localStorage mechanism as the reading-width toggle. Exact CSS preserved (commented) in working/design-prototype.html. (Surfaced 2026-06-16.)
  • Dark / sepia reading theme — a future variant of the palette above; not an MVP need.
  • Fraunces as a display/header face — strongly liked in the 2026-06-16 type audition for headings, but Spectral won as the calmer general-purpose default. Park Fraunces as an optional theme/display face for a future theming layer (it pairs naturally with the dark/sepia variant above — a more expressive "editorial" theme). (Surfaced 2026-06-16.)