Type Specimen
H1
Lato 700
4rem / 1.1
Electrical Intelligence
H2
Lato 700
3rem / 1.2
Electrical Intelligence
H3
Lato 700
2rem / 1.3
Electrical Intelligence
body-large
Inter 400
1.25rem / 1.6
Electrical Intelligence — real-time energy monitoring for commercial buildings.
body
Inter 400
1rem / 1.6
Electrical Intelligence — real-time energy monitoring for commercial buildings.
body-small
Inter 400
0.875rem / 1.6
Electrical Intelligence — real-time energy monitoring for commercial buildings.
mono
JetBrains 400
0.875rem / 1.6
oklch(0.753 0.1279 191.57) // brand.verdigris
Print + Slide Type Specimen — new tier roles (PR-G)

Demonstrates the canonical print/slide token roles. Each row labels the token name (left), the print pt + web rem mapping (mono), and a render at the rem value. Floor/ceiling rows are marked with their relationship to the default.

display.cover
Lato 700
2.375rem / 38pt print
Telemetry as Contract
display.cover-min
floor
2rem / 32pt
Telemetry as Contract
display.cover-max
ceiling
3rem / 48pt
Telemetry
display.slide-h1
title slide
56pt
Pilot kickoff
headline.page
case-study H1
1.875rem / 30pt
A pilot, not a procurement
headline.page-min
one-pager H1
1.625rem / 26pt
A pilot, not a procurement
headline.section
print H2
1.125rem / 18pt
The argument
headline.section-max
body-slide H1
2.25rem / 36pt
The meter said the load was flat. The waveform said it was not.
headline.slide
auditorium body-slide
2.625rem / 42pt
Auditorium body H1
deck.page
print deck
0.8125rem / 13pt
Behind-the-meter visibility is the load-bearing primitive for an AI-factory grid.
deck.slide
body-slide deck
1.25rem / 20pt projected
Body-slide deck-line at projection distance.
body-display
long-form / slide body
1.25rem / 22pt slide
For thirty years, behind-the-meter telemetry has been sold to facility operators the way analytics dashboards are sold to product teams.
caption
footer / eyebrow
0.8125rem / 9pt print / 11pt slide
CEO BRIEF — POLICY AUDIENCE
micro
disclosure / credit
0.75rem / 8pt print / 10pt slide
ORCID 0000-0002-1234-5678 — Disclosure: author is CEO of Verdigris.
metric.anchor
case-study load-bearing
3.5rem / 56pt
18%
metric.callout
3-up grid (one-pager + slide)
1.5rem / 24pt
14
metric.deck
case-study pull-quote
1.0625rem / 17pt
"It changed how we think about peak."
Read-distance principle — print vs slide body

Same content, different read distance. Print is read at 18 inches; slides project at 6-30 feet. Slide context overrides body inheritance to 18pt at the slide root, with body content at 22pt (body-display). Caption / caption-strong / micro are scope-overridden inside .vd-slide to slide pt values.

PRINT — body 11pt @ 18in

Telemetry stops being a feature the moment another system depends on its cadence to be safe. The thesis of this brief is narrow and load-bearing.

SLIDE — body-display 22pt @ 6-30ft

Telemetry stops being a feature the moment another system depends on its cadence to be safe.

Floor + ceiling band — display.cover

Tokens with cell variation ship as a band: floor (min), default, ceiling (max). Authors pick within the band based on cover length, audience, or read distance. Validators check the rendered size sits inside the band.

cover-min
2rem / 32pt
Long cover compresses to floor
DEFAULT
cover
2.375rem / 38pt
Telemetry as Contract
cover-max
3rem / 48pt
Telemetry
Light + dark mode — typography is mode-invariant

Typography sizes, weights, line-heights, and letter-spacing are identical across light and dark mode. Only colors differ. Brand teal #0fc8c3 at lightness 0.75 has 2.085:1 contrast on white (fails WCAG AA-large 3:1, not just AA-body 4.5:1), and 9.54:1 on canonical dark #09090b (passes). For text on light backgrounds at every size — body, caption, AND headline accent — use brand.verdigris-on-light (#007571, 5.55:1 on white, passes AA). Numbers verified by npm run validate:wcag; CI blocks merges that introduce regressions.

LIGHT MODE — eyebrow uses brand.verdigris-on-light
CASE STUDY · APEX TRADING
A pilot, not a procurement
DARK MODE — eyebrow uses brand.verdigris
CASE STUDY · APEX TRADING
A pilot, not a procurement
Font Comparison — "Electrical Intelligence"
Lato (Display)
Electrical Intelligence
Inter (Body)
Electrical Intelligence
JetBrains Mono (Code)
Electrical Intelligence
Button Text Sample
Get Started Learn More Contact Sales Inter 600 / 0.875rem
Documentation

Typography

Font Stack

Inter (Body — shared)

Inter is the body font across both codebases. It’s a versatile, highly legible sans-serif designed for screens, with excellent support for tabular numbers and multiple weights.

  • Usage: Body text, labels, navigation, buttons, data tables
  • Weights: 400 (regular), 500 (medium), 600 (semibold), 700 (bold)
  • Loading: Google Fonts or self-hosted via next/font (Patina) or <link> (www)

Lato (Display/Headings — www only)

Lato provides visual contrast for marketing headings. It’s slightly wider and rounder than Inter, creating a more approachable feel for hero text. Patina does not use a display font — it uses Inter everywhere.

  • Usage: H1, H2, H3 headings on marketing pages
  • Weights: 700 (bold) only — headings don’t need medium/regular
  • Where: www applies font-display class to all h1–h6 via @layer base

JetBrains Mono (Code — Patina canonical)

Patina uses JetBrains Mono for all monospace contexts. The www site falls back to system monospace. JetBrains Mono has excellent ligatures and is designed for code readability.

  • Usage: Code blocks, terminal output, metrics, IDs, timestamps, CLI commands
  • Weights: 400 only

Font Evaluation (Inter+Lato vs Alternatives)

The current Inter+Lato pairing is the baseline to evaluate against. Potential directions:

Option A: Keep Inter + Lato (current www)

  • Pros: No migration cost, familiar to users, Lato is widely available
  • Cons: Lato is ubiquitous (Google’s #3 most popular font), limited brand differentiation
  • Verdict: Safe, not distinctive

Option B: Inter for everything (current Patina)

  • Pros: Simplest stack, one font to load, consistent across app and marketing
  • Cons: No typographic contrast between headings and body — marketing pages feel flat
  • Verdict: Works for apps, insufficient for marketing

Option C: Inter + a geometric display font

  • Candidates: Plus Jakarta Sans, General Sans, Satoshi, Cabinet Grotesk
  • Pros: More personality than Lato, still clean/tech-forward
  • Cons: Requires evaluation and licensing review
  • Verdict: Worth exploring in Phase 3

Option D: A single variable font with wide weight range

  • Candidates: Instrument Sans, Space Grotesk
  • Pros: One font file, weight variation creates hierarchy
  • Cons: Less typographic contrast than a serif/sans pairing
  • Verdict: Modern but may not differentiate enough

Evaluation Results (2026-03-27)

Evaluated all four options against these criteria:

Criteria Weight Inter+Lato (A) Inter-only (B) Inter+Geometric (C) Single Variable (D)
Brand fit High Good — clean, approachable Flat — no hierarchy contrast Excellent — fresh, distinctive Good — modern
Migration cost High Zero Low (remove Lato) Medium (add new font, test) Medium
Performance Medium 2 fonts, well-cached (Google #3 + #1) 1 font, fastest 2 fonts, may need self-hosting 1 font
Patina alignment Medium Divergent (Patina = Inter-only) Perfect alignment Divergent Divergent
Licensing Low Free (OFL) Free (OFL) Varies — some need licensing Varies

Option C deep dive: Plus Jakarta Sans and Satoshi were the strongest candidates. Both offer more geometric personality than Lato. However:

  • Neither is available on Google Fonts (requires self-hosting or CDN setup)
  • Introducing a new display font mid-sprint adds risk with no user-facing upside yet
  • The token architecture makes a future font swap trivial — update fontFamily.display in tokens/typography/font-family.json and rebuild

Decision: Lock Inter + Lato.

Rationale:

  1. Zero migration cost — already implemented in www, already in the token system
  2. Performance — both fonts are top-10 on Google Fonts, maximizing cache hits across the web
  3. Good enough — Lato at 700 weight provides sufficient heading contrast for marketing pages
  4. Future-proof — the token system decouples the font choice from every consumer. If we want to explore a geometric display font later, it’s a single JSON change + rebuild. No reason to block the website upgrade sprint on a font decision.
  5. Patina stays Inter-only — the display font is a justified www deviation (marketing needs font contrast that an app dashboard doesn’t)

Locked fonts:

  • Body: Inter (shared across all surfaces)
  • Display: Lato (www marketing headings only)
  • Mono: JetBrains Mono (code, metrics, data)

Review trigger: Revisit if/when Verdigris rebrands or if user research indicates the typography feels generic. The token architecture ensures a swap is low-cost when the time comes.

Type Scale

All values from production CSS. This repo is the canonical source of truth.

Headings

Level Desktop Mobile (<1024px) Weight Line Height Letter Spacing
H1 4rem (64px) 2.75rem (44px) 700 1.1 -0.02em
H2 3rem (48px) 2rem (32px) 700 1.2 -0.02em
H3 2rem (32px) 1.5rem (24px) 700 1.3

Note: www currently uses 991px as its mobile breakpoint. The canonical target is 1024px (Tailwind lg) pending migration.

Body

Name Size Line Height Usage
Large 1.25rem (20px) 1.6 Hero subtext, feature descriptions
Medium 1.125rem (18px) 1.6 Cards, summaries
Regular 1rem (16px) 1.6 Body paragraphs, lists
Small 0.875rem (14px) 1.6 Captions, metadata, fine print

1.6 is the base default. Use 1.65-1.75 on tinted/dark backgrounds per the coupling rules, and 1.7 for Narrate prose. See composition.persuade-web-page.coupling.tinted-line-height and composition.narrate-web-page.coupling.long-form-line-height.

Print stylesheets (cover, whitepaper-body, case-study, one-pager, slides) consume parallel pt values from build/dist/typography/print.css. One scale.json source; two output emissions (rem for web, pt for print). The token names are identical across surfaces; the pt mapping resolves the read-distance principle.

Display (cover headlines)

Token Print pt Role
display.cover-min 32pt Long covers compress to this floor
display.cover 38pt Whitepaper cover headline default
display.cover-max 48pt Single-line ceo_brief opens to this ceiling

Display (slide headlines, projected)

Token Print pt Role
display.slide-h1-min 48pt Long title-slide line floor
display.slide-h1 56pt Title-slide H1 / close H2 default
display.slide-h1-max 64pt Auditorium one-word title ceiling

Headline (page-level)

Token Print pt Role
headline.page-min 26pt One-pager headline
headline.page 30pt Case-study page H1
headline.page-max 38pt Cover headline upper bound (= display.cover)
headline.section-min 16pt Pull-quote tier
headline.section 18pt H2 across whitepaper-body, case-study, cover paper
headline.section-max 36pt Body-slide H1 default at slide root
headline.slide-min 40pt Body-slide H1 floor for long-distance projection (auditorium opt-in)
headline.slide 42pt Body-slide H1 auditorium default — opt in via [data-projection="auditorium"] on <body> or .vd-slide ancestor
headline.slide-max 44pt Body-slide H1 ceiling for auditorium
headline.sub 14pt H3 in whitepaper-body

Deck (subtitle / supporting line)

Token Print pt Role
deck.page-min 12pt One-pager deck
deck.page 13pt Cover deck, case-study deck, CTA strip
deck.page-max 14pt Whitepaper-body H3 / lab_tradition deck
deck.slide-min 18pt Body-slide deck floor
deck.slide 20pt Body-slide deck-line default
deck.slide-max 22pt Body-slide deck ceiling
deck.slide-title-min 22pt Title-slide deck floor
deck.slide-title 24pt Title-slide deck default
deck.slide-title-max 28pt Title-slide deck ceiling

Body (print)

Token Print pt Role
body 11pt Canonical baseline across all print cells
body-small 9.5pt Affil, table thead, references
body-display 22pt Slide-context body (long-form reading at projection distance)

Print body is normalized to 11pt across all cells (cover, whitepaper-body, case-study, one-pager). Prior cover.css and whitepaper-body.css inherited 10.5pt by accident; that 0.5pt drift is below WCAG perceptual threshold but above evaluator detectability and surfaced every cohesion-audit run. 11pt aligns with the explicit case-study spec and editorial-register references (Brookings, Stripe Press, Anthropic Core Views).

Caption / Micro

Token Print pt Role
caption 9pt Footer, eyebrow, figcaption — the most common small-text role
caption-strong 9.5pt Number-prefixed eyebrow (visual weight against the number)
micro-min 7.5pt Site-header chrome only; not content
micro 8pt Disclosure, ORCID, figure-credit
micro-max 9pt Ceiling for the micro tier — above this, use caption

Metric (anchor numbers)

Token Print pt Role
metric.deck 17pt Case-study pull-quote tier
metric.callout 24pt One-pager 3-up grid AND body-slide 3-up grid
metric.anchor-min 40pt Compact callout floor
metric.anchor 56pt Case-study anchor / single-anchor slide
metric.anchor-max 72pt Auditorium close-slide ceiling

Anchor metrics use Lato 700 + tnum + tracking 0 + line-height 1.0. A 56pt headline uses tracking -0.02em + line-height 1.10. Same size, different typographic treatment, different role — that is why metric is its own tier, not a headline alias.

Foot-gun: don’t use fontSize.h1 in print stylesheets

fontSize.h1 is the legacy web token at 4rem (64px). It is preserved verbatim for Patina and www consumer compatibility. Print stylesheets must not reach for it; reach for display.cover (38pt) or headline.page (30pt) directly. Aliasing display.cover to fontSize.h1 would couple the cover headline to every web h1 consumer and silently move it on any future tweak.

Slide-root override

The slide stylesheet sets a slide-context body inheritance (18pt) at the slide root via .vd-slide { font-size: 18pt }, distinct from the 11pt print body inherited by cover, whitepaper-body, case-study, and one-pager. This codifies the read-distance principle: print is read at 18 inches; slides project to 6-30 feet. Slide-context tokens (display.slide-h1, headline.section-max, deck.slide, body-display, metric.callout) carry the projection-scaled pt values.

In addition, three canonical tokens are scoped-overridden at .vd-slide:

Token Print pt Slide pt Why
caption-strong 9.5pt 12pt Slide eyebrow + callout label legible at projection distance
caption 9pt 11pt Footer chrome + figure-label readable from row N of the room
micro 8pt 10pt Figure credit at slide minimum

Print stylesheets loaded in the same document keep their print pt values for these tokens; the override is scoped to .vd-slide descendants only.

Body Measure (Line Length)

The number of characters per line of body text. This is one of the highest-leverage typography decisions — it controls reading rhythm more than font choice, size, or leading does.

Canonical measure: 65ch (default) / 75ch (maximum).

Surface Target Hard maximum
Platform / product / case-study body 65-68ch 75ch
Narrate / inform (editorial) 65ch 70ch
Tinted or dark surface 65ch 65ch (explicit)
Marketing hero subtext 50-55ch 60ch
Dashboard / tabular 45-55ch (not enforced — data rules dominate)

At our type scale (Inter 16px body), 1ch ≈ 8px. So:

Measure Roughly
45ch 360px
65ch 520px — comfortable reading
68ch 544px — our default
75ch 600px — absolute upper bound
90ch 720px — too wide, rejected

Why these numbers

The Quiet Reader + Precision Instrument model demands reading comfort first. Marketing pages that feel like product docs (which ours do — technical audience, specification-heavy copy) must honor the typography literature. A 100ch column says “this is brochure copy nobody will read end-to-end.” A 65ch column says “I expect you to read this.”

Three sources converge on the 65-75 range:

  • Apple Human Interface Guidelines — “Aim for an average of 50–75 characters per line of body text” for reading comfort in long-form content.
  • Bringhurst, Elements of Typographic Style — “Anything from 45 to 75 characters is widely regarded as a satisfactory length of line for a single-column page set in a serifed text face in a text size. The 66-character line (counting both letters and spaces) is widely regarded as ideal.”
  • Butterick, Practical Typography — “The optimal line length … is between 45 and 90 characters, with 60–80 characters being preferable.”

Every respected editorial reference lands within this range. There is no position that “100+ characters is fine for readable body text.”

Why not wider

The eye saccades (jumps ahead) in chunks of roughly 7-9 characters. Beyond ~75ch, the return sweep to the start of the next line crosses enough horizontal distance that the reader can lose their place. This is measurable: reading speed drops, comprehension drops, re-reads increase. Marketing research shows conversion drops too — people skim rather than read.

Wider lines are appropriate for scanning (tables, dashboards, data-dense displays), not for reading.

Evaluator enforcement

rules/visual-rules.ymltypography.line-length.body enforces 75ch as a hard maximum. A configured contentMaxWidth on any content page that resolves to more than 75ch is a rule violation, not a warning — meaning evaluator runs should block merges.

Consumers should pin their content column using ch units, not px or rem, so the measure stays tied to font character width regardless of type scale changes. Example:

.prose-column { max-width: 68ch; margin-inline: auto; }

When body becomes figure: the break-out patterns

Body text at 65ch is narrow. Data visualizations, tables with more than 4 columns, and hero-scale illustrations often need more horizontal room. Three canonical patterns let content escape the reading column without abandoning it. See categories/visualizations/interactive-viz.md for full specs.

Short version:

  • Inline — matches prose measure. Default for small figures, code blocks, inline formulas.
  • Breakout — widens to the content column (up to a section max, typically ~900px), centered on the viewport. Default for Canvas visualizations, charts, wide comparison tables.
  • Full-bleed — spans the full viewport width edge-to-edge. Reserved for Demonstrate-arc pages where a visualization IS the hero of a section. Use <FullBleedSection>.

Pattern choice is a design decision per surface, not a component-level default. The evaluator does not dictate the choice; it does flag ad-hoc widths that aren’t one of these three patterns.

Notes

  • CTA text-transform (uppercase) is not enforced. Buttons use sentence case.
  • Patina uses Inter for headings (no display font). The www display font (Lato) is a justified deviation for marketing contexts.
  • All values in this document are canonical. The design token JSON files are the machine-readable source of truth.