Design language Foundations
Layout and shape
One column, a few section rhythms and a hairline where other systems reach for a box. This page sets out the container, spacing, rules, tones, splits and shapes the website uses. Every value is read from the file that defines it.
One container.
#Every page sits in one column, the wrap utility of the site stylesheet. It centres the content, stops growing at 1200px and declares a 28px gutter on each side, so the widest line of content is 1144px. There is no second, narrower container and no column grid inside it.
window 1440px
window 390px
gutter 28pxcontentmargin-inline: auto
wrap utility at a 1440px and a 390px window, drawn to the same scale from the values in the site stylesheet.| Window | wrap | Content |
|---|---|---|
| 320px | 320px | 264px |
| 390px | 390px | 334px |
| 900px | 900px | 844px |
| 1280px | 1200px | 1144px |
| 1440px | 1200px | 1144px |
Content width is the wrap width less two gutters. Below 1200px the wrap fills the window; above it, the side margins grow and the column stays where it is.
Keeping the gutter
wrap is a Tailwind utility, so it sits in the utilities layer, and a component's own styles win over it. An element that carries wrap therefore sets only its block padding, with padding-block. A padding shorthand would also set the inline padding and remove the gutter.
No element in use sets the shorthand, so every wrap keeps its gutter at every window width.
Reading width
Narrower measures are set inside components, mostly in ch. Research articles and legal documents use one column of at most 68ch, centred in the container. From 1180px upwards a 220px contents rail joins it on the right, 56px away.
Full-bleed scenes
Three pinned scenes leave the container on purpose: the home hero and the two scroll scenes, results on the home page and decision on the Zero Door page. The hero's stage fills the window while its text stays in wrap. In the other two the stage runs to the right edge of the window, and the text column sets its own left padding, max(28px, calc((100vw - 1200px) / 2 + 28px)). Up to 1200px that is the gutter; on wider windows it is the side margin of wrap plus the gutter. So at every window width the text starts on the same column edge as the rest of the page.
Under the sticky header
The header stays at the top while the page scrolls: a 66px row over a 1px hair line. Every element that can take keyboard focus keeps 84px of scroll margin above it, and the Section component keeps 80px for links that jump to it, so neither lands under the header.
The
wraputility is at most 1200px wide and declares a 28px gutter on each side.WhyOne column edge lines up the header, every section and the footer. The test reads the utility from the site stylesheet and fails if a value changes or a media query there alters it.
TestEnforced by a test on every change.
An element that carries
wrapsets its block padding only, withpadding-block.WhyA component's own padding wins over the utilities layer, so a
paddingshorthand removes the gutter. The test finds every style that sets inline padding on an element withwrapand fails on any that is not in its list of known exceptions. That list is empty today.TestEnforced by a test on every change.
Keyboard focus is not hidden under the sticky header.
WhyWCAG 2.2 success criterion 2.4.11. Every focusable element keeps 84px of scroll margin, more than the header is tall. The tests tab forwards and backwards through /, /zero-door and /tr/contact, in the desktop window and again in a desktop window narrowed to 390px, and fail if a focused element is covered completely.
TestEnforced by a test on every change.
There is one container. Narrower measures are set inside components, mostly in
ch.WhyA second container would add a second column edge. A measure in
chfollows the type size, so a line stays readable at any width.ReviewKept by review, not by a test.
Sections set the rhythm.
#The website has no spacing scale. Vertical space is set by the components a page is built from, and each one carries its own padding. An inner-page section has 72px above and below at every window width.
padding: 72px 0 40pxpadding: 72px 0padding: 72px 0padding: 72px 0PageHero, a Section on paper, a Section on paper-2 and the closing CtaBand2. The brackets show each padding, read from the component.| Component | Top and bottom | 900px and below |
|---|---|---|
| Section | 72px / 72px | same |
| CtaBand2 | 72px / 72px | same |
| CtaBand | 72px / 72px | same |
| PageHero | 72px / 40px | same |
| TrustHero | 64px / 56px | 40px / 32px |
| ResearchHero | 64px / 56px | 40px / 32px |
| ServicesHero | 64px / 56px | 40px / 32px |
| DoorHero | 64px / 56px | 40px / 32px |
| CompanyHero | 64px / 56px | 40px / 32px |
| Principles | 96px / 96px | same |
| Footer | 64px / 32px | same |
| Article | 72px / 32px | same |
| LegalDoc | 72px / 32px | same |
Every value in this table is a multiple of 8: 32px, 40px, 56px, 64px, 72px and 96px. The build and a unit test check this, so a change to any band padding is reviewed with this page.
Rows inside a section
Alternating feature rows are spaced by their own padding and a hair line between them: 48px above and below on the Zero Door page and 56px on the Services page, tightening to 36px and 40px at 900px and below.
Inside components
Within a component, spacing is written as literal pixel values. Of the 810 non-zero values written for padding, margin and gap in the production components, 772 are even, 471 are multiples of 4 and 268 are multiples of 8. The most used are 10px, 12px, 14px, 28px and 8px. They do not sit on a 4 or 8 pixel grid, and this page does not present one as if they did. The Zero Door interface does have a spacing scale; it is shown at the end of this page.
Build inner pages from
Sectionand close them withCtaBand2.WhyBoth carry the same 72px padding, a hair line on top and an 80px scroll margin, so every inner page keeps the same rhythm and its anchors land in the same place.
ReviewKept by review, not by a test.
Keep page-level padding on multiples of 8.
WhyEvery band in the table above follows it. It keeps the large rhythm regular while components stay free to use finer steps. The test reads each band from its component.
TestEnforced by a test on every change.
Hairlines carry the structure.
#Where other systems put each item in a box, the website draws lines. A structured set opens with a 1px rule in ink, its items are divided by hair lines of the same width, and numbered items carry their index in Geist Mono. On this page a hairline is any 1px line, and a hair line is one drawn in --color-hair.
A 1px rule in ink opens the set, once, at the top. It marks where a group begins.
Hair lines of the same width divide the items. They are lighter than the text they separate.
The index is set in Geist Mono at 11px in accent-deep, padded to two digits.
Ruled rows
- Ink rule
- Opens a structured set: ruled columns, ruled rows, numbered lists and glossary terms.
- Hair line
- Divides items, opens every full-width band and closes every hero.
- Hair-2 line
- Draws the border of a control, such as the motion pause button, and of cards inside illustrations.
- Accent stroke
- Marks the current page in the header and a quotation in an article, 2px wide.
Hair list
- A hair line on top marks a lighter list.
- Each item closes with a hair line of its own.
- There is no index and no ink, so the list stays quiet.
In use: which structure holds which content
- Ruled columns
- Three parallel points of equal weight, read side by side.
- Ruled rows
- A term and its definition, or a label and its value.
- Hair list
- Short unnumbered items that support the text around them.
Lines in use
- Ink rule
border-top: 1px solid var(--color-ink)- Hair line
border-top: 1px solid var(--color-hair)- Hair-2 line
border: 1px solid var(--color-hair-2)- Accent stroke
border-left: 2px solid var(--color-accent)
A 1px ink line that structures content is only ever the top border of a set.
WhyThe ink rule says where a group starts. Between items it would turn a list into a ledger and lose that meaning. The test reads every component style on the site and on this page and fails on an ink border on any other side, except on the ink button (a control), the frame of an open rule on the home page (a box) and the Do not example above.
TestEnforced by a test on every change.
Every full-width band opens with a hair line, and every hero closes with one.
WhyA single line and a change of tone mark the change of band, so no band needs a box or a shadow.
ReviewKept by review, not by a test.
Two papers and a tint.
#Sections sit on paper or on paper-2, and a page usually alternates between the two so that each section reads as its own band. As a band background, the accent tint is kept for one place: the band that closes a page with a call to action.
paper and paper-2 and the page closes on accent-tint.- --color-paper#fdfaf6The page itself and the default Section.
- --color-paper-2#f6f3eeSection with tone paper-2, the footer and illustration frames.
- --color-accent-tint#d9f5f3The background of closing call-to-action bands only.
- --color-ink#0f1c26Dark bands and panels: the proof strip on the Zero Door page, code and file panels.
| Text colour | paper | paper-2 | accent-tint |
|---|---|---|---|
| ink | 16.61:1 AAA | 15.62:1 AAA | 15.07:1 AAA |
| ink-muted | 6.85:1 AA | 6.44:1 AA | 6.21:1 AA |
| ink-subtle | 4.89:1 AA | 4.60:1 AA | 4.44:1 fail |
| accent-deep | 6.65:1 AA | 6.26:1 AA | 6.04:1 AA |
Where each tone is set
paperbody { background: var(--color-paper) }paper-2.sec.paper-2 { background: var(--color-paper-2) }accent-tint.cta { background: var(--color-accent-tint) }accent-tint.band { background: var(--color-accent-tint) }ink.proof { background: var(--color-ink) }
ink-subtle on accent-tint stays below 4.5:1. The closing bands therefore set their text in ink, ink-muted and accent-deep.
Alternation is a habit.
In use, the Architecture, Pricing and Solution pages alternate strictly, while the Company, Trust centre and Zero Door pages run two sections of the same tone in a row. Nothing in the code enforces alternation, so this page does not call it a rule.
Use
accent-tintas a band background only for the closing call to action.WhyThe accent means verified signal. As a band it appears once on a page, where the page asks the reader to act. The test fails if any other band sets
accent-tintas its background; tags and rows inside illustrations may still use it.TestEnforced by a test on every change.
Uneven splits, no column grid.
#The website has no column grid. Text-and-visual splits are written in each component as uneven fr ratios, so one side, usually the text, is visibly narrower than the other. Most of the work is done by four ratios.
Split heroes5fr 6frgap 56px
Trust centre, Research and Company heroes; Careers
Feature rows5fr 7frgap 56px
Feature rows on Zero Door and Services
Flipped rows7fr 5frgap 56px
Every second feature row
Definition rowsminmax(0, 4fr) minmax(0, 8fr)gap 40px
Definition lists on Architecture and Pricing
| Ratio | Column gap | Widths at 1144px |
|---|---|---|
| 5fr 6fr | 56px | 494.5px / 593.5px |
| 5fr 7fr | 56px | 453.3px / 634.7px |
| 7fr 5fr | 56px | 634.7px / 453.3px |
| 4fr 8fr | 40px | 368px / 736px |
Text first on narrow screens
At 900px and below every split becomes one column, usually with a 28px gap. A flipped row moves its text to the second column on wide screens with order: 2 and resets it to 0 at the breakpoint, so on a phone the text always comes before the visual.
The split heroes and feature rows keep bare fr tracks and set min-width: 0 on their visual column, so a wide illustration cannot widen its track. A new split can write each track as minmax(0, 5fr), as the definition rows do, and needs neither.
Equal columns and card grids
Sets of three use three equal tracks; on the Architecture page they are written repeat(3, minmax(0, 1fr)), so they may shrink. A few pairs, such as the paired cards on the Architecture page, use two equal tracks. Most card collections size themselves instead: an auto-fit track with a minimum width, so the number of columns follows the space available.
Write a text-and-visual split as an uneven
frratio inside the container.WhyThere is no grid to snap to. The ratio is chosen per layout, and the uneven split keeps the text at a readable measure beside a larger visual. Give the visual column
min-width: 0, or write the tracks withminmax(0, …), so long content cannot widen it.ReviewKept by review, not by a test.
On narrow screens the text comes before the visual.
WhyOn narrow screens the visual order returns to source order, so reading and focus order follow what the reader sees (WCAG 1.3.2 and 2.4.3). On wide screens only the column position changes, not the meaning.
ReviewKept by review, not by a test.
One main breakpoint.
#The website is designed desktop first. Components that change their layout mostly do it with max-width queries, and of the 46 production component and style files that have a width query, 40 use the same one: 900px. A few components add a breakpoint of their own. There is no breakpoint token; each value is written in the component that uses it.
max-width: 1199.98pxThe four rules on the home page fold into an accordion; on wider windows they stand side by side as frames that widen to open.
min-width: 1180pxArticles and legal documents gain a contents rail beside the text.
max-width: 1100pxGlossary letters stop hanging in the margin.
max-width: 1000pxThe four integration columns on Architecture become two.
max-width: 900pxmainThe header folds into a menu, splits and ruled columns become one column, heroes tighten.
40 of 46 files
max-width: 860pxGlossary rows stack.
max-width: 760pxThe architecture flow diagram scrolls inside its own frame.
max-width: 699.98pxThe rules accordion keeps one column, and each description runs under its glyph; wider windows get two columns.
max-width: 620pxThe integration columns become one.
What changes at 900px
- The header link row and its right-hand cluster hide, and a menu button opens a panel with the same links.
- Two-column splits become one column, text first.
- Ruled columns stack, and their side lines become top lines.
- Split heroes tighten from 64px / 56px to 40px / 32px above and below.
- The footer grid folds into two columns.
Design for the desktop first and switch at
max-width: 900px.WhyOne shared breakpoint means the header, the splits and the ruled sets change together, not one by one as the window narrows. The test fails if 900px stops being the query most files use.
TestEnforced by a test on every change.
Write a breakpoint in the component that needs it, as a literal.
WhyThere is no breakpoint token to reach for, so the value lives with the layout it changes and can be read in one place.
ReviewKept by review, not by a test.
No page scrolls sideways at 320px.
#Every page has to reflow at 320 CSS pixels, the width WCAG 2.2 uses for success criterion 1.4.10, without the page scrolling sideways. A test loads every built page at that width and fails if the document is wider than the window.
How layouts stay inside 320px
minmax(0, 1fr) tracks- Stops a long word, hash or path from widening its column past the window.
min-width: 0 on visual columns- Stops an illustration from forcing its grid cell wider than the track.
Focusable scroll boxes- Keeps wide tables, code and diagrams from pushing the page sideways. They scroll inside their own box, and the box takes keyboard focus so it can be scrolled without a mouse.
overflow-wrap on prose and code- Lets text without a break opportunity wrap instead of running out of its column.
auto-fit tracks with a minimum width- Lets card grids drop from three columns to one on a phone.
Every table on this page sits in such a box. At 320px it scrolls on its own while the page stays still.
No page scrolls sideways at 320 CSS px.
WhyWCAG 2.2 success criterion 1.4.10, Reflow. The test walks every page in the build, so a new page is covered the day it is added.
TestEnforced by a test on every change.
Two radii and square rules.
#Shape is restrained. There are two radius tokens: 6px for controls and overlay tags, 8px for cards and illustration frames. Ruled structures, section bands and the frames of the rules on the home page keep square corners: they are lines, not boxes.
- Button
--radius-sm6px - Ghost button
--radius-sm6px - Overlay tag
--radius-sm6px - Card
--radius-md8px - Illustration frame
--radius-md8px - Pause buttonliteral
50 percent - Mono tagliteral
4px - Search chipliteral
999px - Ruled setnone
0
Radius in use
--radius-sm6px- Buttons, the skip link, form fields, the menu button and its links, overlay tags and stamps; also article code blocks and images, the legal banner and some finding cards
--radius-md8px- Cards, illustration frames, the menu panel and ink code panels
- circle50 percent · 22 uses
- The motion pause button, step discs, map nodes
- small tag4px · 10 uses
- Small mono tags, badges, severity labels and pips
3px4 uses- Not one of the common shapes
2px2 uses- Not one of the common shapes
12px2 uses- Not one of the common shapes
- pill999px · 2 uses
- Search chips and the event pill in the Zero Door illustrations
8px1 use- Not one of the common shapes
10px1 use- Not one of the common shapes
calc(8 * var(--u))1 use- Not one of the common shapes
- square0
- Ruled sets, section bands, the frames of the home page rules
Outside the two tokens, radii are written as literals. Circles and 4px are the common ones, and 999px rounds two pill shapes. The rows above are read from every production component, so a new literal value appears here and fails a unit test until it is reviewed. The rest appear in only a few places: 3px, 2px, 12px, 8px, 10px and calc(8 * var(--u)).
The two radius tokens are 6px and 8px.
WhyThere is no larger token. The test reads the token file and fails if a value changes or a third radius token appears.
TestEnforced by a test on every change.
Use
radius-smfor controls and overlay tags,radius-mdfor cards and frames.WhyIn use, controls and floating tags mostly take
radius-smand cards and framesradius-md, so a corner often tells a control from a container. The split is not strict: article code blocks, the legal banner and some finding cards takeradius-sm.ReviewKept by review, not by a test.
Keep ruled structures square.
WhyA ruled set is made of lines. Rounding its corners would turn it back into a box.
ReviewKept by review, not by a test.
One shadow, for things that float.
#There is one shadow token and no elevation scale. The shadow is used only on objects that float over a page or an illustration: the menu panel, overlay tags and stamps, chips and floating cards inside visuals. Cards in the flow of the page have a border and no shadow.
--shadow-float: 0 12px 30px -18px rgb(15 28 38 / 0.45);The shadow is cast in the ink colour, --color-ink #0f1c26, with an alpha of 0.45, not in black.
Both radius tokens and the shadow live in the site's token file, which can be downloaded whole as tokens.css.
Every use of the shadow in production components
- The menu panel on narrow screens
.menu .panel- Overlay tags on illustrations
.tag- Evidence stamp
.stamp- Floating cards inside illustrations
.card- Search bar inside an illustration
.bar- Chips inside scroll scenes and illustrations
.chip, .chip.bare
Only floating objects cast
--shadow-float.WhyA shadow says that something sits above the page. In-flow cards are separated by a hair border and by tone instead. The test lists every use of the token in production components and fails on a new one, so each new use is checked against this rule.
TestEnforced by a test on every change.
Spacing and shape in Zero Door
#The Zero Door interface speaks the calm register of the same language, and it does what the website does not: it defines a spacing scale. The token values below come from the product token file as of 2026-08-23.
The product values in this section come from a snapshot of the product's tokens and components, published as product-tokens.json.
Spacing scale
The scale has 12 steps from 2px to 64px. Each bar is drawn at the real width of its step. In the code the steps feed one variable, the row padding shown under Density; components space themselves with Tailwind utility classes that hold the same values.
--space-12px--space-24px--space-36px--space-48px--space-512px--space-616px--space-720px--space-824px--space-932px--space-1040px--space-1148px--space-1264px
Shell
The frame around every screen is written in its components, as Tailwind classes or a component default, not as tokens. The values below are read from those components as of 2026-10-09. The content gutter is 24px, against 28px on the website.
The Zero Door shell
- Content gutter24px
- Page headers, pagination and the outer cells of tables align to it.In code
px-6 - Top bar56px
- Height of the bar along the top, which holds the search button for the command palette and the user menu.In code
h-14 - Sidebar240px
- Open width of the navigation sidebar.In code
w-60 - Rail56px
- The sidebar collapsed to a rail of icons.In code
w-14 - Side panel480px
- Default width of the side panel, capped at the window width.In code
width = 480 - Command palette576px
- Maximum width of the command palette.In code
max-w-xl
Radius
The product has three radius tokens: 4px for inputs, badges, tags, tooltips and small buttons; 8px for medium and large buttons, menus and empty states; 12px for the largest surfaces, such as the command palette.
--radius-sm4px--radius-md8px--radius-lg12px
Shadow
The product sets two shadow tokens per theme. The flat one marks a selected item, such as the active row in the sidebar; the raised one sits under overlays: dialogs, side panels, drawers, menus, tooltips and the command palette. Both tokens are cast in black; the website casts its single shadow in ink.
Light theme
--shadow-flat0 1px 2px rgb(0 0 0 / 0.04)--shadow-raised0 8px 24px rgb(0 0 0 / 0.08)Dark theme
--shadow-flat0 1px 2px rgb(0 0 0 / 0.20)--shadow-raised0 8px 24px rgb(0 0 0 / 0.40)Density
The product offers two density modes. Compact changes one thing in the code: the vertical padding of table rows drops from 12px to 6px. Comfortable is the default, and a control in the user menu switches between them.
Comfortable --space-5
- Row 1
padding 12px - Row 2
padding 12px - Row 3
padding 12px
Compact --space-3
- Row 1
padding 6px - Row 2
padding 6px - Row 3
padding 6px
Shared with the website: radius-md is 8px in both. Different: the small radius is 4px in the product and 6px on the website, and the product adds 12px for its largest surfaces.