Outfit
Display + UI
Aa Bb Cc 0 1 2 3
- 400Regular — the quiet default
- 500Medium — for accents and gradients
- 600Semibold — eyebrows, card titles
- 700Bold — section headlines
- 800Extrabold — hero displays
Design system
Typography, colour, spacing, and the primitive tokens that govern the visual language of every page.
Two families anchor the brand: Outfit for headings and accented UI, Noto Sans for body and long-form prose. A 12-step modular scale keeps every page in the same rhythm. All values are exposed as CSS custom properties in variables.css and consumed via tokens, never raw values.
Both are variable fonts loaded once at the top of the document, with metric-adjusted fallbacks (Outfit Fallback, Noto Sans Fallback) to avoid layout shift.
Display + UI
Aa Bb Cc 0 1 2 3
Body + prose
Aa Bb Cc 0 1 2 3
Twelve steps from --font-size-xs at 0.75 rem to --font-size-8xl at 5.5 rem. Heading recipes pick from this scale, sometimes wrapped in clamp() for fluid behaviour at hero scale.
Display, section, subsection, and footer roles, ordered from biggest to smallest. Most live in Outfit; the footer heading is the only one in Noto Sans because it labels a column rather than introducing a section. Highlight sits in this group too — a gradient text fill applied to a span or em inside a heading.
Outfit / 800 / 5xl – 8xl / 1.05 – 1.1 / -0.03em to -0.04em
Contextual AI for the open web
Page-level hero titles. Used by .hero__title, .about-hero__headline, .contact-hero__title, .api-demo-hero__title, .solution-hero__headline.
var(--gradient-accent) / static
Made for the open web
The shared static accent applied via the --gradient-accent token. Used on every page-level hero/CTA accent that doesn't shimmer: .hero__title-accent, .final-cta__title-accent, .contact-hero__accent, .api-demo-hero__accent.
var(--gradient-accent-shimmer) + 4s shimmer loop
Audiences that match the moment
A horizontal shimmer that loops every four seconds, drawing the eye across the headline. Reserved for product-page heroes. Pair the --gradient-accent-shimmer token with background-size: 200% 100% and animation: shimmer 4s ease-in-out infinite. Used by .solution-hero__headline em across all solution pages and .about-hero__headline em. Respects prefers-reduced-motion.
Outfit / 700 / 4xl – 5xl / 1.2
Trusted by leading publishers
Top-of-section titles (h2). Default heading style across landing, solution, and blog sections.
Noto Sans / 400 / 2xl – 3xl / 0.1em / uppercase / muted
Trusted by industry leaders
A quiet, wide-tracked, all-caps title that introduces a band of supporting content without competing with the surrounding section headlines. Used by .partners__title above the partner logo carousel.
Outfit / 600 – 700 / xl – 2xl / 1.3
Monetisation platform
Card titles, feature headers, form headings. Examples: .cta-banner__headline, .api-demo__section-title, .contact-team__heading.
linear-gradient(135deg, var(--color-green) → var(--color-green-dark))
Made for the open web
A green-only diagonal accent unique to the Lumi block on the landing page. Used by .lumi__title-accent. Not yet promoted to a token — the only consumer is Lumi.
Noto Sans / 600 / sm / 0.08em / uppercase
Column headings inside the site footer. The smallest member of the heading family and the only one in Noto Sans — it labels a column of links rather than introducing section content. Used by .site-footer__heading.
Four roles of paragraph text: large for hero subtitles and intros, base for default paragraphs, a dedicated article body for long-form blog content, and meta for dates and captions. All Noto Sans, regular weight. Both size and line-height vary deliberately by context so each block reads at the right pace.
Noto Sans / 400 / lg (xl on landing ≥48rem) / 1.6 – 1.75
Neuwo classifies open-web content in milliseconds, surfacing audiences that match the moment a reader is in.
Hero subtitles and intro paragraphs. Default size is lg (1.125 rem). Two responsive overrides apply: the landing .hero__subtitle bumps to xl (1.25 rem) at ≥48 rem, while .solution-hero__sub and .api-demo-hero__subtitle drop to base (1 rem) below 48 rem. Line-height also loosens with context: 1.6 on .hero__subtitle, 1.65 on the solution / API-demo subs, 1.7 on .contact-hero__subtitle and .team-block__desc, up to 1.75 on the about-page .story__prose p.
Noto Sans / 400 / base / 1.6 – 1.7
The default paragraph style. Comfortable line-height for short to medium blocks of running text, with strong emphasis rendered at semibold weight against the heading colour.
The base body rule and blog index excerpts (.post-list p) sit at 1.6. Mid-length component prose loosens to 1.65 on .api-demo-info__intro or 1.7 on .lumi__text and .founder__bio p. Long-form blog post content has its own role (see below).
Noto Sans / 400 / base / 1.8
Long-form prose loosens to a generous 1.8 line-height so paragraphs stay readable as the reader scrolls. The same leading applies to bulleted and numbered lists inside an article so the rhythm doesn't break across formatting boundaries.
Blog post content paragraphs and lists. Used by .blog-post__content p, .blog-post__content ul, and .blog-post__content ol. Distinct from regular Body because the line-height is materially looser — tuned for sustained reading at scroll, not for short paragraphs inside a marketing section.
Noto Sans / 400 / sm / 1.6 / muted
Dates, captions, and secondary metadata. Inherits the body line-height of 1.6 (or sets it explicitly, as on .timeline__desc). Used by .post-list time, .blog-post__date, .timeline__desc, .team-card__role.
Two compact label roles — the kicker that sits beside headings (Outfit, uppercase) and the form label beside inputs (Noto Sans, sentence case).
.eyebrow · Outfit / 600 / xs / 0.08em / uppercase
.section-kicker
Solutions
blue · .solutions__eyebrow
Meet Lumi
green · .lumi__eyebrow
A small uppercase label that sits above a headline or at the top of a section card. Add the .eyebrow utility class to opt in, or use one of the existing component classes (.section-kicker, .story__kicker, .solution-hero__kicker, .solutions__eyebrow, .lumi__eyebrow, .use-cases__does-kicker). Only the colour varies per context — muted by default, blue or green where the section calls for emphasis. The recipe lives in src/css/global/eyebrow.css. Note: tags, badges, footer headings, and similar small-uppercase elements share the same visual recipe via the same global rule, but they're distinct roles and will be documented separately.
Noto Sans / 500 / sm
Work email
Field labels in contact and demo forms. Used by .contact-form__label, .api-demo__field-label.
Two brand hues — blue and green — sit on a deep navy ground. Everything else is a neutral ramp, a small set of semantic surfaces, and translucent glass tokens that keep panels feeling lit from behind. The site is dark-mode only, so the grey scale climbs lighter as the number rises. All values are authored in OKLCH for predictable lightness across hues; consume them through tokens, never as raw values.
Blue carries primary action and trust; green signals momentum and the Lumi product line. Each has lighter and darker companions for hover, depth, and emphasis.
oklch(66.623% 0.1177 217.10)
#0aa5c3
oklch(77.31% 0.13351 211.702)
#0bcbe6
oklch(58.216% 0.1005 212.646)
oklch(77.183% 0.1766 131.692)
#8acb46
oklch(64.020% 0.1502 131.396)
Eleven steps from --color-grey-50 (almost-black panels) up to --color-grey-900 and --color-white (off-white text). The numbers reflect lightness, so in the dark theme high numbers are bright and low numbers are deep — the opposite of a Tailwind-style ramp.
oklch(20.768% 0.0398 265.755)
Deepest panel surface. Backs floating cards and the glass tokens.
oklch(23.157% 0.0398 262.510)
Inline code chips, recipe pills, subtle inset surfaces.
oklch(27.950% 0.0368 260.031)
Mixed into the accent gradient stops to soften pure brand hues. Borders on dense panels.
oklch(37.170% 0.0392 257.287)
Mid-dark separators and the resting border on most cards.
oklch(71.067% 0.0351 256.788)
The same value powering --color-text-muted; secondary copy and disabled states.
oklch(55.439% 0.0407 257.417)
Anomaly in the ramp — darker than 400. Reserved for low-emphasis decorative shapes.
oklch(86.898% 0.0198 252.894)
Default body text colour (--color-text aliases this).
oklch(92.876% 0.0126 255.508)
Bright neutral for emphasis paragraphs and table values.
oklch(96.826% 0.0069 247.896)
Same lightness as --color-white; used where heading-level text appears in body context.
oklch(98.415% 0.0034 247.858)
The brightest neutral. Reserved for hero metrics and high-contrast accents.
oklch(96.826% 0.0069 247.896)
Heading colour and footer column titles. Slightly off-true-white to avoid clinical contrast.
Three semantic surfaces describe vertical depth: the page itself, raised solid panels, and the translucent header that floats over content as you scroll.
oklch(16.140% 0.0289 266.826)
The deep navy ground for every page. Sits behind the hero signal canvas and the floating colour blobs.
oklch(18.020% 0.0325 266.625)
Opaque alternative to the glass surfaces. Used for inline form panels, the API demo body, and any block where translucency would clash with content underneath.
oklch(16.140% 0.0289 266.826 / 0.95)
Site header background once a scroll threshold has passed. Same hue as the body, ninety-five-percent opaque so a faint hint of content shows through.
Three named text colours cover the typographic hierarchy. Each is a semantic alias of a neutral step, so the ramp and the text tokens always read in lockstep.
oklch(96.826% 0.0069 247.896)
Headings and high-contrast UI labels. Aliases --color-grey-800.
oklch(86.898% 0.0198 252.894)
Default body copy. Aliases --color-grey-600.
oklch(71.067% 0.0351 256.788)
Secondary copy: section intros, captions, dates, eyebrows in their muted variant. Aliases --color-grey-400.
Translucent panel tokens. Backgrounds are alpha-tinted versions of --color-grey-50; borders are alpha-tinted --color-grey-400. Always pair with backdrop-filter: blur(var(--glass-blur)) so the colour behind picks up texture. The chips below sit on a striped backdrop so the transparency reads.
oklch(20.768% 0.0398 265.755 / 0.6)
Standard glass panel: glassmorphism cards, the active sidebar group on this very page.
oklch(20.768% 0.0398 265.755 / 0.4)
Lighter glass for hover lifts and dense card grids where 60% would feel heavy.
oklch(71.067% 0.0351 256.788 / 0.12)
Resting border on every glass surface and on dashed dividers throughout the design system.
oklch(71.067% 0.0351 256.788 / 0.22)
Hover and focus state for the same surfaces. Roughly twice the alpha — visible without going harsh.
Plus --glass-blur at 1rem — the partner value for every glass background. See Animations › Transitions for the duration tokens that animate the hover state on these surfaces.
Two named gradients carry the brand. The static accent is the default headline highlight; the shimmer variant loops every four seconds across product-page heroes.
135° blue → green, each mixed 90% with grey-200
The default heading highlight. The 10% grey mix tames the pure brand hues so the gradient doesn't feel neon against deep navy.
90° blue → green → blue (200% sized)
Pair with background-size: 200% 100% and a four-second shimmer animation. Respects prefers-reduced-motion.
See Typography › Headings for both gradients applied to the Highlight roles.
A small set of single-purpose colour tokens that don't fit the brand or neutral ramps but earn their keep across the site.
oklch(71.067% 0.0351 256.788 / 0.08)
Background graph paper on technical sections. Paired with --color-grid-line-light at 6% for secondary lines.
oklch(100% 0 none / 0.25)
The diagonal sweep across loading skeletons and the partner-logo carousel hover state.
oklch(26.48% 0.01276 243.42)
The single panel background under each partner logo on the landing page. Sits between body and surface in lightness.
oklch(20.768% 0.0398 265.755 / 0.6)
Same value as --glass-bg, kept as a separate token because the benefits cards predate the glass system. Candidate for consolidation.
The tokens from Colour combine into five composite surfaces that cover every panel on the site. Each recipe is the layered effect a viewer perceives — the literal background plus any interior decorators (radial blobs, masked grids) and the body atmosphere showing through translucent layers. Members of a recipe differ only in details — blob position, hover behaviour, animation entry — so the underlying surface stays consistent. Animated overlays (scan-lines, rotating borders) are surface-agnostic and live in their own section.
--color-body-bg + fixed blob field
.background__gradient {
background:
radial-gradient(ellipse 50% 40% at 20% 20%,
rgba(10, 165, 195, var(--bg-blue-1)) 0%,
transparent 100%),
radial-gradient(ellipse 40% 50% at 75% 15%,
rgba(138, 203, 70, var(--bg-green-1)) 0%,
transparent 100%),
radial-gradient(ellipse 60% 35% at 50% 60%,
rgba(10, 165, 195, var(--bg-blue-2)) 0%,
transparent 100%),
radial-gradient(ellipse 45% 45% at 80% 70%,
rgba(138, 203, 70, var(--bg-green-2)) 0%,
transparent 100%);
}
The dark navy ground every page sits on. A fixed .background layer paints four soft radial blobs — blue at top-left and centre, green at top-right and bottom-right — at 5–10% opacity behind all content. Every translucent surface below composes against this. Source: src/css/global/background.css.
The specimen on the left is a recreation, not the live element. In production each radial gradient is sized as a percentage of the viewport, so the ellipses span hundreds of pixels and fade gradually enough to feel atmospheric. At swatch scale the same gradients transition over far less distance, which makes the blobs read more saturated and crisper than the live ground. Opacities are also bumped (0.15 / 0.11 / 0.10 / 0.08 here vs 0.10 / 0.07 / 0.06 / 0.05 in production) so the blobs stay visible in the smaller frame.
body.background--glass-bg + blur(--glass-blur) + --glass-border
60% alpha grey-blue with a 1 rem backdrop blur. Body atmosphere reads through. Variants add a fade-in entry, hover lift, a top accent bar, or a faint icon watermark — the surface itself is identical.
.use-cases__panel--active.contact-form-wrap.team-card.card-grid__card.solutions__card.comparison-table-wrap--glass-bg-light + blur(12px) + grid + edge mask
40% alpha — more of the body atmosphere shows through than standard glass. The signature trait is a square grid painted in --color-grid-line-light on each cell’s ::before, sized at clamp(2rem, 2.5vw, 3rem), and clipped by an intersected double mask-image so the grid only reads in the central 50 %×50 % of every cell and fades to transparent at every edge. Used to communicate measurement / data density without competing with the numbers laid over it.
.stats-paneldark surface + ::before two-blob radial overlay
A built-in warm glow: ::before paints two corner radials — one green, one blue — at 10–18% opacity. Members differ in blob position, opacity, and base surface. Most sit on standard glass (recipe B); .ca-perf sits on opaque --color-surface-solid (recipe E) and adds a 4 rem 12 % blue halo via box-shadow. .ca-process__card additionally tints its border green and adds an outer green halo.
.signal-split__card.story__timeline.ca-process__card.ca-perf--color-surface-solid
An opaque alternative to the glass surfaces — no translucency, no body atmosphere reads through. Used where the surface needs to assert itself over the page (CTA bands) or where an animated overlay sits on top and translucency would muddy it. .cta-banner is the bare consumer; .ca-perf uses the same base but adds the recipe-D blob field and an outer blue halo.
.cta-bannerA 0.25 rem-based scale of twelve steps drives every gap, padding, and margin on the site. Skips at the top of the ramp (no --space-7, 9, 11, 13…) keep the choices small enough to be memorised — if a value isn't here, it's wrong.
The first six steps move in 0.25 rem increments for fine UI gaps; from --space-8 upward the gaps double in size to suit section padding and large layout rhythm. --space-2, --space-3, and --space-4 account for ~60 % of all uses across the production CSS.
The .section utility wraps every major band of content. Vertical padding scales by viewport so sections breathe at desktop without dwarfing mobile content.
--space-16
4 rem · 64 px top & bottom
--space-20
5 rem · 80 px top & bottom
--space-24
6 rem · 96 px top & bottom
Source: src/css/global/layout.css. Anything that visually behaves as a section — the body of a landing band, a solution-page band, the contact form — should reach for .section rather than re-deriving these values.
The .container utility caps the readable width and provides horizontal gutters that scale with the viewport. Maximum width is fixed at 80 rem; gutters track the section rhythm one step behind.
--space-4
1 rem · 16 px gutter
--space-6
1.5 rem · 24 px gutter
--space-8
2 rem · 32 px gutter
80 rem
1280 px content cap
A handful of consumers cap their inner column tighter than the global container — .blog-post__content and .articles__intro at 48 rem for prose, .about-team__intro at 44 rem — for reading comfort. Those are local overrides on top of the global container, not separate breakpoints.
Six radius tokens span from tight UI chips through pillowy surface cards. The smaller end of the scale is decisive about UI affordances — pills, code chips, copy buttons — while the larger end carries the soft, premium feel of the brand on cards and bands. Pick by role, not by size.
All six tokens shown at the same square size so the corner curvature reads at a glance. --radius-full is a sentinel value (9999 px) that produces a circle on a square or a pill on a wider element.
Each token has a clear role in the system. The mid-scale tokens (lg, xl, 2xl) carry most of the surface chrome on the site; the rest are precise UI primitives.
.ds-code), small inset panels, the design-system TOC sublink. A neutral mid-step that rarely appears on production cards.
.btn) and the default card-band radius — .cta-banner, .solutions__card, .surface-card samples in this very design system. The most-used corner on the site.
.contact-form__input), and the design-system specimen chrome itself (.ds-family, .ds-role, .ds-swatch). Soft enough to feel friendly without losing rectangularity.
.team-card, .contact-form-wrap, .final-cta__card, the about-page leadership portrait, the bid-enrichment / auto-tagging feature panels. Pillowy and brand-forward.
Four neutral elevations and one branded glow, all built on pure black at varying opacity so they feel grounded against the dark navy ground rather than smudgy. Resting cards lift on hover with a shadow swap; primary buttons radiate the brand-blue glow on focus and hover. Note that this site is dark-mode only — shadows still read because the body atmosphere underneath is even darker than the surfaces above.
Each chip below sits on the same body-coloured stage so the shadow's spread, opacity, and blur read as they do in production. The ramp is non-linear: md doubles sm, lg nearly triples it, xl doubles lg.
Shadows mark interaction state, not resting elevation. Cards rest flat (border + glass) and lift only on hover; the glow is reserved for the primary action.
.card-grid__card, the classification-API feature cells, the contextual-audiences panels, the about-page contact pill. Also stacks under --shadow-glow on focused contact-form inputs and bid-enrichment hover states.
.team-card, the about-page leadership portrait, the bid-enrichment / auto-tagging feature panels, the achievements grid. The default "this card is being reached for" elevation.
sync: commit.
.btn--solid, .btn--outline, .btn--glass, the final-CTA button, and on focus to contact-form inputs (stacked with --shadow-md). Signals "this is the thing to click."
Borders carry edges, divisions, and emphasis on the site. The vocabulary is small — one default glass ring covers every translucent surface, a single hover variant takes over on focus, dashed dividers separate content inside cards, and a handful of accent treatments mark emphasis or branded panels. There is no border-width token: weight is picked by role (1 px for chrome, 2–3 px for accent and emphasis). Colour comes from the glass tokens or from color-mix on a brand hue.
Each sample shows the border applied at the same size on a body-coloured stage. Roles cluster around three intents: edge (glass ring), division (dashed dividers), and emphasis (brand-tinted, accent-left, top-stripe).
Great content was being systematically undervalued. The technology to fix that existed.