Visual language / v2.0

Design System

A bound catalogue of paper, ink, type, movement, and the custom instruments that hold the archive together.

25 components10 sections3 input modes

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

Color

Paper, ink, and blue registration marks.

PaperCanonical
var(--paper)

Primary canvas and the light theme ground.

SurfaceCanonical
var(--surface)

Raised paper for cards and controls.

InkCanonical
var(--ink)

Long-form reading and high-contrast headings.

Ink mutedCanonical
var(--ink-muted)

Secondary metadata and quiet instructions.

Blue markCanonical
var(--brand)

Links, active states, and the registration mark.

Blue washCanonical
var(--brand-tint)

A soft field behind selected controls.

Errorvar(--status-error)

Validation failures and destructive outcomes.

Successvar(--status-success)

Completed saves and healthy metadata.

Warningvar(--status-warning)

Work in progress and experimental marks.

Infovar(--status-info)

Neutral notices that need no action.

LightBlue markDarkPaper is the quietest color.

02 / Voice

Typography

Editorial voice with utility labels.

Reading serifThe quiet archivevar(--font)

Charter / Palatino / Georgia fallback for essays.

Display italicA note in the marginvar(--display)

Cormorant for a small editorial accent.

Utility sansPUBLISHED / 2026var(--sans)

Futura for navigation, controls, and labels.

Annotation monospace-24 · 24pxvar(--mono)

Coordinates, token values, and system notes.

A record of making.A small title with a long tailBody copy stays generous, with enough line-height to feel like a page rather than a panel.CAPTION / 11PX / MONO

Article body

.prose

The 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.

A heading inside the body

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 subheading

  • Lists keep the same measure as the paragraphs around them.
  • Markers use the blue mark rather than a default bullet.
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

Spacing

Measured breathing room for quiet pages.

space-14px

Micro gap between a label and a mark.

space-28px

Control internals and compact lists.

space-316px

The smallest comfortable content gap.

space-424px

Card padding and related content.

space-540px

Section rhythm on narrow screens.

space-664px

Desktop section rhythm and margins.

04 / Edges

Borders

Hairlines, dots, and focus rings.

Hairline1px solid var(--hairline)

Quiet edges around paper surfaces.

Strong hairline1px solid var(--hairline-strong)

Interactive edges and field boundaries.

Dot ruleradial-gradient(circle, ...)

The archive and chapter divider signature.

Focus ring2px solid var(--brand)

Visible keyboard focus with a 3–4px offset.

05 / Depth

Shadows

Small physical offsets, never floating UI.

Book shadowrgb(20 20 19 / 14%)

A close, soft edge for physical controls.

Whisper shadow0 16px 36px rgb(20 20 19 / 8%)

Reserved for lifted image cards and modals.

Offset print8px 8px 0 blue / 12%

The design-system specimen card’s physical offset.

06 / Instruments

Components

Everyday controls in their native habitat.

07 specimen sheetsDefault + focus + disabled + errorExpanded
01

Actions

Clear hierarchy, compact language, and visible working states.

Canonical
02

Content surfaces

Editorial cards, loading placeholders, and a useful empty drawer.

Canonical

Specimen

A paper surface

A card is a small page with enough structure to hold one thought.
Updated 02 Aug

Specimen

Ink in reverse

Use the seal field sparingly, when an object needs to step forward.
Featured

Empty / archive

No notes in this drawer

Start a new note or adjust the current filters.
03

Fields

Help, validation, counters, typeahead, and direct manipulation.

Interactive
Material Arrow keys and typeahead are supported.
04

Selection

Binary, single-choice, mixed, and annotated controls.

Canonical

Checkbox

Radio

Switch

05

Navigation

Location, local view state, and movement through long archives.

Keyboard ready
A summary of the current specimen. Overview
06

Feedback

Status should explain what happened and what remains possible.

Live region
Archive completeness68%
Metadata quality92%
Riffle
Tooltips clarify a mark without interrupting the page.
07

Disclosure

Long explanations stay available without making every page dense.

Keyboard ready

Use blue for links, active controls, focus, and explicit registration marks. It should guide the eye, not tint every surface.

08

Prop reference

Every catalogued component, its props, and their defaults.

Canonical

A unit test parses each component's interface Props and fails if this table drifts from the source, so the two cannot disagree silently.

WeBaseAccordion

Single-open disclosure with roving arrow-key focus.

items*
Item[]
openbindable
number0
id
stringauto

WeBaseAlert

Inline status message; error tone announces assertively.

title*
string
message
string''
tone
'info' | 'success' | 'warning' | 'error''info'
dismissible
booleanfalse
openbindable
booleantrue
children*
Snippet
actions*
Snippet

WeBaseBadge

Catalogue label. Uses variant, not tone — these are taxonomy, not status.

label*
string
variant
'canonical' | 'one-off' | 'experiment''canonical'
dot
booleanfalse

WeBaseBreadcrumbs

Location trail; the final item renders as current, not a link.

items*
Item[]

WeBaseButton

Primary action control with loading and icon support.

label*
string
variant
'ink' | 'outline' | 'quiet' | 'text''outline'
size
'sm' | 'md''md'
type
'button' | 'submit' | 'reset''button'
disabled
booleanfalse
loading
booleanfalse
icon*
WeBaseIconName
full
booleanfalse
onclick*
(event: MouseEvent) => void

WeBaseCard

Editorial surface. The ink variant inverts and steps forward.

eyebrow
string'Specimen'
title*
string
body
string''
variant
'paper' | 'ink' | 'outline''paper'
meta
string''
action
string''
children*
Snippet
footer*
Snippet

WeBaseCheck

Checkbox with optional description and indeterminate state.

label*
string
checkedbindable
booleanfalse
disabled
booleanfalse
indeterminate
booleanfalse
description
string''

WeBaseDialog

Modal with focus trap, scroll lock, and focus restoration.

openbindable
booleanfalse
title
string'A quiet confirmation'
message
string'Dialogs keep…'
id
stringauto
confirmLabel
string'Confirm'

WeBaseDivider

Dot rule, optionally captioned; also runs vertically.

label
string''
vertical
booleanfalse

WeBaseEmptyState

Empty drawer with one recovery action.

title
string'No notes in this drawer'
message
string'Start a new note…'
actionLabel
string'Create note'
onclick*
(event: MouseEvent) => void
children*
Snippet
actions*
Snippet

WeBaseField

Single-line input wiring label, help, and error into aria-describedby.

label*
string
id
stringauto
placeholder
string''
help
string''
error
string''
type
'text' | 'email' | 'search''text'
valuebindable
string''
required
booleanfalse
disabled
booleanfalse

WeBaseIcon

Renders one of 23 inlined Lucide glyphs. Decorative by default.

name*
WeBaseIconName
size
number18
strokeWidth
number1.7
fill
string'none'
class
string''
ariaHidden
booleantrue

WeBaseIconButton

Round toggle. Accepts any icon name; fill reads on closed shapes.

label*
string
icon
WeBaseIconName'arrow-up-right'
pressedbindable
booleanfalse
disabled
booleanfalse
onclick*
(event: MouseEvent) => void

WeBaseLoader

Riffling page indicator for indeterminate waits.

label
string'Loading'

WeBasePagination

Numbered pager that clamps at both ends.

total
number5
pagebindable
number1
label
string'Pagination'

WeBaseProgress

Determinate progress with a semantic tone.

value
number62
label
string'Progress'
tone
'brand' | 'success' | 'warning' | 'error''brand'
compact
booleanfalse

WeBaseRadio

Single choice within a named group.

name*
string
label*
string
value*
string
selectedbindable
string''
disabled
booleanfalse
description
string''

WeBaseSectionHeader

Kicker, title, and optional note that opens a catalogue section.

kicker*
string
title*
string
note
string''
headingId*
string

WeBaseSelect

Listbox with typeahead, arrow keys, and Home/End.

label*
string
id
stringauto
options*
Option[]
valuebindable
stringfirst option
help
string''
error
string''
disabled
booleanfalse

WeBaseSkeleton

Loading placeholder announced as busy.

rows
number3
media
booleantrue
label
string'Loading content'

WeBaseSlider

Range input with a printed value readout.

label*
string
valuebindable
number48
min
number0
max
number100
step
number1
unit
string'%'
id
stringauto

WeBaseSwitch

Binary setting that takes effect immediately.

label*
string
checkedbindable
booleanfalse
disabled
booleanfalse
description
string''

WeBaseTabs

Tablist with roving focus; every panel stays mounted.

items*
string[]
activebindable
number0
panels
string[][]
label
string'Example tabs'
id
stringauto

WeBaseTextarea

Multi-line input with a live character counter.

label*
string
id
stringauto
placeholder
string''
valuebindable
string''
help
string''
maxLength
number240
error
string''

WeBaseToast

Transient confirmation from a permanently mounted live region.

openbindable
booleanfalse
title
string'Saved locally'
message
string'The specimen is ready…'
tone
'success' | 'info' | 'error''success'
duration
number0

WeBaseTooltip

Hover and focus hint; Escape dismisses without moving focus.

label*
string
text*
string
id
stringauto

07 / Marks

Iconography

A small vocabulary of marks.

ExternalArrowUpRight
SearchSearch
MarkSparkles
CloseX
ArchiveArchive
SaveBookmark
AdjustSettings2
InspectZoomIn

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

Motion

A page turn, a nudge, a measured pause.

Sequence / 01

Four gestures, one reading direction.

01 / ResponsePress / 140msvar(--duration-fast)

A control moves only far enough to confirm contact.

02 / RevealUncover / 200msvar(--duration-ui)

New content enters from the edge that owns it.

03 / AlignRegister / 200msvar(--ease-out)

Selection resolves with a short, precise snap.

04 / SequenceStagger / 40mschild × 40ms

Related rows arrive together, never as confetti.

0140200900 ms

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

Materials

Paper, pressure, translucency, and overprint.

Paper grain

Low contrast, almost felt rather than seen.

Ink wash

Blue mark softens into the paper instead of becoming a gradient.

Registration

Offset lines and marks make the page feel printed by hand.

Blind emboss

Depth comes from pressure and light, without adding another color.

Carbon copy

A useful echo for drafts, receipts, and saved states.

Tracing paper

Translucency reveals context while keeping the annotation distinct.

Overprint

Halftone and multiply create depth with only paper, ink, and pressure.

This page is ready for review. Existing pages remain unchanged until a separate, explicit migration pass is approved.

Return to the archive ↗

Dialog / modal

A quiet confirmation

Dialogs keep consequential actions in focus.