Design SystemFoundations

Design Foundations

The bedrock every surface shares — colour, type, spacing, radius, elevation, surfaces, materials, and the devices they target — plus the live composers that tune the palette, materials, and semantic tokens. Press ⌘K to search the whole system.

Foundations
Colors
How much of each color to use, and where. Surfaces below covers the mechanics (tokens, modes, alpha scale); this page covers the intent — a visual brand guideline you can point a partner team to when they ask "what colors can I use?". The palette stays small on purpose: two neutrals carry every surface, one primary accent anchors the brand, and a tight set of semantic + decorative accents handle everything else.

Brand colors — palette + usage ratio

Three accents and a 60/30/10 ratio — Ink, Sapphire, Pink. Every Product, Marketing, and Docs surface inherits these tokens.

Usage ratio — 60 / 30 / 10

60%
30%
10%
Ink

Surfaces, text, borders

Sapphire

Action — CTAs, links, focus, data

Pink

Signature accent

Brand identity — primary trio · .swatch--label-inside

Action · 30%
Sapphire #405CCF
Signature · 10%
Pink #F7C2FF
Surface · 60%
Ink #0C0E2E

Semantic — only when meaningful

Success
--success oklch(63% 0.16 155) #00A35D
Danger
--danger oklch(66% 0.18 24) #EC5B59
Warn
--warn oklch(78% 0.17 67) #FF9E00
Info
--info oklch(71% 0.15 269) #7C9BFD

Semantic state pairs — bg / border / fg per tone

Every semantic state ships three paired tokens — --{name}-bg, --{name}-border, --{name}-fg — for alert cards, callouts, toasts, info panels. The pattern: the surface uses -bg, an optional border uses -border, emphasis text + icons use -fg. All three stay in the same hue family so a success alert reads as green end-to-end. Both modes auto-flip via :root + [data-theme="light"].

Success — the bridge route was found and quoted.

Info — this preset stays put across brand-preset switches.

Warn — the rate limit will reset in 30 seconds.

Danger — the transaction was rejected by the wallet.

Success bg
--success-bg oklch(0.20 0.05 161) #001D0E
Success border
--success-border oklch(0.34 0.10 161) #004726
Success fg
--success-fg oklch(0.72 0.17 161) #00C481
Info bg
--info-bg oklch(0.20 0.05 220) #001B25
Info border
--info-border oklch(0.34 0.10 220) #00425B
Info fg
--info-fg oklch(0.72 0.16 220) #00BAE9
Warn bg
--warn-bg oklch(0.22 0.05 85) #251800
Warn border
--warn-border oklch(0.36 0.10 85) #553700
Warn fg
--warn-fg oklch(0.78 0.16 85) #E6AD00
Danger bg
--danger-bg oklch(0.20 0.05 25) #290B0A
Danger border
--danger-border oklch(0.34 0.12 25) #691214
Danger fg
--danger-fg oklch(0.64 0.21 25) #F14445

Text & icon colors --text-* · --icon-*

Semantic tokens for prose hierarchy and chrome icons. Theme-aware via the :root / [data-theme="light"] blocks; icon tokens alias text tokens today, overridable per-theme to diverge.

Six tokens drive every grayscale colour in the system. Reach for --text-* from prose / labels / numerals; reach for --icon-* from icon-only chrome (borderless icon buttons, dropdown carets, list-row affordances, navbar utility icons). Both families flip themes via the data-theme attribute on <html> — one token, two contextual values.

Text family · prose hierarchy

Theme-aware
Primary text
var(--text-primary) Headlines, hero numbers, primary body
100% ink. Anchor of the type hierarchy. Pure black in light, pure white in dark.
Theme-aware
Secondary text
var(--text-secondary) Sub-headlines, supporting copy
75% ink. Use for the second tier of prose — section descriptions, supporting paragraphs.
Theme-aware
Muted text
var(--text-muted) Descriptions, captions, eyebrows
55% ink. Quiet copy that supports the primary content — meta labels, value units, eyebrows, hints.
Theme-aware
Faint text
var(--text-faint) Chrome · axis ticks · placeholder hints
40% ink. Decorative-tier copy — below WCAG body-text contrast; use only where readability isn't the goal (axis labels, watermarks).

Icon family · chrome icons · aliases text today, overridable to diverge

Aliased
Primary icon
var(--icon-primary) = var(--text-primary) .btn-icon.btn-borderless
Default rest colour for borderless icon buttons and any icon that should match label weight. Today aliases --text-primary; override per-theme to recolour all icon chrome with one edit.
Aliased
Muted icon
var(--icon-muted) = var(--text-muted) .btn-icon.btn-borderless.btn-muted
Opt-in deemphasised icon colour. Today aliases --text-muted. Use when an icon should yield to the row's primary content — meta affordance next to a metric, secondary toolbar action.

Brand colors — extended palette --spectral-1--spectral-12

Twelve OKLCH hues extending the brand palette for charts, illustrations, decorative blocks. Stays put across preset switches.

Twelve hues at 30° OKLCH spacing — vivid but not garish, perceptually balanced for categorical data. Each cell shows the swatch, token name, named alias, and OKLCH coordinates. Hover any cell for a one-line "use it for" hint.

Coral
--spectral-1 oklch(0.72 0.20 20) #FF8C7A
Orange
--spectral-2 oklch(0.74 0.20 50) #FF9358
Amber
--spectral-3 oklch(0.82 0.18 80) #FFB454
Lime
--spectral-4 oklch(0.84 0.20 110) #C5E866
Green
--spectral-5 oklch(0.78 0.22 140) #5EEAA0
Teal
--spectral-6 oklch(0.76 0.18 175) #3DD9D9
Cyan
--spectral-7 oklch(0.78 0.18 205) #42E2F5
Sky
--spectral-8 oklch(0.74 0.20 235) #67BAFF
Blue
--spectral-9 oklch(0.70 0.22 265) #7B86FF
Violet
--spectral-10 oklch(0.66 0.22 295) #9B5DE5
Magenta
--spectral-11 oklch(0.72 0.24 325) #D472FA
Pink
--spectral-12 oklch(0.76 0.22 355) #FF8FCB

Chart subsets

For charts, pick a subset that maximises consecutive-pair distance. The default 8-series mapping (used by --series-1--series-8) goes blue → orange → green → magenta → amber → cyan → violet → coral.

4 series — most distinct quartet
6 series — extends with amber + cyan
8 series — full chart palette (default --series-1--series-8)

The surface used to render every colour above — the five sizes, three shape modifiers, chip-wrapped variants, and strip container — lives as its own component at Components → Swatch. Foundations consumes the primitive; it does not own it.

Foundations
Device resolutions & breakpoints
The screen sizes the team designs against, drawn to one shared scale so a phone reads as the sliver of a monitor it actually is. Logical viewport (what CSS sees) is the number that matters for layout; native resolution and DPR are the hardware behind it. The 1280 px MacBook Air 13" width is our practical design floor for “laptop and wider” — it's the width the Advanced Limit widget is sized to fit (see Widget). Breakpoint anchors are the industry-standard Tailwind references, shown for cross-team shorthand; LI.FI's own floating-surface widths live in the --w-* ladder (Spacing → Surface widths).

Device frames & viewport ruler

Common laptop, tablet, and phone viewports — logical size, native resolution, DPR, and the industry breakpoint anchors.

Target layout width 1280 px
xl 7 / 16 devices are at least this wide — click any frame to set the width

Laptops & desktops

QHD display2560 × 1440
FHD display1920 × 1080
MacBook Pro 16"1728 × 1117
MacBook Pro 14"1512 × 982
MacBook Air 15"1496 × 967
MacBook Air 13.6"1470 × 956
MacBook Air 13" (M1)1280 × 800 · floor

Tablets

iPad Pro 11"834 × 1194
iPad 10.9"820 × 1180

Phones · one shared scale (≈0.12× actual)

iPhone 16 Pro Max440 × 956
iPhone Plus · Pro Max430 × 932
Pixel 8412 × 915
iPhone 16393 × 852
iPhone 12–15390 × 844
iPhone SE375 × 667
Galaxy S360 × 800
Foundations
Elevation
How content is lifted off the page — through shadow, alpha state layers, or both. Three mechanisms compose: --elev-1/2/3 shadow tiers signal depth, --alpha-* overlays signal state, and the “elevation over hard borders” discipline keeps every card / row / panel reading as physical instead of utilitarian. Materials compose these tokens; components consume them directly when a full Material would be overkill.

Elevation tiers --elev-1 · --elev-2 · --elev-3

Three shadow tiers — resting cards, hover state, floating surfaces. Reach for the tier, don’t hand-author shadows.

Three card-shaped surfaces, identical fill, ascending shadow tier. Tier semantics map to UI state: --elev-1 rest → --elev-2 hover → --elev-3 floating (modals, popovers, dropdowns). Don’t skip a tier; use what the state calls for.

--elev-1 · rest
Resting card / settings row

Subtle drop + 1px white-rim highlight (dark) / gentle drop (light). The default tier for content surfaces.

--elev-2 · hover / sticky-active
Hovered row / active route

Stronger drop + brighter rim. The momentary lift signals interactivity without changing fill color.

--elev-3 · floating
Modal / popover / dropdown

Deep drop + brightest rim. Reserved for surfaces that float over the page (modals, popovers, dropdowns).

Alpha state layers

Four tinted overlays for state — recessed, inactive hover, active, active hover. Layered on top of any surface fill.

Surface elevation scale (alpha). Four tinted overlays meant to sit ON TOP of a surface fill, not replace it. Use for tracks, recessed bases, hovers, and active states — anywhere the same surface needs to read as a different state without changing palette.

--alpha-subtle
Tracks, recessed bases
--alpha-dim
Inactive hovers
--alpha-raised
Active pills, raised tiles
--alpha-overlay
Active hover, top elevation

On-alpha text scale — pair with the alpha layer beneath. Text on alpha surfaces uses different tokens than text on solid surfaces because the resolved color depends on what’s below.

Default
--on-alpha-default
Muted
--on-alpha-muted
Primary
--text-primary

Elevation over hard borders

System-wide rule — soft elevation over hard luminance steps. The Paper material systematizes this recipe; reach for the manual three-mechanic version below only when authoring outside the Materials API.

Same content rendered two ways. Left: a hard 1px hairline on a flat fill — reads as utilitarian, “form-control,” spreadsheet-cell. Right: raised fill + --elev-1 + optional 6% hairline — reads as physical, premium, lifted off the page. The right one is the rule. The Paper material bundles this exact recipe; this card documents the manual version for the rare case you author outside Materials.

Don’t — hard border
Quote summary

3 routes · best price via Stargate · ~12s

Do — raised fill + elev-1
Quote summary

3 routes · best price via Stargate · ~12s

Foundations
Materials
Surface character bundles — fill, border, shadow, backdrop-filter, and edge highlight, bundled and named. Swap a card / tile / panel from paper to glass by changing one attribute. Four canonical materials (paper · glass · gradient · halo); the Material Composer tunes their values without authoring CSS. Spec: design.md §02 → Materials.

Where this layer sits. Materials sit between Surfaces (the raw color tokens) and components (cards, tiles, panels). A material's bg field doesn't bake an oklch() literal — it references a surface token (paper.bg = var(--surface-card), glass.bg = var(--surface-panel-glass)). Components consume --mat-* and never reach into --material-*-* directly. Three layers, each owns one concern.

Overview

Materials system data-material

Three layers — definitions, resolved API, consumers. Components read --mat-*; data-material on the element picks which material is active.

Four demos — the full canonical set. Same markup, same dimensions — only data-material differs. The fill, border, shadow, backdrop, and edge highlight all flow from the chosen material. Designers compare materials at a glance; engineers swap them with one attribute change.

data-material
paper

Default. Opaque fill, soft drop, 1px hairline.

data-material
glass

Translucent + backdrop-blur. Floating panels and marketing tiles.

data-material
gradient

Brand fill (blue → pink). Hero KPIs, cover tiles.

data-material
halo

Accent wash + radial glow. Brand-identity tiles.

Card anatomy — exploded view

The five layers a card composes — page, shadow, fill, edge, content. How surfaces, elevation, and materials stack.

The same card-shape rendered with each of its layers pulled apart vertically. Designers get a single image that explains why four different foundations — Elevation, Surfaces, Materials, Typography — coexist: each one owns a different layer in the stack. The diagram showcases the glass material — translucent fill plate over a brand-gradient viewport, with the backdrop blur softening the gradient and shadow beneath. Numbered callouts (01–04) sit on the iso plane and reference the four foundation cards below.

Catalog

Paper data-material="paper"

Opaque fill, soft drop, 1px hairline. The default for stat-cards, feature-cards, action-cards, action containers.

Card-shape and tile-shape rendered in paper. Quiet drop shadow, hairline border, neutral fill — the visual default for content surfaces. Light and dark themes flip via the upstream --surface-card and --elev-1 tokens.

24h volume
$1.24B

Cross-chain settlement across 30+ networks

Routes
30+
chains

Glass data-material="glass"

Translucent fill + backdrop-blur + neutral drop. Aliases the canonical Panel Surfaces 3-token recipe — same surface character.

Glass is FAB sub-panels, side rails, dropdowns — anything that floats over content and frosts the page behind. Composes --surface-panel-glass + --shadow-panel-glass + --backdrop-panel-glass, the canonical Panel Surfaces recipe. Visual diff vs. the pre-Materials implementation: zero.

Network
Polygon

Connected · block 52,830,491

Gas
28
gwei

Gradient data-material="gradient"

Brand gradient fill + minimal chrome + white text. Hero KPIs, marketing accent surfaces, cover tiles where the gradient is the subject.

Gradient is the loudest material — the LI.FI brand gradient at 135° from --lifi-sapphire to --lifi-ink. Use for ONE hero KPI, ONE cover tile, ONE call-to-action surface. Text flips to white automatically (the brand gradient is too saturated for primary-text contrast).

Cross-chain TVL
$8.42B

Total value secured · 30+ chains

24h
+12.4%
growth

Halo data-material="halo"

Soft accent wash + radial glow at top-right. Promoted from .brand-card — brand-identity tiles, premium feature cards, “about this product” showcases.

Halo reads as a quietly brand-forward card. The base is paper-tier (3 % accent over --surface-card), and a radial gradient anchored at the top-right adds a 12 % accent halo that fades by 70 %. Distinct from tinted (uniform wash, accent-louder) and gradient (full brand fill, hero-status). Shown with three accents to demonstrate the parametric tint.

Default tint
LI.FI

--lifi-ink — the system default

Cross-chain
Stargate

Custom tint · --lifi-sapphire

Settlement
12s · final

Custom tint · --lifi-pink

Branded tile composition data-material="halo" + --tile-accent-* + .is-active

The full visual recipe behind .brand-card — halo material, per-tile dual-mode accent, and active-state glow — available on any tile.

Three example tiles — partner showcase, integration directory, ecosystem spotlight — all wearing the same recipe with their own accent. The middle one carries .is-active to show the sticky-selected glow; in production, a click handler toggles that class.

Partner

Acme Wallet

Cross-chain swap embedded directly in the wallet's send sheet. 400k MAU.

Integration

Solana via Wormhole

Now live — native USDC, JUP, and BONK route through the LI.FI router.

Ecosystem

Ondo Finance

RWA settlement layer — tokenised treasuries on six chains, one quote.

Foundations
Spacing
Two layers of the same dimensional system, on the 4n grid. Tokens below are the raw --space-* scale every padding / gap / radius pulls from. Sizing ladders sits on top — the sm / default / lg / xl tier rule that every multi-size component graduates through, derived entirely from the token grid. Read tokens first, ladders second.

Spacing system

4px grid foundation used everywhere. Tokens --space-1 through --space-128 map to multiples of 4px.

Geometry on grid. Every component dimension — width, height, padding, margin, gap, border-radius — must resolve to a token below. The 4px grid is the law: if a value isn't a multiple of 4 (excluding the 1px / 2px hairline exceptions), it's a bug to fix at the source, not a one-off to tolerate. Components scale predictably across themes, sizes, and viewports only when they share this baseline.

--space-22px
--space-44px
--space-88px
--space-1212px
--space-1616px
--space-2020px
--space-2424px
--space-2828px
--space-3232px
--space-3636px
--space-4040px
--space-4444px
--space-4848px
--space-5252px
--space-5656px
--space-6464px
--space-7272px
--space-8080px
--space-9696px
--space-120120px
--space-160160px

Surface widths --w-*

Seventeen max-widths for floating containers — popovers, menus, modals, panels. Ordinal +32px ladder; --w-N+1 is the next tier.

Seventeen tokens, ordinal naming, uniform +32px step. --w-N+1 is always the next tier up — no skips, no exceptions. Names are deliberately abstract: --w-7 doesn't bake-in "panel" or "rail", so the same tier can host a widget canvas today and a wallet drawer tomorrow without renaming anything. Reserved tiers are claimable for new surfaces; reach for the nearest tier and never write a literal width.

--w-1224px
--w-2256px
--w-3288px
--w-4320px
--w-5352px
--w-6384px
--w-7416px
--w-8448px
--w-9480px
--w-10512px
--w-11544px
--w-12576px
--w-13608px
--w-14640px
--w-15672px
--w-16704px
--w-17736px

Sizing ladders sm · default · lg · xl

Five lockstep ladders (height, label, padX, padY, radius) define each tier — every value a token. Canonical reference: #btn-sizes.

Each tier locks together a height, a label size, a horizontal padding, a vertical padding, and a corner radius. Buttons are the canonical reference today; as more components join the ladder (segs, inputs, switches, cards), they'll line up in matching rows.

sm · 32px · dense rails, data tables, toolbar chrome
default · 40px · forms, primary CTAs, comfortable rows
lg · 48px · heroes, marketing CTAs, top-of-page rows
xl · 56px · banner / poster CTAs, statement compositions

Card gap ladder --gap-card-*

Five-tier ladder (xs / sm / md / lg / xl) for the gap between card-shaped siblings. Distinct from --cluster-* (inline gaps) and --stack-* (content rhythm). The ladder mapping is swappable — same model as the Theme Composer. May 2026.

One family, five tiers, swappable mapping. The 5 tier tokens (--gap-card-xs through --gap-card-xl) describe POSITION on the ladder — not the use case. Use-case-to-tier assignment is documentation; the tokens themselves are a clean numeric ladder. This is what makes the mapping swappable: a future "card gap composer" can install a Compact or Spacious preset by overriding the 5 tokens at :root, and every consumer flips automatically via cascade — same mechanism the Theme Composer uses to swap brand colours.

Convenience alias. --gap-card (no modifier) resolves to --gap-card-md. Use the explicit -md name in component CSS for clarity; the bare alias is for inline overrides where brevity helps (style="--card-gap: var(--gap-card);").

--gap-card-xs · 4 px · ultra-tight (reserved — no current consumer)

--gap-card-sm · 8 px · compact list (rail cards, dense menus)

--gap-card-md · 12 px · default · quote cards, vertical card stacks

--gap-card-lg · 16 px · comfortable grid (multi-col, breathing room)

--gap-card-xl · 24 px · spacious grid (hero-tier, marketing)


Nested rhythm — wrap a sub-group to tighten without touching the outer container. When a container's gap is correct for separating top-level zones (header → group → footer) but a subset of children wants to read as one coherent set, don't change the container's gap. Drop a stack wrapper around the subset that publishes its own tighter --card-gap. The outer rhythm survives; the inner group feels denser. Canonical example: the swap form's state-content keeps 16 px (header → stack → action footer) while the inner .ui-form-stack runs at 8 px between cards.

Outer 16 px (lg) · inner stack 8 px (sm) · 3 zones

Canvas grid spacing --grid-gap-x / --grid-gap-y

Two-axis canvas spacing (Portal, Playground), edited per-theme from the Composer's Spacing section — a sibling of Corners. June 2026.

Two axes, one job each. A content canvas uses two different spacing values for two different jobs — a tight gutter between side-by-side cards (--grid-gap-x, default 16) and roomier breathing between stacked sections (--grid-gap-y, default 24). A single symmetric gap would flatten that distinction, so the system keeps them independent. Both are mode-independent (no light/dark flip).

Composer-driven. Edit per-theme from the Theme Composer's Spacing section (Compact / Standard / Spacious trio + a Custom card with Horizontal + Vertical sliders), painted to the active canvas. Enabled in the Portal + Playground rail composers; the FAB sitewide composer stays palette + corners. Distinct from the card-gap ladder, which is the universal card-LIST gap family.

--grid-gap-x · 16 px · horizontal gutter between side-by-side cards

--grid-gap-y · 24 px · vertical rhythm between stacked sections


Preset trios. Each snaps both axes at once. The active trio derives from the current gaps (no separate storage); a value off the trio grid highlights the Custom card.

Compact · x 12 · y 16

Standard · x 16 · y 24 · default

Spacious · x 24 · y 32

Nested radius outer = inner + pad

Concentric-corner rule for nested rounded elements — the outer radius equals the inner radius plus the padding between them.

Concentric corners. When a rounded element nests inside a rounded, padded parent, the two corner curves stay parallel — a constant gap all the way around the bend — only when outer radius = inner radius + padding. Solved for the child, that's inner radius = outer radius − padding: the default radius for any new nested element. Match the radii without accounting for the padding and the curves pinch at the corner — the most common rounded-corner mistake.

Don't — matched radii

outer = inner ignores the padding, so the corner gap pinches around the bend.

32px 12px 32px

Do — radius + padding

outer = inner + padding keeps a constant gap all the way around the bend.

32px 12px 20px

In real components · inner = outer − padding

card · radius 32

Inner 32 px, matched to the frame — corner gap pinches.

card · radius 20

Inner 20 px = 32 − 12 — curves stay parallel.

Foundations
Surfaces
Surfaces own only color. The four --surface-* fill tokens, the light/dark theme system that flips them, and the audience-led naming for cards versus tiles. For shadow / lift / state mechanics see Elevation; for full surface character (paper, glass, gradient, halo — fill + border + shadow + backdrop + highlight, bundled) see Materials.

Where this layer sits. Surfaces are the colors Materials reach for. A material recipe like paper.bg = var(--surface-card) doesn't duplicate the color — it composes it. Three-layer stack: surfaces (colors) → materials (compositions, named) → components (consume materials via --mat-*). Each layer owns one concern, no overlap.

Surface ladder --surface-*

The four --surface-* fill tiers, shown side-by-side for dark + light. Flips automatically via [data-theme] on <html>. This card is the canonical reference for the ladder — share #theming when teammates ask "which surface token at which tier?"

The ladder, both themes side-by-side. Four tiers stack from --surface-sunk (deepest recess) to --surface-card (highest lift). Same token names in both themes; values flip automatically. Each swatch is rendered with its own theme's value — the swatches don't follow the page's current theme, so you can scan both ladders at once even when the rest of the page is in just one mode.

Dark mode ladder · 5 → 8 → 16 → 24 % lightness (rebalanced May 2026 v2)

--surface-sunk oklch(5% 0.012 268) · recessed
--surface-page oklch(8% 0.015 268) · canvas
--surface-raised oklch(16% 0.016 268) · .panel shell
--surface-card oklch(24% 0.018 268) · card / tile

Light mode ladder · 91 → 100 → 97 → 100 % lightness (card pivots to page)

--surface-sunk oklch(91% 0 268) · recessed
--surface-page oklch(100% 0 268) · canvas
--surface-raised oklch(97% 0 268) · .panel shell
--surface-card pivots → --surface-page · lifts via shadow

Tier mapping · which token for which job

  • --surface-sunk — recessed wells, demo containers, "well" treatments. The only tier that goes down from the page.
  • --surface-page — viewport / canvas bg. <body> background; what every other surface sits against.
  • --surface-raised.panel shells, the playground rail, the swap widget shell, footer bands, raised page-level regions. One step lighter than the page.
  • --surface-card — cards, tiles, paper-material consumers, .ui-amount-card. In dark = 24% (highest tier); in light = pivots to --surface-page (100% white) and lifts via shadow alone — "Material Design approach" to light mode where you can't go above pure white.
  • --glass-base — translucent fill base for the Glass material (dropdowns, command palette, FAB sub-panels). Not part of the solid ladder; see Materials → Glass.

Glass--glass-base is the translucent fill base for floating panels. The full glass recipe (fill + shadow + backdrop-filter) is the Glass material; see Materials → Glass.

Foundations
Typography
Two font families, a distilled set of sizes, and strict weight/spacing rules that keep every page visually cohesive. All text inherits from var(--font-sans) unless explicitly set to var(--font-mono).

Font families --font-sans · --font-mono

Two fonts, two roles. Geist carries content + UI; Geist Mono grounds anything technical — code, addresses, numerics, eyebrows.

Aa

--font-sans

Geist · 7 weights

Aa

--font-mono

Geist Mono · 4 weights

Geist weights

Ag
Light · 300
Rare; deck whisper text
Ag
Regular · 400
Body, prose, default text
Ag
Medium · 500
Form labels, hints
Ag
Semibold · 600
Button labels, card titles
Ag
Bold · 700 ★
h1/h2/h3, hero, display
Ag
Extra-bold · 800
Deck tier (poster→colossal)
Ag
Black · 900
Reserved; brand extreme

Geist Mono weights

Ag
Regular · 400
Code, OKLCH values, addresses
Ag
Medium · 500 ★
Token names, eyebrows
Ag
Semibold · 600
Tab nav, panel titles
Ag
Bold · 700
Mono heading anchor (rare)

★ Default weight for the family. Geist 700 anchors every heading in the system; Geist Mono 500 is the default for token labels and eyebrow markers. Reach for those first; pick a different weight only when the content asks for it (a 600 button, a 400 paragraph, a 600 tab strip).

Jumper typography --font-jumper

Jumper swaps the sans family to Urbanist. Type scale, weight ladder, tracking, and Geist Mono stay shared with LI.FI.

Aa

--font-jumper

Urbanist · 7 weights

Aa

--font-sans · LI.FI reference

Geist

Same scale, two voices

Move value across chains. Urbanist 700 · --text-h2
Move value across chains. Geist 700 · --text-h2

Urbanist weights

Ag
Light · 300
Lockup sub-product labels
Ag
Regular · 400
Body, prose, default text
Ag
Medium · 500
Form labels, hints
Ag
Semibold · 600
Button labels, card titles
Ag
Bold · 700 ★
h1/h2/h3, hero, display
Ag
Extra-bold · 800
Deck tier (poster→colossal)
Ag
Black · 900
Reserved; brand extreme

One family swap, everything else shared. Urbanist mirrors Geist's role table 1:1 — same default weights per role (700 headings, 400 body, 500/600 UI), same --text-* / --lh-* / --tracking-* ladders, same Geist Mono for everything technical. Until the brands formally split, Jumper-brand surfaces differ from LI.FI by exactly three levers: theme (the jumper-1 / jumper-2 presets), the logo tokens (--jumper-indigo / --jumper-purple), and this sans family.

Font pairings

Five canonical compositions of sans + mono — section headers, KPI stats, inline references, form values, and tab nav.

Section header

// 03 — Foundations

Color tokens describe intent

Pages reference var(--accent-primary) and var(--surface-raised), never literal OKLCH.

Mono eyebrow grounds the section as an editorial unit. Sans heading carries the title; mono inline code surfaces token references inside prose.

KPI stat

Volume routed · Q1 2026
$1.24B

Mono numerics align column-to-column when stacked. Mono uppercase label sits as the metric's name; sans delta chip carries the directional cue.

Inline references

Quotes route through the 0xb1739…ee01 aggregator on Arbitrum, return cached responses for ~80ms via the quote-cache service, and emit a QuoteReady event with amountOut and gasEstimate.

Mono code differentiates references from prose without parenthetical asides. The reader scans mono runs as "things that exist in the code," sans as "what they do."

Detail list

Recipient
0x742d35…f8e3
Amount
1,250.00 USDC
Network
Arbitrum
Tx hash
0xb1739…ee01

Sans terms read as questions; mono values read as data. Long hex strings stay legible at fixed-width because every character occupies the same column; numeric amounts use tabular-nums so columns align across rows.

Tab nav + content

Bridge volume across 28 chains

Routes are scored by execution time, slippage, and fee. The aggregator returns the lowest-cost path for every quote.

Sans tabs above sans content, with the active tab marked by an accent underline. The catalog's own viewport tabs (the Preview / Markup / Specs strip on every card) use the alternate mono uppercase recipe — same underline mechanic, different type voice for "architecture marker" vs "section nav."

Typography

Geist (sans) for everything; Geist Mono for code/numbers/eyebrows. Modular type scale shared across Product, Marketing, and Docs.

One ladder, biggest first. Deck scale (256–112px) is for slide covers, single-word reveals, and canvas-fill statements; web & product (80–12px) is everything else. Deck-tier samples use static --lh-* tokens (matching pixel line-heights tuned at 0.94–0.96); web-tier display sizes use unitless literals so they don't overlap when fonts clamp.

--text-colossal · 256px / 800 · −5% · 0.94 lh
LI.FI
--text-keynote · 192px / 800 · −5% · 0.94 lh
Connect.
--text-statement · 144px / 800 · −4% · 0.94 lh
Bridges.
--text-poster · 112px / 800 · −4% · 0.96 lh
Liquidity.
--text-hero · 80px / 700
Hero numbers
--text-display · 56px / 700
Display headlines
--text-h1 · 48px / 700
H1 · Section title
--text-h2-lg · 36px / 700 · value-display tier
Value display · $2,113.50
--text-h2 · 32px / 700
H2 · Subsection
--text-h3 · 24px / 700
H3 · Card title
--text-body-xl · 20px
Body XL · oversized lede, hero intros
--text-body-lg · 18px
Body LG · intro paragraphs, xl button labels
--text-body · 16px
Body · standard reading copy
--text-sm · 14px
Small · captions, helpers, table cells
--text-caption · 12px
Caption · labels, hints, eyebrows
--text-micro · 10px
MICRO · 0 8 12 16 20 24 · TICKS, BADGES, SUPERSCRIPTS
Components
Material Composer
Live editor for the Materials layer. Tune opacity / blur / tint / shadow / highlight per material, see the change applied across a preview tray AND every consumer on the page (FAB panel, dropdowns, playground rail). Save named variants, export JSON. Changes apply in-session only — never auto-restored on reload (per the LI.FI 1.0 default rule). Architecture: sliders mutate --material-<name>-* tokens directly on :root; the cascade flows through [data-material] selectors so every consumer updates without per-component wiring.

Material Composer .material-composer

Inline tuner for material values — pick a material, drag sliders, watch every consumer repaint. Modal for the full workspace.

Pick a material in the right column, drag sliders, watch every preview surface (and the FAB panel, and dropdowns, and the playground rail) update live. The inline workspace below shows four preview surfaces wearing the active material; the modal expands to a larger tray + saved variants + JSON export.

Material Composer

Card · paper Cross-chain swaps Tune opacity / shadow / highlight to retune every card on the page.
Tile · paper Stat tile Reads the same --mat-* tokens; repaints automatically.
Small · paper Setting row
Panel · paper FAB sub-panel Try the glass material to see the blur slider come alive.
Editing material
Components
Semantic states
The four semantic state tokens (--success / --danger / --warn / --info) are formula-driven in styles.css via OKLCH relative-color syntax — each derives from --brand-anchor with a per-role L offset, C multiplier, and role-locked hue. Tuning lives in the Theme Composer’s Semantic states section (the standalone Semantic Composer merged in, June 2026): every theme carries its own per-mode coefficients, so a brand palette that would wash a warning out to grey can pull it back into its legible band — and the fix travels with the theme.

Semantic states --success

Formula-derived state tokens — per-role L offset / C multiplier / locked hue over --brand-anchor, tunable per theme in the Theme Composer.

Each role’s anchor token is a live function of --brand-anchor: oklch(from var(--brand-anchor) calc(l + L_offset) calc(max(c, 0.12) * C_mult) H) — the 0.12 chroma-input floor keeps a muted or monochrome anchor from collapsing the states to grey. Everything below reads the LIVE tokens — pick or edit a theme in the Theme Composer (the card in the next section, or the floating composer) and every swatch, alert, chip, badge, and button repaints through the cascade. The per-role sliders live in the editor’s Semantic states section.

Success · --success

Route confirmed

Stargate via Polygon → Arbitrum settled in 12s with 0.04 % slippage.

Live +12.4 %

Danger · --danger

Transaction reverted

Insufficient gas on destination chain. No funds were moved.

Failed −4.1 %

Warn · --warn

High slippage detected

This route shows 1.8 % price impact. Consider reducing trade size.

Slow Beta 3 left

Info · --info

New route available

Stargate just added a USDC bridge between Base and Arbitrum.

Note v2 New
Composers
Theme Composer
The self-contained theming mini-app: a user picks or edits a theme and every surface re-skins live. It began as a brand-palette editor (OKLCH accent generation) and grew six more axes — corners (card / panel / button radius), spacing (canvas grid gaps), surface contrast (the canvas-to-panel tonal step), panel elevation (elevated vs flat), semantic states (per-role success / danger / warn / info coefficients), and charts (fixed spectral vs a brand-derived series ramp) — the last two landed in the June 2026 Semantic Composer merge — plus theme management (export · duplicate · rename · reset · delete). Users pick between saved themes, create new ones, or drill into a dedicated edit view to tune OKLCH seeds for Primary, Secondary, Tertiary, and Background separately for Light and Dark mode. It mounts on three host surfaces — FAB sub-panel · playground rail · Portal Settings — each painting a different scope. Changes apply in-session, never auto-restored on reload (per the LI.FI 1.0 default rule). Built from documented primitives (.screen-header, .theme-card, .option-card, .seg) plus the shared window.ThemeComposer editor.

Theme Composer

Theming mini-app — saved-theme list + a drill-in editor tuning every theme axis, from palette and corners to charts and brand font.

Both zones below are the live Theme Composer, hydrated through the shipped code (ds-theme-composer.js) so the documentation can't drift from the component. Every edit is scope-contained to this card — drag a slider and the demo re-derives its own tokens without re-skinning the catalog, and nothing persists. Click a theme in the list to load its seeds into the editor.

List view · theme management


Edit view · meta + the five axes

Every axis renders here for documentation; real mounts gate a subset via features — see the mount matrix in Anatomy.