Skip to content

Foundations

Typography

Three families with one voice: Inter for the interface, Inter Tight for hierarchy, JetBrains Mono for code and numbers. Every role has a fixed size, line height and tracking.

Families

All three are open source (SIL OFL 1.1) and self-hosted in the app bundle — no third-party font CDN at runtime.

Precise, calm interface text
font-sansSIL OFL 1.1

Interface text, controls, body copy. Optimised for small sizes on screens.

Confident hierarchy
font-displaySIL OFL 1.1

Headings and headline numbers. Same DNA as the UI face, tighter at large sizes.

btc_1d_close = 109241
font-monoSIL OFL 1.1

Code, identifiers, log output. Also used for dense tabular numerals.

Scale

Ten roles. If a size is missing, the answer is usually to use an existing role rather than invent a value.

display40px / 1.06 / -0.030em
Volatility regime
One hero statement per view
display-sm32px / 1.12 / -0.026em
Research overview
Page titles
heading24px / 1.20 / -0.022em
Drawdown analysis
Section headings
heading-sm20px / 1.25 / -0.018em
Rolling correlation
Sub-section headings
title17px / 1.35 / -0.012em
Chart card title
Card and panel titles
body-lg16px / 1.60 / -0.006em
Introductory paragraphs and leads.
Lead paragraphs
body14px / 1.55 / -0.002em
Default body copy for dense product surfaces.
Body text
label13px / 1.40 / 0.002em
Form labels, buttons, table cells
Controls and dense rows
caption12px / 1.45 / 0.005em
Meta text, timestamps, deltas
Secondary meta
micro11px / 1.40 / 0.080em
metric label
Uppercase metric labels only

Numeric text

Tabular figures are mandatory wherever a number can change. Digits occupy equal width, so values do not jitter when they update.

Tabular vs proportional

Same string, two figures. Only the tabular version stays stable when the value changes.

Proportional — never use for data

109,241.00108,977.00

Tabular — luc-numeric

109,241.00108,977.00

NumericText component

$128,431+12.4%48.3M
<NumericText value={109241} kind="currency" />

Using text components

Text component API
ComponentAPINotes
Headingsize="display" | "display-sm" | "heading" | "heading-sm" | "title"Uses the display face and balanced wrapping.
Textvariant="body-lg" | "body" | "label" | "caption" | "micro"Plus tone: primary…disabled, accent, positive, negative.
CodeblockInline by default; `block` renders a monospaced panel.
NumericTextvalue, kind="number" | "decimal" | "percent" | "currency" | "compact"Always tabular; `—` for missing values.
KbdchildrenKeyboard hints inside tooltips and docs.

Rules

Do

  • Use one display heading per view.
  • Reach for micro only on short uppercase labels.
  • Set numbers in luc-numeric, including table cells.

Don't

  • Introduce a fourth family or a one-off weight.
  • Use tracking overrides to squeeze text into a box.
  • Set long prose in the display face.
Luc UI v1.0Typographydark theme