var(--paper)Primary canvas and the light theme ground.
Visual language / v2.0
A bound catalogue of paper, ink, type, movement, and the custom instruments that hold the archive together.
Scope This page is additive and intentionally separate from the public archive. It is the source of truth for future site-wide component work.
Point of view Controls are treated as instruments on a proof sheet: clear state, visible focus, blue seal ink, and no decorative chrome without a job.
01 / Foundation
Paper, ink, and blue registration marks.
var(--paper)Primary canvas and the light theme ground.
var(--surface)Raised paper for cards and controls.
var(--ink)Long-form reading and high-contrast headings.
var(--ink-muted)Secondary metadata and quiet instructions.
var(--brand)Links, active states, and the registration mark.
var(--brand-tint)A soft field behind selected controls.
var(--status-error)Validation failures and destructive outcomes.
var(--status-success)Completed saves and healthy metadata.
var(--status-warning)Work in progress and experimental marks.
var(--status-info)Neutral notices that need no action.
02 / Voice
Editorial voice with utility labels.
var(--font)Charter / Palatino / Georgia fallback for essays.
var(--display)Cormorant for a small editorial accent.
var(--sans)Futura for navigation, controls, and labels.
var(--mono)Coordinates, token values, and system notes.
Article body
.proseThe most-used typographic surface on the site, and the one every published article renders into. It is a global class in app.css rather than a component, because Velite hands the routes compiled HTML that gets written straight into the page.
Body copy sets the reading rhythm: a serif face, a generous measure, and line-height that lets a long paragraph feel like a page rather than a panel. Inline links carry the blue mark, and emphasis stays quiet enough not to interrupt the line.
A pulled quote sits slightly outside the column, so the eye registers it as a different voice.
Inline code borrows the annotation mono face, and a horizontal rule closes a movement.
03 / Rhythm
Measured breathing room for quiet pages.
space-14pxMicro gap between a label and a mark.
space-28pxControl internals and compact lists.
space-316pxThe smallest comfortable content gap.
space-424pxCard padding and related content.
space-540pxSection rhythm on narrow screens.
space-664pxDesktop section rhythm and margins.
04 / Edges
Hairlines, dots, and focus rings.
1px solid var(--hairline)Quiet edges around paper surfaces.
1px solid var(--hairline-strong)Interactive edges and field boundaries.
radial-gradient(circle, ...)The archive and chapter divider signature.
2px solid var(--brand)Visible keyboard focus with a 3–4px offset.
05 / Depth
Small physical offsets, never floating UI.
rgb(20 20 19 / 14%)A close, soft edge for physical controls.
0 16px 36px rgb(20 20 19 / 8%)Reserved for lifted image cards and modals.
8px 8px 0 blue / 12%The design-system specimen card’s physical offset.
06 / Instruments
Everyday controls in their native habitat.
Clear hierarchy, compact language, and visible working states.
Editorial cards, loading placeholders, and a useful empty drawer.
Specimen
Specimen
Empty / archive
Help, validation, counters, typeahead, and direct manipulation.
Binary, single-choice, mixed, and annotated controls.
Checkbox
Radio
Switch
Location, local view state, and movement through long archives.
Status should explain what happened and what remains possible.
Long explanations stay available without making every page dense.
Use blue for links, active controls, focus, and explicit registration marks. It should guide the eye, not tint every surface.
Motion confirms a change or preserves spatial context. Reduced-motion users receive the same state change without travel or rotation.
They are ready for review here. Existing pages remain unchanged until a separate migration pass is approved.
Every catalogued component, its props, and their defaults.
A unit test parses each component's interface Props and fails if this table drifts from the source, so the two cannot disagree silently.
Single-open disclosure with roving arrow-key focus.
items*Item[]openbindablenumber0idstringautoInline status message; error tone announces assertively.
title*stringmessagestring''tone'info' | 'success' | 'warning' | 'error''info'dismissiblebooleanfalseopenbindablebooleantruechildren*Snippetactions*SnippetCatalogue label. Uses variant, not tone — these are taxonomy, not status.
label*stringvariant'canonical' | 'one-off' | 'experiment''canonical'dotbooleanfalseLocation trail; the final item renders as current, not a link.
items*Item[]Primary action control with loading and icon support.
label*stringvariant'ink' | 'outline' | 'quiet' | 'text''outline'size'sm' | 'md''md'type'button' | 'submit' | 'reset''button'disabledbooleanfalseloadingbooleanfalseicon*WeBaseIconNamefullbooleanfalseonclick*(event: MouseEvent) => voidEditorial surface. The ink variant inverts and steps forward.
eyebrowstring'Specimen'title*stringbodystring''variant'paper' | 'ink' | 'outline''paper'metastring''actionstring''children*Snippetfooter*SnippetCheckbox with optional description and indeterminate state.
label*stringcheckedbindablebooleanfalsedisabledbooleanfalseindeterminatebooleanfalsedescriptionstring''Modal with focus trap, scroll lock, and focus restoration.
openbindablebooleanfalsetitlestring'A quiet confirmation'messagestring'Dialogs keep…'idstringautoconfirmLabelstring'Confirm'Dot rule, optionally captioned; also runs vertically.
labelstring''verticalbooleanfalseEmpty drawer with one recovery action.
titlestring'No notes in this drawer'messagestring'Start a new note…'actionLabelstring'Create note'onclick*(event: MouseEvent) => voidchildren*Snippetactions*SnippetSingle-line input wiring label, help, and error into aria-describedby.
label*stringidstringautoplaceholderstring''helpstring''errorstring''type'text' | 'email' | 'search''text'valuebindablestring''requiredbooleanfalsedisabledbooleanfalseRenders one of 23 inlined Lucide glyphs. Decorative by default.
name*WeBaseIconNamesizenumber18strokeWidthnumber1.7fillstring'none'classstring''ariaHiddenbooleantrueRound toggle. Accepts any icon name; fill reads on closed shapes.
label*stringiconWeBaseIconName'arrow-up-right'pressedbindablebooleanfalsedisabledbooleanfalseonclick*(event: MouseEvent) => voidRiffling page indicator for indeterminate waits.
labelstring'Loading'Numbered pager that clamps at both ends.
totalnumber5pagebindablenumber1labelstring'Pagination'Determinate progress with a semantic tone.
valuenumber62labelstring'Progress'tone'brand' | 'success' | 'warning' | 'error''brand'compactbooleanfalseSingle choice within a named group.
name*stringlabel*stringvalue*stringselectedbindablestring''disabledbooleanfalsedescriptionstring''Kicker, title, and optional note that opens a catalogue section.
kicker*stringtitle*stringnotestring''headingId*stringListbox with typeahead, arrow keys, and Home/End.
label*stringidstringautooptions*Option[]valuebindablestringfirst optionhelpstring''errorstring''disabledbooleanfalseLoading placeholder announced as busy.
rowsnumber3mediabooleantruelabelstring'Loading content'Range input with a printed value readout.
label*stringvaluebindablenumber48minnumber0maxnumber100stepnumber1unitstring'%'idstringautoBinary setting that takes effect immediately.
label*stringcheckedbindablebooleanfalsedisabledbooleanfalsedescriptionstring''Tablist with roving focus; every panel stays mounted.
items*string[]activebindablenumber0panelsstring[][]labelstring'Example tabs'idstringautoMulti-line input with a live character counter.
label*stringidstringautoplaceholderstring''valuebindablestring''helpstring''maxLengthnumber240errorstring''Transient confirmation from a permanently mounted live region.
openbindablebooleanfalsetitlestring'Saved locally'messagestring'The specimen is ready…'tone'success' | 'info' | 'error''success'durationnumber0Hover and focus hint; Escape dismisses without moving focus.
label*stringtext*stringidstringauto07 / Marks
A small vocabulary of marks.
Interface icons use Lucide at 1.6–1.8px stroke width. The custom Seal remains the only brand mark: product meaning comes from a shared stroke vocabulary, not a mixture of Unicode symbols.
Two trade-offs worth knowing before this set grows. WeBaseIcon does not import glyphs by name — it inlines all 23 path definitions as one literal and imports only Lucide's generic renderer, so tree-shaking never applies: every route using an icon ships all 23 (about 1.5 KiB gzip). That inlined copy is also pinned, so upstream Lucide corrections do not reach it. Both are comfortable at this size; revisit if the set nears three figures.
08 / Time
A page turn, a nudge, a measured pause.
var(--duration-fast)A control moves only far enough to confirm contact.
var(--duration-ui)New content enters from the edge that owns it.
var(--ease-out)Selection resolves with a short, precise snap.
child × 40msRelated rows arrive together, never as confetti.
Purpose Movement explains cause, hierarchy, or spatial origin.
Frequency Repeated actions lose flourish after the first response.
Reduced motion Keep the state change; remove travel, delay, and page turns.
09 / Surface
Paper, pressure, translucency, and overprint.
Low contrast, almost felt rather than seen.
Blue mark softens into the paper instead of becoming a gradient.
Offset lines and marks make the page feel printed by hand.
Depth comes from pressure and light, without adding another color.
A useful echo for drafts, receipts, and saved states.
ARCHIVETranslucency reveals context while keeping the annotation distinct.
FIELDHalftone and multiply create depth with only paper, ink, and pressure.