Skip to content
VVVER

Design System / 03

Typography

A host-supplied type system with roles for interface copy, display headings, code, quotations, and occasional condensed accents.

Role map

The package bundles no font files. Hosts bind their licensed faces to role variables; the catalog demonstrates the intended hierarchy with four loaded families. Switzer is the only general-purpose face. The other three have narrow, named jobs.

Technical detail

Tokens
--font-switzer, --font-geist-mono, --font-crimson, --font-saira, --vvver-code-font.
Families
Switzer (Grotesque), Geist Mono (Monospace), Crimson Text (Serif), Saira Semi Condensed (Condensed).
Weights
400 / 500 / 700 (Switzer, Saira), 400 / 600 (Crimson Text), variable (Geist Mono).
  • Switzer

    Aa Bb Gg Qq Rr — 0123456789 — making things, written down

    Switzer

    Primary grotesque · Self-hosted · 400 / 500 / 700

    The catalog default for body, navigation, headings, and display. Its base body weight is 500; hierarchy comes mainly from size, case, spacing, and measure.

  • Geist Mono

    Aa Bb Gg Qq Rr — 0123456789 — making things, written down

    Geist Mono

    Real monospace · Google next/font · variable

    Bound to --vvver-code-font for code, filenames, and telemetry. It is distinct from the catalog's font-mono alias, which remains Switzer for interface labels.

  • Crimson Text

    Aa Bb Gg Qq Rr — 0123456789 — making things, written down

    Crimson Text

    Serif voice · Google next/font · 400 / 600

    Bound to --font-serif and used only for quotations, prose, or a contrasting display line. Quote opts in with its serif prop; interface chrome stays sans.

  • Saira Semi Condensed

    Aa Bb Gg Qq Rr — 0123456789 — making things, written down

    Saira Semi Condensed

    Condensed accent · Google next/font · 400 / 500 / 700

    A catalog-only preview for rare poster-scale display. No package component consumes it, and it never becomes body or control text.

In this catalog, font-mono intentionally aliases Switzer for uppercase interface labels. Actual code bypasses that alias through --vvver-code-font. Switzer’s local files are version 1.200 and governed by the official ITF Free Font License.

css
@theme inline {
  --font-sans: var(--font-switzer);
  --font-mono: var(--font-switzer);   /* interface labels */
  --font-serif: var(--font-crimson);
}

:root {
  --vvver-code-font: var(--font-geist-mono), ui-monospace, monospace;
}

Fluid scale

Five named tokens cover display through lede. Their rem values also inherit the package’s fluid root size, so the specimens respond without breakpoint-specific type classes. Body and the canonical micro-label remain fixed role registers.

Technical detail

Tokens
--fluid-display, --fluid-h1, --fluid-h2, --fluid-h3, --fluid-h4, --fluid-lede.
Clamps
Five clamps, from clamp(2.75rem, 1.42rem + 5.9vw, 6rem) down to clamp(1.05rem, 0.99rem + 0.26vw, 1.2rem).
Fixed
Body at 1rem (500, leading 1.2); micro-label at 0.62rem (uppercase, tracking 0.12em).

Display

--fluid-display

clamp(2.75rem, 1.42rem + 5.9vw, 6rem)

Hero titles and dominant statements

Making

Heading 1

--fluid-h1

clamp(2rem, 1.41rem + 2.61vw, 3.5rem)

Major section and closing CTA titles

Things, written down

Heading 2

--fluid-h2

clamp(1.5rem, 1.21rem + 1.3vw, 2.25rem)

Section headings and page titles

Editorial structure

Heading 3

--fluid-h3

clamp(1.15rem, 1.05rem + 0.43vw, 1.4rem)

Card titles and compact headings

A smaller hierarchy

Heading 4

--fluid-h4

clamp(1rem, 0.96rem + 0.17vw, 1.1rem)

Panel and settings-group titles

The last heading step

Lede

--fluid-lede

clamp(1.05rem, 0.99rem + 0.26vw, 1.2rem)

Introductory and supporting paragraphs

A measured introduction gives the page its reading pace.

Body

1rem

Catalog base · 500 · leading 1.2

Interface copy; Prose expands leading to 1.65

Body copy stays direct and compact in the interface. Long-form reading receives a wider line height and a controlled measure.

Micro-label

House register

0.62rem · uppercase · tracking 0.12em · /60 ink

Eyebrows, metadata, and status labels

Source · 2026 · In production

Component reference

Display voices

DisplayDuet interleaves two treatments at one inherited size. Voice A is medium and uppercase; voice B is regular, natural-case, and tracked by 0.01em. It does not change font family, so it works even when a host provides no serif.

Live specimen

Rendered output

Technical detail

Component
DisplayDuet interleaves voice="a" and voice="b" at one inherited size.
Voice A
Switzer 500 · uppercase · no tracking override.
Voice B
Switzer 400 · natural case · tracking 0.01em.

Making Thingswritten down,Kept in Order

Voice A
Switzer 500 · uppercase
Voice B
Switzer 400 · natural case · tracking 0.01em

API reference

Inputs, types, and behavior

Inputlines
Type{ text, voice? }[]
BehaviorRequired lines. voice is "a" or "b"; omitted voices alternate by index.
Inputas
Type"h1" | "h2" | "h3" | "p"
BehaviorRendered element, default "h1". An empty array renders nothing.
InputclassName
Typestring?
BehaviorMerged onto the rendered element; it sets the shared size and leading.

Reading rhythm

The catalog body sits at 1rem, weight 500, with 1.2 leading. Long-form Prose keeps that size but opens to 1.65 leading and caps the measure at 68ch. Ledes use 1.5. These are separate reading contexts, not one universal line-height.

Tracking belongs to a role. The canonical micro-label is 0.62rem / 0.12em; many utility labels use 0.04em, while the medium button uses 0.075em. Display tracking usually tightens to -0.01em. Do not derive tracking from size with a blanket formula.

Scale and case carry display emphasis; bold is reserved for local, semantic stress.

The package defines four display-leading tokens: 1 / 0.85 / 0.8 / 0.75. Components choose the tier that fits their composition—Hero uses 0.85—rather than assigning a tier mechanically to every heading. Prose balances headings and wraps paragraphs pretty inside its own scope; the catalog host applies those wrap behaviors to its general headings and paragraphs too.

Natural case — correct

Body copy stays in natural sentence case so it reads easily at length.

Sentence case keeps long-form copy easy to read.

Tracked uppercase — avoid

Body copy stays in natural sentence case so it reads easily at length.

Uppercase and wide tracking belong to labels, not sentences.

Rules

  • Bind roles, not brand font names, in package component code.

  • Use the primary grotesque for all interface chrome; accents never become controls or body copy.

  • Choose at most one decorative counter-register—serif, condensed, or typewriter—in a composition.

  • Use the real mono for code and telemetry; font-mono remains the catalog's label register.

  • Keep readable text at full, /70, or /60 ink. Lower opacity is decorative only.

  • Preserve natural case for sentences; reserve uppercase and tracking for labels and display type.