Near-white #fafafa canvas, #171717 ink and one grey (#4d4d4d) for everything else: Geist type with tight negative tracking, 1px ring borders instead of strokes, and a single dark button per group.
Paint the page #fafafa and put white (#ffffff) only on things you can act on or read as a unit: buttons, cards, the highlighted plan, the auth card.
Use two text colours for almost everything: #171717 for what matters and #4d4d4d for the rest. Reach for #666666 and #8f8f8f only for small secondary text and icons.
Draw edges with a 1px box-shadow ring (#ebebeb or rgba(0, 0, 0, 0.08)), not borders. Add the 2px soft drop only on the few surfaces that float.
Set headlines in Geist with heavy negative tracking (-0.06em on display sizes) at weight 400 to 600; never bold 700.
Interface text is 14px. Buttons are 32px in headers, 36px in content, 40px in heroes and forms.
One dark #171717 button per group. Pair it with white ringed buttons; colour is never used for a button fill.
Blue #0072f5 is for focus rings and auth links only. The focus ring is a 2px white gap plus a 2px blue ring.
Keep motion short and plain: 0.1s for link colours, 0.15s with cubic-bezier(0.4, 0, 0.2, 1) for controls, 0.2s to 0.3s with a slight overshoot for popovers and overlays.
Avoid
Coloured, gradient or glowing buttons
Visible drop shadows on cards that sit on the canvas
Text in pure #000000 for body copy (it is reserved for docs card titles and the selected tab)
Weights of 700 and above, and positive letter spacing on headings
Custom-styled validation errors on simple auth forms; the platform relies on native browser validation
Dark overlays behind menus: the mega menu washes the page out with white instead
Source
Pages
homehttps://vercel.com
pricinghttps://vercel.com/pricing
docshttps://vercel.com/docs
loginhttps://vercel.com/login
signuphttps://vercel.com/signup
Captured
2026-11-13
Widths
1440, 768, 390
Mode
deep
Tool
craft-anything 0.4.0 + playwright 1.65.0
Layout Patterns
Header
64px (--header-height) on the canvas colour, no border until the page scrolls. 24px logo mark at the left edge; then the nav (two menu triggers with small chevrons, two plain links) in 14px #4d4d4d, the current page in #171717. Right edge: three 32px buttons 12px apart, two secondary and the dark one last.
Mega menu
Opening a nav trigger drops a full-width white panel under the header with a hairline below it. Three columns, each a small muted group label over a stack of large single-line links in #171717, some with a trailing north-east arrow for external pages. The page behind is washed out to about half strength, not darkened.
Home hero
Three zones on one row at 1440: a two-line 64px headline with two 40px pill buttons (dark then outlined) at the left, the large black triangle mark centred, and three short 16px lines stacked at the right that cycle. Lots of empty canvas above and below; no background image.
Logo row
Six monochrome customer logos spread edge to edge across the 1400px column, about 330px below the hero buttons.
Split showcase
A 56px two-line headline in a 673px left column, then a product illustration built from white panels with 1px rings, and at the right a two-tone 24px quote plus a small 'Features' label over 14px/500 links. The next section mirrors it with the headline on the right half.
Plan frame
Three plan columns share one 1px frame with 1px dividers; the middle (recommended) column is white, the others canvas. Each column: a small plan name (with a grey pill badge on the middle one), a large price with a small mono unit (the page inventory has 56px and 48px; which is the price was not isolated), 16px #4d4d4d description, a hairline, a 14px feature list with 16px line icons, and a 36px pill button at the bottom (dark only in the middle column).
Comparison table
Full 1400px width. A 36px pill search field and a 24px plan-name header row; then groups, each with a 16px line icon and 24px title, a 16px description and a hairline. Rows about 53px tall: 14px #4d4d4d label on the left, centred check marks or 14px values per plan, info icons after some labels, hairlines only between groups.
FAQ split
Headline (56px, two lines) in the left half; numbered accordion in the right half. Each row: two-digit number in #8f8f8f, 20px question in #171717, chevron at the far right; the open answer is 16px #4d4d4d under the question text.
Docs shell
Header with logo, a slash and the section name in 18px/600, then menu triggers. A 300px left sidebar on the canvas: a 36px search trigger with a key hint at the top, small muted group labels, 36px rows with chevrons for expandable items, and soft fades at its top and bottom edges as it scrolls. Main column 1024px.
Docs hero
Left: 56px/600 title, a lead paragraph in #4d4d4d (size not isolated), three 36px buttons (dark, then two outlined). Right: an underlined tab strip over a white terminal panel with a header row (icon, label, copy button) and 13px mono commands.
Card grid
Three columns of white 12px-radius link cards with 16px gaps: a 16px line icon, a 16px/600 title and a 13px #666666 description, 24px padding. Hover turns the card canvas colour over 0.25s.
Changelog list
Rows split by hairlines: a 13px date in a narrow left column, then an underlined 16px/500 title and an underlined 14px description.
Docs footer
40px block padding, 24px inline, six link columns at 1440, three at 768, two at 390. The home page footer was not captured.
Responsive
The header stays 64px; at 390 it shows only the logo and a two-line menu icon (docs adds a three-dot button after the section name). Home hero at 768 and 390 becomes one centred column: mark, centred headline, a single mono sub-line, then full-width stacked pill buttons. Pricing plans stack into one column already at 768; the pricing h1 is 64px at 768 and 40px at 390. The docs sidebar is hidden at 768 and 390, the docs title is 48px, cards stack to one column. The sign-up card goes to 358px wide with 16px side margins at 390 and its title to 24px.
Color
Background
canvas
Page background on every page, including the header and the auth screens
surface
Secondary buttons, docs cards, the highlighted plan column, the sign-up card, inputs
inverse
Primary button fill
inverse-pressed
Primary auth button right after a click, with the pointer still on it (read during the log-in step)
row-hover
Docs sidebar item on hover and press
badge
Small pill badge fill on the pricing page (three elements)
card-hover
Docs link card on hover and press (white card turns canvas colour)
Text
primary
Headlines, button labels, current nav item, emphasised words
secondary
The most used text colour: nav links, sidebar items, body copy, the second half of two-tone quotes
tertiary
Docs card descriptions, inactive tabs
muted
Icon buttons at rest and small grey text on pricing (21 elements), such as the FAQ numbers
faint
Legal links in the log-in footer
strong
Docs card titles, active tab, typed input text
on-inverse
Label on the primary button
link
Text links on auth screens and the skip link. Outside code highlighting it is the only coloured text seen; docs also has two #0068d6 text elements whose role was not isolated
Border
ring
1px box-shadow ring on secondary buttons, provider buttons and inputs; there are almost no real borders
ring-alpha
rgba(0, 0, 0, 0.08) ring on raised surfaces (sign-up card, docs search, raised pills)
tab-rail
1px inset rule under a tab list
card-edge
1px border of pricing feature cards
card-edge-hover
Pricing feature card border on hover
header-rule
Hairline under the header once the page scrolls (--header-border-bottom: 0 1px 0 0)
Accent
focus
Focus ring (2px white gap, then 2px blue: 0 0 0 2px #fff, 0 0 0 4px) and 2px solid outlines on links
rating-hover
Background of a feedback rating button on hover
Semantic
code-green
Highlighted tokens inside terminal code blocks on the docs page
error
--geist-error (#e00). Declared on the docs page; a rendered use was not observed
warning
--geist-warning. Declared on the docs page; a rendered use was not observed
legacy-success-blue
--geist-success (blue in this legacy palette). Declared on docs and auth pages; a rendered use was not observed
Geistgoogle-fonts · Same face: Geist is open source (SIL OFL), also on npm as geist. Loaded as a variable face, weights 100 to 900; 450 and 550 are used
button-large16px500lh 24pxls normal40px buttons: hero pills and every auth button
Ship the quiet interface
body16px400lh 24pxls normalDefault body, auth links, plan descriptions
Ship the quiet interface
prose16px400lh 27.2pxls normalDocs reading paragraphs; inline links in them are 16px/500, underlined
Ship the quiet interface
button14px500lh 21pxls normal32px and 36px buttons: header, pricing and docs
Ship the quiet interface
ui14px400lh 20pxls normalThe workhorse size (most counted on every page): nav links, table rows, feature lists. 21px line height in the docs sidebar
Ship the quiet interface
small13px400lh 18pxls normalPricing fine print and its links; docs card descriptions use 20px line height, the sign-up terms line 16px
Ship the quiet interface
code13px400lh 20pxls normalTerminal and code blocks, ligatures off
Ship the quiet interface
caption12px400lh 16pxls normalLegal links in the log-in footer
Space, Radius, Shadow
Spacing
2px
4px
6px
8px
10px
12px
16px
24px
32px
36px
40px
48px
64px
96px
128px
Unit
4px
Container
1448px including 24px inline padding, so content is 1400px (--ds-page-width). Docs main column 1024px; the docs sidebar 300px
Gutter
Desktop: 24px · Mobile: 24px on marketing and docs pages, 16px on auth pages
Section Gap
Pricing: the page opens with 144px of top padding at 1440, 96px at 768, 64px at 390; each section closes with 96px, 80px and 64px of bottom padding. The plan block has 72px above it at 1440
Radius
22pxPricing feature cards, legal text links
44px24px icon buttons, logo mark hit area on auth
66pxThe default (--geist-radius, most counted): 32px header buttons, docs sidebar items, menu rows, the docs search trigger, the skip link
88pxAuth buttons and the auth email field (--geist-marketing-radius, --radius-lg)
1212pxDocs link cards and the sign-up card
2020pxSix elements on home; which ones was not isolated
pill9999pxHero buttons, pricing plan buttons, Show more, the pricing search field, badges. Computed style reads 3.35544e+07px
circle50%32px feedback rating buttons
Shadow
ringrgb(235, 235, 235) 0px 0px 0px 1pxEdge of every secondary and provider button. In the computed value it is preceded by four transparent Tailwind ring layers
tab-railrgb(234, 234, 234) 0px -1px 0px 0px insetBottom rule of a tab list
header0 1px 0 0 #0000001aHeader bottom edge once scrolled (--header-border-bottom), faded in with box-shadow 0.2s ease
tooltip0 0 0 1px #00000014, 0px 1px 1px #00000005, 0px 4px 8px #0000000a, 0 0 0 1px var(--ds-background-200)--ds-shadow-tooltip with its border variables written out
menu0 0 0 1px #00000014, 0px 1px 1px #00000005, 0px 4px 8px -4px #0000000a, 0px 16px 24px -8px #0000000f--ds-shadow-menu: dropdowns. The captured variable is cut off after these layers, so any trailing layer is not recorded
modal0 0 0 1px #00000014, 0px 1px 1px #00000005, 0px 8px 16px -4px #0000000a, 0px 24px 32px -8px #0000000f--ds-shadow-modal: dialogs. Cut off in the capture like menu; no dialog was opened
modal-elevated0px 0px 0px 1px #00000014, 0px 32px 72px -12px #0000000f, 0px 8px 32px -12px #00000014, 0px 8px 24px -12px #0000001f--ds-shadow-modal-elevated, declared on docs and auth pages; a rendered use was not observed
Components
Button, primary
Anatomy: Dark filled rectangle (6px or 8px radius) or pill with a centred label; no icon.
Spec
height
32px in the header, 36px on pricing and docs, 40px in the home hero and on auth
padding
0 6px at 32px; 0 10px at 36px (docs), 0 12px as a 36px or 40px pill; 0 14px on auth
radius
6px at 32px and 36px; 9999px for hero and pricing pills; 8px on auth
background
#171717
color
#ffffff
font
14px/500, line height 21px at 32px and 36px; 16px/500, line height 24px at 40px
transition
all 0.15s cubic-bezier(0.4, 0, 0.2, 1)
States
hover
No difference measured under forced hover. After a click on the auth button, with the pointer still on it, the fill read #383838
active
Home hero pill: outline colour #f7fafd, width 2px, offset 1px (outline-style stays none, so nothing visible was measured)
focus-visible
Outline colour #005fcc, width 1px, offset 1px reported with outline-style none: no visible focus ring was measured on filled buttons
One per group, always the last of a header button group and the first of a hero pair.
Button, secondary
Anatomy: White fill with a 1px #ebebeb ring drawn as box-shadow, no border; same shapes and sizes as primary.
Spec
height
32px, 36px, 40px as primary
padding
as primary
radius
as primary
background
#ffffff (#fafafa for the Log In button on the sign-up header)
color
#171717
box-shadow
rgb(235, 235, 235) 0px 0px 0px 1px
font
as primary
transition
all 0.15s cubic-bezier(0.4, 0, 0.2, 1); the log-in header Sign Up button uses colours only, 0.2s ease
States
hover
No difference measured under forced hover
focus-visible
Outline colour #005fcc, width 1px, offset 1px with outline-style none, as primary
A raised variant on home (40px pill, 262px wide, padding 0 12px 0 8px, no text label; the uneven padding suggests a leading icon, not confirmed) uses the border-small shadow instead of the plain ring. Its states were not measured.
#a8a8a8, 12px/400 on log in; #171717 13px on sign up
list links
colours 0.1s cubic-bezier(0.4, 0, 0.2, 1)
States
hover
Auth and comparison-table links: underline appears. Legal links on log in: colour #4d4d4d
active
Same as hover
focus-visible
Outline 2px solid #0072f5, offset 4px. Sign-up legal links: the blue box-shadow ring instead
Text field
Anatomy: A bare input inside a wrapper; the wrapper draws the edge and radius, the input has neither.
Spec
height
40px on auth, 36px for the pricing search
padding
0 12px
background
#ffffff
color
#000000
font
16px/400, line height 24px on auth (prevents zoom on phones); 14px/400 for the pricing search
wrapper
8px radius on auth, pill on pricing; the auth page inventory shows one rgba(0, 0, 0, 0.08) 1px ring that is not on a button, which fits the field wrapper
overlay-fade-inDialog and command menu backdrop; it stops at 0.8 opacity. --ds-overlay-backdrop-color is the lightest grey, so the backdrop is light, not dark.
Hover on filled and outlined buttons: forced hover produced no measurable change on any of them, so their hover colour is not recorded. The only observed variant is #383838 on the dark auth button right after a click.
Running durations of most keyframes: the CSS is recorded but nothing was running when measured. Timings above come from the platform's --animate-* variables where one names the keyframe; the rest have none.
The home hero: a canvas fades in over 1.2s linear and the triangle mark is drawn in it; what the canvas animates is script-driven and not specified.
The three hero lines cycle by script. Only their CSS transitions (colour 0.5s, height 0.2s, detail opacity 0.3s) were measured, not the interval.
Everything on home below the second showcase rendered blank in the capture (it loads on scroll), so those sections and their motion are not recorded.
Sign up: a script-driven Web Animation (Motion) runs filter blur(0px) to blur(5px) on a div over 5100ms with a 110ms delay and a long linear() spring curve. The customer line under the card changes between screenshots; that this animation drives it is likely but not confirmed.
The mega menu, dropdowns and accordions were seen open, but their open and close motion was not captured as it ran.
Focus on the auth email field: no measured difference; screenshots show a soft grey double ring.
The front page: one large statement, proof logos, then alternating product showcases and a closing call to action.
Sticky 64px header (#fafafa, hairline appears once the page scrolls), full mega menu at 961px and up, hamburger sheet below
Hero 836px tall at 1440: H1 64px/400 line height 64px, -3.84px tracking, top at 328px; two 40px pill buttons; a circular product visual on the right; a list of short lines that reveal detail on hover
Logo row: 6 customer logos at about 24px tall
Three split showcases: H2 56px/450, 2 lines; media panel 516px to 660px tall beside a quote block (quote top 101px to 116px); 153px to 289px after each
"Lately released" grid: 3 cards, the first one tall
Closing call to action row: 2 pills
Footer 846px at 1440: 12 link columns in 2 rows of 6 (212px wide, 24px gap, 34px row gap), headings 14px/500, rows 28px, theme switch pill at the bottom right
An audience or industry page told inside one framed grid: proof numbers, features with small product visuals, a toolkit, a dark block and customer logos.
Framed column 1079px wide at x181, #ebebeb hairlines, plus marks at the top left and bottom right; 64px above, 90px below
Hero row 533px: H1 72px/450, line height 83.52px, -4.32px tracking, 2 lines, centred; lead 20px/36px; two 36px pills
Stats row 604px: H2 40px/450 on the left (359px column), 2x2 stats (24px/500 with a bold lead, logo below), dashed column rules
Two feature rows (597px and 629px): 16px label with icon, 24px/500 text with a bold lead, 443px visual 192px or 224px tall
Quote card (1014x72, 12px radius) and the toolkit: H2 40px, 6 cells in 3 columns (label, 20px/450 text, 32px round arrow), 97px row gap
Dark block (#0a0a0a) 527px: H2 32px #ededed, 3 link cells 348px tall
Logo grid: title row 238px, 3x2 logos (125px and 121px rows), 92px empty guide row
Call to action row 230px: 24px/500 text with coloured plan words, 2 pills; side column with a 14px note and a pill
Page height 5939px at 1440, 7943px at 390 (cells stack, toolkit cells 177px with the arrow on the right)
Policies and terms: long text with a table of contents.
Framed column with a 91px gap row, 154px title row (H1 56px), 90px date row
Two columns: 718px text column (48px padding, 16px/24px #4d4d4d paragraphs, 12px apart) and a sticky table of contents (16px/600 title, 14px links 12px apart)
Section headings 32px, 68px above (139px for the first)
Documentation pages: section sidebar, article and on-this-page list.
Docs header: logo, slash, Docs, Build and Learn menus, Getting Started; Ask AI, Log In, Sign Up on the right
Sidebar 240px at x24, sticky under the header and scrolling on its own: back row, 34px items (14px), 30px sub items (13px), chevrons for groups
Article 788px at x324: breadcrumbs at 112px, H1 48px/600 at 177px, 16px/25.6px paragraphs, H2 32px/600 with 35px to 39px above, code panels (40px head, 13px mono lines of 20px, line numbers), endpoint cards 388x46 in 2 columns, 12px gap
On this page list 240px at x1160: 14px title #7d7d7d, links 32px apart, active link 500 weight with a left rule
Page height 3761px at 1440, 6549px at 390 (no sidebar or list; H1 32px)
64px header: logo (mark on log in, wordmark on sign up) and one 32px button on the right
Log in: no card, a 320px column centred in the space between header and footer; title 32px/600; 40px email field, dark Continue with Email button, 1px rule with 16px around, 5 provider buttons 16px apart, ghost Show other options, 16px sign-up line; 64px footer with two 12px #a8a8a8 links
Sign up: white card 550x600 (12px radius, hairline), 72px under the header, 64px 80px 28px padding; title 2 lines; 4 provider buttons, Show other options, blue Continue with Email link, 13px terms line at the bottom; a single proof line (logo plus 14px result) 8px under the card
Both fit one viewport: 900px at 1440, 844px at 390 (card 358px wide, 40px from the header, title 24px)
Layout: Canvas #fafafa, no card. 64px header with the logo mark at the left and a 32px secondary Sign Up button at the right (24px side padding, 16px at 390). One 320px column centred horizontally, its 32px title about 156px from the top of a 900px viewport. 40px controls; 16px between them. A 64px footer holds two 12px #a8a8a8 legal links, centred.
Step 1Choose a method or enter email
On Screen
Title naming the action ("Log in to <product>"), 32px/600, centred
Email field, placeholder "Email Address"
Dark primary button: continue with email, full column width
1px hairline divider, 16px above and below
Five secondary provider buttons, each a brand icon left of the label: three OAuth providers, SAML SSO, passkey
Ghost button: show other options
16px line: a question with a blue sign-up link
Actions
Continue with email submits the field in place; there is no separate email screen, the URL stays /login
Provider buttons leave for the provider (not followed)
Show other options reveals more methods (not recorded)
Sign-up link goes to /signup
Validation
Empty submit: the browser's native bubble ("Please fill out this field.") under the field. Malformed address: the native bubble asking for an '@'. The page stays put and no custom inline error appears; the dark button reads #383838 while the pointer is still on it.
Not Recorded
Everything after a valid email (code or magic link), the provider and SSO hand-offs, the 'other options' content, and a dialog the state crawler saw open on /login (it changed the address and was not captured as an image).
Sign up
Entry: /signup
Layout: Canvas #fafafa. 64px header with the full wordmark at the left and a 32px Log In button (#fafafa fill, #ebebeb ring) at the right. A white card centred horizontally: 550px wide, 12px radius, border-small shadow, top at 136px, 600px tall at 1440 (358px wide with 16px margins, top 104px, at 390). Inside, a 390px column. Under the card, a single centred line pairing a customer logo with a 14px result that changes between visits.
Step 1Choose a method
On Screen
Title in two centred lines, 32px/600, -1.28px tracking
Four secondary provider buttons, brand icon left of the label, 40px with 16px between
Ghost button: show other options
Blue 16px text link: continue with email, with a trailing arrow
13px #4d4d4d terms line at the bottom of the card with #171717 links
Actions
Continue with email swaps the card content to step 2 in place; the URL stays /signup
Provider buttons leave for the provider (not followed)
Log In in the header goes to /login
Step 2Enter email
On Screen
Same title
Email field, focused on arrival (grey ring visible), placeholder is an example address
Dark primary button: continue with email, full column width
1px hairline
Blue text link with a leading arrow back to the other sign-up options
Terms line
Actions
Enter or the button submits
The back link returns to step 1
Validation
Same as log in: native browser bubbles only, for empty and malformed input; no custom inline error.
Not Recorded
Email verification and everything after it (account details, team or plan choice, onboarding) sit behind an account.
Evidence: --tw-* custom properties on rendered elements and Tailwind v4 theme variables (--spacing, --text-*, --ease-*); data-slot attributes on rendered elements, the convention shadcn/ui uses (weak evidence for shadcn itself)
Accordion, navigation menu and other unstyled primitives
Evidence: data-radix-collection-item, data-state and id^=radix- on rendered elements in docs; "data-radix-" in scripts on every page; --radix-accordion-content-height in keyframes
Read DESIGN.md (the uxprint for Vercel, added with `npx uxprint add vercel`) before writing UI. Use its tokens, type scale, component specs and motion values exactly as written, follow its principles, and avoid everything in its Avoid list.
# DESIGN.md: Vercel style
Build every screen in this project to this specification. It records the interface of Vercel (https://vercel.com),
captured 2026-11-13 at 1440, 768, 390 px. Reproduce the system, not the brand:
do not copy Vercel's logo, name, copy, illustrations or photos.
Near-white #fafafa canvas, #171717 ink and one grey (#4d4d4d) for everything else: Geist type with tight negative tracking, 1px ring borders instead of strokes, and a single dark button per group.
Theme: light. Category: marketing-site.
## Principles
- Paint the page #fafafa and put white (#ffffff) only on things you can act on or read as a unit: buttons, cards, the highlighted plan, the auth card.
- Use two text colours for almost everything: #171717 for what matters and #4d4d4d for the rest. Reach for #666666 and #8f8f8f only for small secondary text and icons.
- Draw edges with a 1px box-shadow ring (#ebebeb or rgba(0, 0, 0, 0.08)), not borders. Add the 2px soft drop only on the few surfaces that float.
- Set headlines in Geist with heavy negative tracking (-0.06em on display sizes) at weight 400 to 600; never bold 700.
- Interface text is 14px. Buttons are 32px in headers, 36px in content, 40px in heroes and forms.
- One dark #171717 button per group. Pair it with white ringed buttons; colour is never used for a button fill.
- Blue #0072f5 is for focus rings and auth links only. The focus ring is a 2px white gap plus a 2px blue ring.
- Keep motion short and plain: 0.1s for link colours, 0.15s with cubic-bezier(0.4, 0, 0.2, 1) for controls, 0.2s to 0.3s with a slight overshoot for popovers and overlays.
## Avoid
- Coloured, gradient or glowing buttons
- Visible drop shadows on cards that sit on the canvas
- Text in pure #000000 for body copy (it is reserved for docs card titles and the selected tab)
- Weights of 700 and above, and positive letter spacing on headings
- Custom-styled validation errors on simple auth forms; the platform relies on native browser validation
- Dark overlays behind menus: the mega menu washes the page out with white instead
## Color
### Background
| Name | Value | Use |
| --- | --- | --- |
| canvas | #fafafa | Page background on every page, including the header and the auth screens |
| surface | #ffffff | Secondary buttons, docs cards, the highlighted plan column, the sign-up card, inputs |
| inverse | #171717 | Primary button fill |
| inverse-pressed | #383838 | Primary auth button right after a click, with the pointer still on it (read during the log-in step) |
| row-hover | #f2f2f2 | Docs sidebar item on hover and press |
| badge | #ebebeb | Small pill badge fill on the pricing page (three elements) |
| card-hover | #fafafa | Docs link card on hover and press (white card turns canvas colour) |
### Text
| Name | Value | Use |
| --- | --- | --- |
| primary | #171717 | Headlines, button labels, current nav item, emphasised words |
| secondary | #4d4d4d | The most used text colour: nav links, sidebar items, body copy, the second half of two-tone quotes |
| tertiary | #666666 | Docs card descriptions, inactive tabs |
| muted | #8f8f8f | Icon buttons at rest and small grey text on pricing (21 elements), such as the FAQ numbers |
| faint | #a8a8a8 | Legal links in the log-in footer |
| strong | #000000 | Docs card titles, active tab, typed input text |
| on-inverse | #ffffff | Label on the primary button |
| link | #0072f5 | Text links on auth screens and the skip link. Outside code highlighting it is the only coloured text seen; docs also has two #0068d6 text elements whose role was not isolated |
### Border
| Name | Value | Use |
| --- | --- | --- |
| ring | #ebebeb | 1px box-shadow ring on secondary buttons, provider buttons and inputs; there are almost no real borders |
| ring-alpha | #00000014 | rgba(0, 0, 0, 0.08) ring on raised surfaces (sign-up card, docs search, raised pills) |
| tab-rail | #eaeaea | 1px inset rule under a tab list |
| card-edge | #e6e6e6 | 1px border of pricing feature cards |
| card-edge-hover | #c9c9c9 | Pricing feature card border on hover |
| header-rule | #0000001a | Hairline under the header once the page scrolls (--header-border-bottom: 0 1px 0 0) |
### Accent
| Name | Value | Use |
| --- | --- | --- |
| focus | #0072f5 | Focus ring (2px white gap, then 2px blue: 0 0 0 2px #fff, 0 0 0 4px) and 2px solid outlines on links |
| rating-hover | #e0f0ff | Background of a feedback rating button on hover |
### Semantic
| Name | Value | Use |
| --- | --- | --- |
| code-green | #297a3a | Highlighted tokens inside terminal code blocks on the docs page |
| error | #ee0000 | --geist-error (#e00). Declared on the docs page; a rendered use was not observed |
| warning | #f5a623 | --geist-warning. Declared on the docs page; a rendered use was not observed |
| legacy-success-blue | #0070f3 | --geist-success (blue in this legacy palette). Declared on docs and auth pages; a rendered use was not observed |
## Typography
| Role | Stack | Substitute | Source |
| --- | --- | --- | --- |
| sans | GeistSans, "GeistSans Fallback"; font-feature-settings: "calt" 0, "rlig", "ss11" | Geist (Same face: Geist is open source (SIL OFL), also on npm as geist. Loaded as a variable face, weights 100 to 900; 450 and 550 are used) | google-fonts |
| mono | "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-feature-settings: "liga" 0 | Geist Mono (Same face, open source. Used for code, the price unit and the hero sub-line on phones) | google-fonts |
| Name | Size | Weight | Line height | Tracking | Family | Use |
| --- | --- | --- | --- | --- | --- | --- |
| display | 64px | 400 | 64px | -3.84px | sans | Home hero headline, two lines. The pricing h1 uses the same size at weight 450 |
| section | 56px | 450 | 56px | -3.36px | sans | Home section headlines, two lines |
| docs-title | 56px | 600 | 56px | -3.36px | sans | Docs page h1 (48px at 768 and 390) |
| auth-title | 32px | 600 | 40px | -0.96px | sans | Log in title. The sign-up title uses -1.28px and drops to 24px at 390 |
| lead | 24px | 450 | 32px | -0.96px | sans | Two-tone quotes on home (first words #171717, rest #4d4d4d) and pricing card titles (h3) |
| heading | 24px | 600 | 32px | -0.96px | sans | Docs h2 |
| section-label | 18px | 600 | 27px | -0.54px | sans | The section name after the logo in the docs header |
| card-title | 16px | 600 | 24px | -0.32px | sans | Docs card titles (h3) |
| button-large | 16px | 500 | 24px | | sans | 40px buttons: hero pills and every auth button |
| body | 16px | 400 | 24px | | sans | Default body, auth links, plan descriptions |
| prose | 16px | 400 | 27.2px | | sans | Docs reading paragraphs; inline links in them are 16px/500, underlined |
| button | 14px | 500 | 21px | | sans | 32px and 36px buttons: header, pricing and docs |
| ui | 14px | 400 | 20px | | sans | The workhorse size (most counted on every page): nav links, table rows, feature lists. 21px line height in the docs sidebar |
| small | 13px | 400 | 18px | | sans | Pricing fine print and its links; docs card descriptions use 20px line height, the sign-up terms line 16px |
| code | 13px | 400 | 20px | | mono | Terminal and code blocks, ligatures off |
| caption | 12px | 400 | 16px | | sans | Legal links in the log-in footer |
## Spacing
- Unit: 4px
- Scale: 2px, 4px, 6px, 8px, 10px, 12px, 16px, 24px, 32px, 36px, 40px, 48px, 64px, 96px, 128px
- Container max width: 1448px including 24px inline padding, so content is 1400px (--ds-page-width). Docs main column 1024px; the docs sidebar 300px
- Page gutter: 24px desktop, 24px on marketing and docs pages, 16px on auth pages mobile
- Gap between sections: Pricing: the page opens with 144px of top padding at 1440, 96px at 768, 64px at 390; each section closes with 96px, 80px and 64px of bottom padding. The plan block has 72px above it at 1440
## Radius
| Name | Value | Use |
| --- | --- | --- |
| 2 | 2px | Pricing feature cards, legal text links |
| 4 | 4px | 24px icon buttons, logo mark hit area on auth |
| 6 | 6px | The default (--geist-radius, most counted): 32px header buttons, docs sidebar items, menu rows, the docs search trigger, the skip link |
| 8 | 8px | Auth buttons and the auth email field (--geist-marketing-radius, --radius-lg) |
| 12 | 12px | Docs link cards and the sign-up card |
| 20 | 20px | Six elements on home; which ones was not isolated |
| pill | 9999px | Hero buttons, pricing plan buttons, Show more, the pricing search field, badges. Computed style reads 3.35544e+07px |
| circle | 50% | 32px feedback rating buttons |
## Shadow
| Name | Value | Use |
| --- | --- | --- |
| ring | rgb(235, 235, 235) 0px 0px 0px 1px | Edge of every secondary and provider button. In the computed value it is preceded by four transparent Tailwind ring layers |
| ring-alpha | rgba(0, 0, 0, 0.08) 0px 0px 0px 1px | --ds-shadow-border-base: edges of raised surfaces |
| border-small | rgba(0, 0, 0, 0.08) 0px 0px 0px 1px, rgba(0, 0, 0, 0.04) 0px 2px 2px 0px, rgb(250, 250, 250) 0px 0px 0px 1px | Sign-up card, raised pill buttons on home (--ds-shadow-border-small) |
| ring-lift | rgb(235, 235, 235) 0px 0px 0px 1px, rgba(0, 0, 0, 0.05) 0px 1px 2px 0px | Ring plus a 1px drop, three elements across the site |
| focus-ring | rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px | Keyboard focus on icon buttons, menu triggers, cards, rating buttons (--ds-focus-ring) |
| tab-rail | rgb(234, 234, 234) 0px -1px 0px 0px inset | Bottom rule of a tab list |
| header | 0 1px 0 0 #0000001a | Header bottom edge once scrolled (--header-border-bottom), faded in with box-shadow 0.2s ease |
| tooltip | 0 0 0 1px #00000014, 0px 1px 1px #00000005, 0px 4px 8px #0000000a, 0 0 0 1px var(--ds-background-200) | --ds-shadow-tooltip with its border variables written out |
| menu | 0 0 0 1px #00000014, 0px 1px 1px #00000005, 0px 4px 8px -4px #0000000a, 0px 16px 24px -8px #0000000f | --ds-shadow-menu: dropdowns. The captured variable is cut off after these layers, so any trailing layer is not recorded |
| modal | 0 0 0 1px #00000014, 0px 1px 1px #00000005, 0px 8px 16px -4px #0000000a, 0px 24px 32px -8px #0000000f | --ds-shadow-modal: dialogs. Cut off in the capture like menu; no dialog was opened |
| modal-elevated | 0px 0px 0px 1px #00000014, 0px 32px 72px -12px #0000000f, 0px 8px 32px -12px #00000014, 0px 8px 24px -12px #0000001f | --ds-shadow-modal-elevated, declared on docs and auth pages; a rendered use was not observed |
## Layout
Breakpoints: min-width 401px (the most used query), min-width 601px / max-width 600px, 961px (--breakpoint-lg, --container-lg), 1200px and 1400px (--container-xl, --container-2xl)
- **Header:** 64px (--header-height) on the canvas colour, no border until the page scrolls. 24px logo mark at the left edge; then the nav (two menu triggers with small chevrons, two plain links) in 14px #4d4d4d, the current page in #171717. Right edge: three 32px buttons 12px apart, two secondary and the dark one last.
- **Mega menu:** Opening a nav trigger drops a full-width white panel under the header with a hairline below it. Three columns, each a small muted group label over a stack of large single-line links in #171717, some with a trailing north-east arrow for external pages. The page behind is washed out to about half strength, not darkened.
- **Home hero:** Three zones on one row at 1440: a two-line 64px headline with two 40px pill buttons (dark then outlined) at the left, the large black triangle mark centred, and three short 16px lines stacked at the right that cycle. Lots of empty canvas above and below; no background image.
- **Logo row:** Six monochrome customer logos spread edge to edge across the 1400px column, about 330px below the hero buttons.
- **Split showcase:** A 56px two-line headline in a 673px left column, then a product illustration built from white panels with 1px rings, and at the right a two-tone 24px quote plus a small 'Features' label over 14px/500 links. The next section mirrors it with the headline on the right half.
- **Plan frame:** Three plan columns share one 1px frame with 1px dividers; the middle (recommended) column is white, the others canvas. Each column: a small plan name (with a grey pill badge on the middle one), a large price with a small mono unit (the page inventory has 56px and 48px; which is the price was not isolated), 16px #4d4d4d description, a hairline, a 14px feature list with 16px line icons, and a 36px pill button at the bottom (dark only in the middle column).
- **Comparison table:** Full 1400px width. A 36px pill search field and a 24px plan-name header row; then groups, each with a 16px line icon and 24px title, a 16px description and a hairline. Rows about 53px tall: 14px #4d4d4d label on the left, centred check marks or 14px values per plan, info icons after some labels, hairlines only between groups.
- **FAQ split:** Headline (56px, two lines) in the left half; numbered accordion in the right half. Each row: two-digit number in #8f8f8f, 20px question in #171717, chevron at the far right; the open answer is 16px #4d4d4d under the question text.
- **Docs shell:** Header with logo, a slash and the section name in 18px/600, then menu triggers. A 300px left sidebar on the canvas: a 36px search trigger with a key hint at the top, small muted group labels, 36px rows with chevrons for expandable items, and soft fades at its top and bottom edges as it scrolls. Main column 1024px.
- **Docs hero:** Left: 56px/600 title, a lead paragraph in #4d4d4d (size not isolated), three 36px buttons (dark, then two outlined). Right: an underlined tab strip over a white terminal panel with a header row (icon, label, copy button) and 13px mono commands.
- **Card grid:** Three columns of white 12px-radius link cards with 16px gaps: a 16px line icon, a 16px/600 title and a 13px #666666 description, 24px padding. Hover turns the card canvas colour over 0.25s.
- **Changelog list:** Rows split by hairlines: a 13px date in a narrow left column, then an underlined 16px/500 title and an underlined 14px description.
- **Docs footer:** 40px block padding, 24px inline, six link columns at 1440, three at 768, two at 390. The home page footer was not captured.
Responsive: The header stays 64px; at 390 it shows only the logo and a two-line menu icon (docs adds a three-dot button after the section name). Home hero at 768 and 390 becomes one centred column: mark, centred headline, a single mono sub-line, then full-width stacked pill buttons. Pricing plans stack into one column already at 768; the pricing h1 is 64px at 768 and 40px at 390. The docs sidebar is hidden at 768 and 390, the docs title is 48px, cards stack to one column. The sign-up card goes to 358px wide with 16px side margins at 390 and its title to 24px.
## Components
### Button, primary
Dark filled rectangle (6px or 8px radius) or pill with a centred label; no icon.
- height: 32px in the header, 36px on pricing and docs, 40px in the home hero and on auth
- padding: 0 6px at 32px; 0 10px at 36px (docs), 0 12px as a 36px or 40px pill; 0 14px on auth
- radius: 6px at 32px and 36px; 9999px for hero and pricing pills; 8px on auth
- background: #171717
- color: #ffffff
- font: 14px/500, line height 21px at 32px and 36px; 16px/500, line height 24px at 40px
- transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1)
- State hover: No difference measured under forced hover. After a click on the auth button, with the pointer still on it, the fill read #383838
- State active: Home hero pill: outline colour #f7fafd, width 2px, offset 1px (outline-style stays none, so nothing visible was measured)
- State focus-visible: Outline colour #005fcc, width 1px, offset 1px reported with outline-style none: no visible focus ring was measured on filled buttons
One per group, always the last of a header button group and the first of a hero pair.
### Button, secondary
White fill with a 1px #ebebeb ring drawn as box-shadow, no border; same shapes and sizes as primary.
- height: 32px, 36px, 40px as primary
- padding: as primary
- radius: as primary
- background: #ffffff (#fafafa for the Log In button on the sign-up header)
- color: #171717
- box-shadow: rgb(235, 235, 235) 0px 0px 0px 1px
- font: as primary
- transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1); the log-in header Sign Up button uses colours only, 0.2s ease
- State hover: No difference measured under forced hover
- State focus-visible: Outline colour #005fcc, width 1px, offset 1px with outline-style none, as primary
A raised variant on home (40px pill, 262px wide, padding 0 12px 0 8px, no text label; the uneven padding suggests a leading icon, not confirmed) uses the border-small shadow instead of the plain ring. Its states were not measured.
### Button, ghost
Label only, no fill and no ring.
- height: 40px
- padding: 0 14px
- radius: 8px
- background: transparent
- color: #171717
- font: 16px/500, line height 24px
- transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1)
- State focus-visible: Outline colour #005fcc, width 1px (outline-style none)
Used for the 'show more options' row under the provider buttons on auth.
### Icon button
A 16px line icon in a square hit area, no fill.
- size: 24px (page actions), 28px (copy in a code header), 32px (copy prompt)
- radius: 4px at 24px, 6px at 28px and 32px
- color: #8f8f8f at 24px, #4d4d4d at 28px, #171717 at 32px
- transition: none at 24px; all 0.15s cubic-bezier(0.4, 0, 0.2, 1) at 28px and 32px
- State hover: 24px variant: colour #171717
- State active: 24px variant: colour #171717
- State focus-visible: 24px variant: colour #171717 and box-shadow rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px
### Nav link
Plain text in the header; menu triggers add a small chevron that flips when open.
- height: 32px
- padding: 0
- color: #4d4d4d; #171717 for the current page
- font: 14px/400, line height 20px
- gap between links: about 24px
- transition: none on the marketing header; the docs section label uses colours 0.15s cubic-bezier(0.4, 0, 0.2, 1)
- State hover: Docs section label: colour #171717. Marketing nav links: no difference measured
- State focus-visible: Links: outline 2px solid #0072f5, offset 4px. Docs section label: the blue box-shadow focus ring
### Text link
Inline text, three flavours: blue on auth, underlined ink in docs and pricing, grey legal links.
- auth: #0072f5, 16px/400, no underline at rest
- docs inline: #171717, 16px/500, underlined, line height 27.2px, transition opacity 0.1s cubic-bezier(0.4, 0, 0.2, 1)
- fine print: #171717, 13px/400, underlined
- legal: #a8a8a8, 12px/400 on log in; #171717 13px on sign up
- list links: colours 0.1s cubic-bezier(0.4, 0, 0.2, 1)
- State hover: Auth and comparison-table links: underline appears. Legal links on log in: colour #4d4d4d
- State active: Same as hover
- State focus-visible: Outline 2px solid #0072f5, offset 4px. Sign-up legal links: the blue box-shadow ring instead
### Text field
A bare input inside a wrapper; the wrapper draws the edge and radius, the input has neither.
- height: 40px on auth, 36px for the pricing search
- padding: 0 12px
- background: #ffffff
- color: #000000
- font: 16px/400, line height 24px on auth (prevents zoom on phones); 14px/400 for the pricing search
- wrapper: 8px radius on auth, pill on pricing; the auth page inventory shows one rgba(0, 0, 0, 0.08) 1px ring that is not on a button, which fits the field wrapper
- attributes: type=email, name=email, autocomplete=email, required
- State focus: Not measured. Screenshots of the focused auth field show a soft grey double ring around it
- State invalid: No styling; the browser's native validation bubble appears under the field
### Sidebar item
Row with the label left and a 16px chevron right for items that expand.
- height: 36px
- padding: 0 8px 0 10px
- gap: 8px
- radius: 6px
- color: #4d4d4d
- font: 14px/400, line height 21px
- transition: none on the row
- State hover: background #f2f2f2, colour #171717
- State active: background #f2f2f2, colour #171717
- State focus-visible: outline 2px solid #0072f5, offset 4px
### Search trigger
Field-shaped button: search icon, placeholder-style label, a small key-hint chip at the right.
- height: 36px
- radius: 6px
- color: #4d4d4d
- font: 14px/400, line height 21px
- width: 264px in the docs sidebar
- State focus-visible: box-shadow rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px
Opens the command menu (cmdk); the menu itself was not opened.
### Tabs
A row of text tabs on a 1px inset bottom rule; the selected tab carries a dark bar on that rule.
- height: 51px
- tab padding: 14px 2px
- font: 14px/400, line height 21px
- color: #666666 inactive, #000000 selected
- rail: rgb(234, 234, 234) 0px -1px 0px 0px inset
- State hover: colour and bar colour #000000
- State focus-visible: browser default outline (auto, 1px, #005fcc)
### Link card
White card: 16px line icon, 16px/600 title, 13px description; the whole card is the link.
- padding: 24px
- radius: 12px
- background: #ffffff
- title: 16px/600, -0.32px, #000000
- description: 13px/400, line height 20px, #666666
- edge: a 1px light edge is visible in screenshots; it is not on the link element itself
- transition: background 0.25s ease
- State hover: background #fafafa
- State active: background #fafafa
- State focus-visible: outline 2px solid #0072f5, offset 4px
### Feature card
Bordered panel with a text link and chevron at the top, an illustration, then a 24px title and 16px description at the bottom.
- padding: 32px
- gap: 32px
- radius: 2px
- border: 1px #e6e6e6
- background: transparent (canvas)
- transition: colours 0.15s cubic-bezier(0.4, 0, 0.2, 1)
- State hover: border colour #c9c9c9
- State active: border colour #c9c9c9
- State focus-visible: box-shadow rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px
### Accordion row
Number, question, chevron on one line; answer below, indented to the question text.
- summary height: 68px
- number: #8f8f8f, same size as the question
- question: 20px, #171717
- answer: 16px, #4d4d4d
- open motion: accordion-down 0.2s ease-out, accordion-up 0.2s ease-out
- State open: chevron turns up, answer revealed
- State focus-visible: outline colour #005fcc, width 1px
The 20px size comes from the page inventory; its weight and line height were not isolated.
### Dropdown menu
White popover under its trigger, right edges aligned; rows with a 16px icon and a 14px label.
- padding: 6px (--ds-popover-padding)
- row height: 36px (--ds-popover-row-height)
- row padding: 0 8px
- row radius: 6px
- shadow: --ds-shadow-menu
- motion: --ds-motion-popover-duration 0.2s with --ds-motion-timing-swift cubic-bezier(.175, .885, .32, 1.1)
Seen open on the docs prompt actions; row hover was not measured.
### Rating button
Round emoji button in a row of four, part of a 'was this helpful' box with a textarea and a small dark Send button.
- size: 32px
- radius: 50%
- color: #4d4d4d
- transition: background, border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1)
- textarea: 100px tall, padding 10px 12px, 14px/400 line height 20px
- send button: 32px, padding 0 6px, 6px radius, #171717, 14px/500
- State hover: background and border colour #e0f0ff
- State focus-visible: box-shadow rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px
### Code panel
White panel with a header row (prompt icon, 13px label, copy button at the right) over 13px mono lines.
- font: 13px Geist Mono, line height 20px, ligatures off
- token colour: #297a3a for highlighted words
- copy button: 28px icon button
### Skip link
Hidden link at the very top that appears on keyboard focus.
- height: 24px
- padding: 0 4px
- radius: 6px
- color: #0072f5
- background: #ffffff
- box-shadow: rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px
- opacity: 0
- State focus-visible: opacity 1
### Job row
Full-width link row: title and location stacked on the left, a Read more pill on the right.
- padding: 48px at 1440, 24px at 390
- title: 20px/450, line height 26px, -0.4px tracking, max 470px (16px/24px in 194px on phones)
- location: 16px/400 #4d4d4d, 8px under the title (14px/20px on phones)
- pill: 128x40 at 1440, 90x40 at 390, white with a #ebebeb ring, 14px/500
- divider: 1px #ebebeb between rows
- State hover: Not observed; the reference uses a white row background
### Template card
White card: image on top, title, two-line description.
- size: 448x361 at 1440, 342x306 at 390
- radius: 2px
- border: 1px rgba(0, 0, 0, 0.08)
- image: 235px tall (180px on phones)
- title: 20px/450, line height 26px, 24px from the image, one line
- text: 14px/400 #4d4d4d, line height 20px, clamped to 2 lines, 12px below the title
- State hover: Not observed
### Framed grid
A 1079px column outlined by #ebebeb hairlines with small plus marks at two corners; rows split by full rules and columns by dashed rules.
- width: 1079px at 1440, full width minus 16px each side on phones
- plus mark: 21px, 1px #a8a8a8 strokes, centred on the corner
- row rule: 1px #ebebeb
- column rule: 1px dashed #ebebeb
Used by the solution, careers and legal templates.
## Page templates
Every page of the site is built on one of these layouts. Pick the one that fits the page you are building.
### Home
The front page: one large statement, proof logos, then alternating product showcases and a closing call to action.
1. Sticky 64px header (#fafafa, hairline appears once the page scrolls), full mega menu at 961px and up, hamburger sheet below
2. Hero 836px tall at 1440: H1 64px/400 line height 64px, -3.84px tracking, top at 328px; two 40px pill buttons; a circular product visual on the right; a list of short lines that reveal detail on hover
3. Logo row: 6 customer logos at about 24px tall
4. Three split showcases: H2 56px/450, 2 lines; media panel 516px to 660px tall beside a quote block (quote top 101px to 116px); 153px to 289px after each
5. "Lately released" grid: 3 cards, the first one tall
6. Closing call to action row: 2 pills
7. Footer 846px at 1440: 12 link columns in 2 rows of 6 (212px wide, 24px gap, 34px row gap), headings 14px/500, rows 28px, theme switch pill at the bottom right
8. Page height 5930px at 1440, 6905px at 390
Pages on this layout: /home
### Product Page
A single product or capability: hero with a dark product bar, then a grid of feature cards and a call to action.
1. Hero: chips row, H1 and lead, 36px pills, a dark full-width product bar
2. H2 48px/450 in 2 lines
3. Feature grid: 9 cards in 3 columns, each a 448x252 media frame with a 14px title and body, 72px between rows
4. Call to action row (2 pills), footer
5. Page height 3362px at 1440, 6169px at 390
Pages on this layout: /ai, /ci, /cdn, /eve, /agent, /botid, /fluid, /ai-sdk, /chat, /plugin, /sandbox, /passport, /security, /workflows, /ai-gateway, /connect, /products/observability, /products/previews, /security/bot-management, /security/web-application-firewall, /solutions/turborepo, /frameworks/nextjs, /oss
### Solution Page
An audience or industry page told inside one framed grid: proof numbers, features with small product visuals, a toolkit, a dark block and customer logos.
1. Framed column 1079px wide at x181, #ebebeb hairlines, plus marks at the top left and bottom right; 64px above, 90px below
2. Hero row 533px: H1 72px/450, line height 83.52px, -4.32px tracking, 2 lines, centred; lead 20px/36px; two 36px pills
3. Stats row 604px: H2 40px/450 on the left (359px column), 2x2 stats (24px/500 with a bold lead, logo below), dashed column rules
4. Two feature rows (597px and 629px): 16px label with icon, 24px/500 text with a bold lead, 443px visual 192px or 224px tall
5. Quote card (1014x72, 12px radius) and the toolkit: H2 40px, 6 cells in 3 columns (label, 20px/450 text, 32px round arrow), 97px row gap
6. Dark block (#0a0a0a) 527px: H2 32px #ededed, 3 link cells 348px tall
7. Logo grid: title row 238px, 3x2 logos (125px and 121px rows), 92px empty guide row
8. Call to action row 230px: 24px/500 text with coloured plan words, 2 pills; side column with a 14px note and a pill
9. Page height 5939px at 1440, 7943px at 390 (cells stack, toolkit cells 177px with the arrow on the right)
Pages on this layout: /for/retail, /for/web-apps, /for/marketing-sites, /for/platforms, /enterprise, /solutions/design-engineering, /solutions/platform-engineering, /partners/aws, /startups, /open-source-program
### Pricing
Plans, a full comparison table and the pricing FAQ.
1. H1 display in 2 lines
2. Plans frame: 3 plan columns with price, lead, feature list and a button
3. Fine print, two side cards
4. Comparison table with a sticky head (plan names fade in), group rows, per-row heights as measured, check and dash marks
5. Call to action row
6. FAQ accordion of 14 items, the first open
7. "Still not sure?" call to action
8. Page height 16092px at 1440
Pages on this layout: /pricing
### About
Company story: statement, pillars, investors and people.
1. Hero: display H1 in 2 lines with a side lead and a pill
2. 3 pillars with labels
3. Investor logo grid of 16 cells
4. People grid of 17 cells (260px and 280px)
5. Call to action, footer
6. Page height 5798px at 1440, 11215px at 390
Pages on this layout: /about
### Customer Stories
Story index: carousel of featured stories, a story list, a quote and a logo wall.
1. H1 72px/400 at 176px
2. Carousel: 974x548 slides, previous and next buttons with a progress bar
3. 13 story rows of 96px
4. Quote
5. Logo wall: 60 logos in 6 columns of 118px (20 on phones), select filter, Show More
6. Page height 5696px at 1440, 8664px at 390
Pages on this layout: /customers
### Careers
Job board inside the framed grid: hero, filters on the left and a long list of positions.
1. Framed column 1079px, 64px above and 181px below
2. Hero row 539px with a 90px guide grid and a globe drawing; title 48px/450 in 2 lines at 388px; 36px pill
3. Head row 93px: H2 32px/450 in the right column
4. Left column 359px: Location and Department filter rows (60px, 16px/600), sticky
5. Job rows 718px wide: 48px padding, title 20px/450 (max 470px), location 16px #4d4d4d 8px below, 128x40 Read more pill; 154px with a location, 136px without, 180px for 2-line titles
6. Page height 15090px at 1440 (86 rows), 13309px at 390 (rows 100px to 168px, 16px titles in 194px, 90px pills)
Pages on this layout: /careers
### Blog and Article Index
Lists of posts, changelog entries, press items and courses.
1. H1 48px/450 at 112px; filter pills, search field and RSS icon
2. 3 featured cards (420px, H2 32px)
3. Post grid: 12 posts of 216px (date, H3 24px/450 in up to 3 lines, author avatars)
4. Show more pill
5. Two split sections with an H2 and link lists
6. Page height 3328px at 1440, 7338px at 390 (posts 156px with 89px gaps)
Pages on this layout: /blog, /changelog, /press, /i, /kb, /academy, /events
### Template Catalog
Searchable grid of templates, integrations or partners.
1. H1 48px/450 at 136px with a 384px lead (16px, 2 lines)
2. Right: 256x36 search pill with icon and a 100x36 Filters pill
3. Card grid: 3 columns, 24px gaps, cards 448x361 (white, 2px radius, hairline), 235px image, 20px/450 title 24px below, 14px text clamped to 2 lines
4. View All pill (105x36) 34px under the grid, 96px before the footer
5. Page height 4396px at 1440 (24 cards); 8414px at 390 in the survey (cards 342x306 with 180px images)
Pages on this layout: /templates, /marketplace, /shipped, /partners/solution-partners
### Legal Document
Policies and terms: long text with a table of contents.
1. Framed column with a 91px gap row, 154px title row (H1 56px), 90px date row
2. Two columns: 718px text column (48px padding, 16px/24px #4d4d4d paragraphs, 12px apart) and a sticky table of contents (16px/600 title, 14px links 12px apart)
3. Section headings 32px, 68px above (139px for the first)
4. Page height 4220px at 1440, 6615px at 390
Pages on this layout: /legal, /legal/dpa, /legal/terms, /legal/cookie-policy, /legal/privacy-notice, /legal/acceptable-use-policy
### Contact Form
Sales or support contact: intro with proof on the left, form on the right.
1. Intro 684px: display H1, 18px lead, 5 proof rows (logo plus 16px/500 result, 34px apart; 3 rows on phones)
2. Form 566px: 2 columns of 275px, 32px row gap, 36px fields (6px radius, hairline ring), 150px textarea, consent box with a switch, 36px submit pill
3. Page height 1924px at 1440, 3454px at 390
Pages on this layout: /contact/sales, /help, /domains, /drop
### Docs Article
Documentation pages: section sidebar, article and on-this-page list.
1. Docs header: logo, slash, Docs, Build and Learn menus, Getting Started; Ask AI, Log In, Sign Up on the right
2. Sidebar 240px at x24, sticky under the header and scrolling on its own: back row, 34px items (14px), 30px sub items (13px), chevrons for groups
3. Article 788px at x324: breadcrumbs at 112px, H1 48px/600 at 177px, 16px/25.6px paragraphs, H2 32px/600 with 35px to 39px above, code panels (40px head, 13px mono lines of 20px, line numbers), endpoint cards 388x46 in 2 columns, 12px gap
4. On this page list 240px at x1160: 14px title #7d7d7d, links 32px apart, active link 500 weight with a left rule
5. Page height 3761px at 1440, 6549px at 390 (no sidebar or list; H1 32px)
Pages on this layout: /docs, /docs/frameworks, /docs/queues/sdk, /docs/rest-api/sdk, /docs/frameworks/backend/nitro, /docs/flags/flags-sdk-reference, /docs/frameworks/backend/fastapi, /docs/frameworks/full-stack/nuxt, /docs/frameworks/full-stack/sveltekit, /docs/frameworks/full-stack/tanstack-start
### Auth
Log in and sign up.
1. 64px header: logo (mark on log in, wordmark on sign up) and one 32px button on the right
2. Log in: no card, a 320px column centred in the space between header and footer; title 32px/600; 40px email field, dark Continue with Email button, 1px rule with 16px around, 5 provider buttons 16px apart, ghost Show other options, 16px sign-up line; 64px footer with two 12px #a8a8a8 links
3. Sign up: white card 550x600 (12px radius, hairline), 72px under the header, 64px 80px 28px padding; title 2 lines; 4 provider buttons, Show other options, blue Continue with Email link, 13px terms line at the bottom; a single proof line (logo plus 14px result) 8px under the card
4. Both fit one viewport: 900px at 1440, 844px at 390 (card 358px wide, 40px from the header, title 24px)
Pages on this layout: /login, /signup
## Motion
Durations, easings and keyframes are measured values. Use them as written; honour `prefers-reduced-motion`.
### Durations
| Name | Value | Use |
| --- | --- | --- |
| link | 0.1s | Colour changes on text links; opacity on underlined docs links |
| default | .15s | --default-transition-duration: buttons (all), card borders, docs nav colours |
| popover | .2s | --ds-motion-popover-duration; also accordions, rating buttons, header shadow |
| card | 0.25s | Docs card background on hover |
| overlay | .3s | --ds-motion-overlay-duration: dialog and command menu backdrop and panel; header opacity |
| cycle | 0.5s | Colour change on the cycling hero lines |
### Easings
| Name | Value | Use |
| --- | --- | --- |
| standard | cubic-bezier(0.4, 0, 0.2, 1) | The default for nearly every transition (--default-transition-timing-function, --ease-in-out) |
| ease-out | cubic-bezier(0, 0, 0.2, 1) | Hero line changes and the docs feedback box (--ease-out) |
| ease-in | cubic-bezier(0.4, 0, 1, 1) | One pricing colour transition (--ease-in) |
| swift | cubic-bezier(.175, .885, .32, 1.1) | --ds-motion-timing-swift, a slight overshoot: overlays and popovers |
| out-expo | cubic-bezier(.16, 1, .3, 1) | fade-slide-in and the feedback toast scale in and out |
| slow-settle | cubic-bezier(.4, .04, .04, 1) | Long 1.25s fade-in and slide-in, card flips |
| in-out-quad | cubic-bezier(.455, .03, .515, .955) | Command menu loading bar; a 0.3s opacity on pricing |
| fade | cubic-bezier(0.3, 0.57, 0.07, 0.95) | A 0.15s opacity transition present on every page; the element was not identified |
### Transitions
| Target | Properties | Duration | Easing |
| --- | --- | --- | --- |
| Button (primary, secondary, ghost, icon) | all | 0.15s | cubic-bezier(0.4, 0, 0.2, 1) |
| Text and footer links | color, background-color, border-color, outline-color, text-decoration-color, fill, stroke | 0.1s | cubic-bezier(0.4, 0, 0.2, 1) |
| Docs section label, docs nav colours | color, background-color, border-color, outline-color, text-decoration-color, fill, stroke | 0.15s | cubic-bezier(0.4, 0, 0.2, 1) |
| Feature card border | color, background-color, border-color, outline-color, text-decoration-color, fill, stroke | 0.15s | cubic-bezier(0.4, 0, 0.2, 1) |
| Docs link card | background | 0.25s | ease |
| Underlined docs link | opacity | 0.1s | cubic-bezier(0.4, 0, 0.2, 1) |
| Rating button | background, border-color | 0.2s | cubic-bezier(0.4, 0, 0.2, 1) |
| Comparison table icons (svg) | all | 0.2s | cubic-bezier(0.4, 0, 0.2, 1) |
| Header on marketing pages | opacity | 0.3s | cubic-bezier(0.4, 0, 0.2, 1) |
| Header bottom edge on scroll (sign-up) | box-shadow | 0.2s | ease |
| Log-in header button | color, background-color, border-color, outline-color, text-decoration-color, fill, stroke | 0.2s | ease |
| Cycling hero lines: text | color | 0.5s | cubic-bezier(0, 0, 0.2, 1) |
| Cycling hero lines: container and detail | height 0.2s; opacity of the detail text 0.3s | 0.2s and 0.3s | cubic-bezier(0, 0, 0.2, 1) |
| Auth provider group | opacity, transform, filter | 0.13s, 0.2s, 0.13s | ease-out, ease-in-out, ease-out |
| Auth footer line | opacity, transform, filter | 0.11s, 0.175s, 0.11s | ease-out, ease-in-out, ease-out |
| Another auth block (not identified) | opacity, transform, filter | 0.08s, 0.175s, 0.08s | ease-out, ease-in-out, ease-out |
| Docs sidebar panel | transform, translate, opacity, filter | 0.2s | ease |
| Docs sidebar edge fades | --docs-sidebar-fade-top, --docs-sidebar-fade-bottom | 0.15s | ease |
| Docs feedback box growing | height, width, border-radius, transform, background-color | 0.15s | cubic-bezier(0, 0, 0.2, 1) |
| Docs feedback form reveal | opacity, translate | 0.2s | cubic-bezier(0.4, 0, 0.2, 1) |
| Home hero canvas fade-in (seen running) | opacity 0 to 1 | 1.2s | linear |
### Keyframes
**overlay-fade-in:** Dialog and command menu backdrop; it stops at 0.8 opacity. --ds-overlay-backdrop-color is the lightest grey, so the backdrop is light, not dark. Timing: var(--ds-motion-overlay-duration) var(--ds-motion-overlay-timing): .3s cubic-bezier(.175, .885, .32, 1.1).
```css
@keyframes overlay-fade-in { 0% { opacity: 0; } 100% { opacity: 0.8; } }
```
**overlay-fade-out:** Backdrop leaving. Timing: .3s cubic-bezier(.175, .885, .32, 1.1).
```css
@keyframes overlay-fade-out { 0% { opacity: 0.8; } 100% { opacity: 0; } }
```
**overlay-scale-in:** Dialog and command menu panel entering; --ds-motion-overlay-scale is .96. Timing: .3s cubic-bezier(.175, .885, .32, 1.1).
```css
@keyframes overlay-scale-in { 0% { transform: scale(var(--ds-motion-overlay-scale)); opacity: 0; } 100% { opacity: 1; transform: scale(1); } }
```
**overlay-scale-out:** Dialog and command menu panel leaving. Timing: .3s cubic-bezier(.175, .885, .32, 1.1).
```css
@keyframes overlay-scale-out { 0% { opacity: 1; transform: scale(1); } 100% { transform: scale(var(--ds-motion-overlay-scale)); opacity: 0; } }
```
**command-loading:** Indeterminate bar while the command menu searches. Timing: 1.1s cubic-bezier(.455, .03, .515, .955) infinite.
```css
@keyframes command-loading { 0% { opacity: 1; transform: translate(-100%); } 100% { opacity: 1; transform: translate(300%); } }
```
**nav-enter-from-left:** Navigation menu content when moving to an item on the left; served with the auth pages.
```css
@keyframes nav-enter-from-left { 0% { opacity: 0; transform: translate(-200px); } 100% { opacity: 1; transform: translate(0px); } }
```
**nav-enter-from-right:** Navigation menu content when moving to an item on the right.
```css
@keyframes nav-enter-from-right { 0% { opacity: 0; transform: translate(200px); } 100% { opacity: 1; transform: translate(0px); } }
```
**nav-exit-to-left:** Outgoing navigation menu content.
```css
@keyframes nav-exit-to-left { 0% { opacity: 1; transform: translate(0px); } 100% { opacity: 0; transform: translate(-200px); } }
```
**nav-exit-to-right:** Outgoing navigation menu content.
```css
@keyframes nav-exit-to-right { 0% { opacity: 1; transform: translate(0px); } 100% { opacity: 0; transform: translate(200px); } }
```
**nav-scale-in:** Navigation menu viewport appearing, tipping forward slightly.
```css
@keyframes nav-scale-in { 0% { opacity: 0; transform: rotateX(-30deg) scale(0.9); } 100% { opacity: 1; transform: rotateX(0deg) scale(1); } }
```
**nav-scale-out:** Navigation menu viewport closing.
```css
@keyframes nav-scale-out { 0% { opacity: 1; transform: rotateX(0deg) scale(1); } 100% { opacity: 0; transform: rotateX(-10deg) scale(0.95); } }
```
**accordion-down:** Accordion answer opening. Timing: .2s ease-out.
```css
@keyframes accordion-down { 0% { height: 0px; } 100% { height: var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto))))); } }
```
**accordion-up:** Accordion answer closing. Timing: .2s ease-out.
```css
@keyframes accordion-up { 0% { height: var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto))))); } 100% { height: 0px; } }
```
**dropdown-open:** Small dropdowns dropping in from just above (auth pages).
```css
@keyframes dropdown-open { 0% { opacity: 0; transform: translateY(-5px); } 100% { opacity: 1; transform: none; } }
```
**dropdown-close:** Small dropdowns leaving upward.
```css
@keyframes dropdown-close { 0% { opacity: 1; transform: none; } 100% { opacity: 0; transform: translateY(-10px); } }
```
**tooltip-fade-in:** Tooltips: a 0.4s hover delay, then a 0.1s fade (0.1s delay for the faster variant). Timing: .1s ease-in .4s forwards.
```css
@keyframes tooltip-fade-in { 0% { opacity: 0; } 100% { opacity: 1; pointer-events: all; } }
```
**popover-fade-out:** Popovers closing. Timing: var(--ds-motion-popover-timing) var(--ds-motion-popover-duration): cubic-bezier(.175, .885, .32, 1.1), .2s.
```css
@keyframes popover-fade-out { 0% { opacity: 1; } 100% { opacity: 0; } }
```
**hover-card-slide-down:** Docs hover card appearing below its trigger.
```css
@keyframes hover-card-slide-down { 0% { opacity: 0; transform: translateY(-10px); } 100% { opacity: 1; transform: none; } }
```
**hover-card-slide-up:** Docs hover card appearing above its trigger.
```css
@keyframes hover-card-slide-up { 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: none; } }
```
**tip-enter:** Inline tips on auth screens: fade in out of a 3px blur.
```css
@keyframes tip-enter { 0% { filter: blur(3px); opacity: 0; } 100% { filter: blur(); opacity: 1; } }
```
**tip-exit:** Inline tips leaving into a blur.
```css
@keyframes tip-exit { 0% { filter: blur(); opacity: 1; } 100% { filter: blur(3px); opacity: 0; } }
```
**swap-reveal:** Auth card content swapping between steps: fades in from a 2px blur.
```css
@keyframes swap-reveal { 0% { opacity: 0; filter: blur(2px); } }
```
**sso-reveal-fade:** The SSO field appearing on auth.
```css
@keyframes sso-reveal-fade { 0% { opacity: 0; filter: blur(2px); } }
```
**sso-reveal-slide:** Paired with sso-reveal-fade: slides down 6px into place.
```css
@keyframes sso-reveal-slide { 0% { transform: translateY(-6px); } }
```
**item-enter:** List items entering on auth pages.
```css
@keyframes item-enter { 0% { opacity: 0; transform: translateY(4px); } 100% { opacity: 1; transform: none; } }
```
**item-leave:** List items leaving on auth pages.
```css
@keyframes item-leave { 0% { opacity: 1; transform: none; } 100% { opacity: 0; transform: translateY(-2px); } }
```
**shake:** A small sideways shake, served on docs and auth; the trigger was not observed.
```css
@keyframes shake { 25% { translate: -1%; } 75% { translate: 1%; } }
```
**modal-appear:** Modal rising 20px into place.
```css
@keyframes modal-appear { 0% { opacity: 0; transform: translateY(20px); } 100% { opacity: 1; transform: translateY(0px); } }
```
**feedback-appear:** Feedback widget content appearing. Timing: .5s .1s ease forwards.
```css
@keyframes feedback-appear { 0% { opacity: 0; transform: translateY(5px); } 100% { opacity: 1; transform: none; } }
```
**feedback-fade-in:** Feedback popover scaling in. Timing: .1s cubic-bezier(.16, 1, .3, 1).
```css
@keyframes feedback-fade-in { 0% { opacity: 0; scale: 0.95; } 100% { opacity: 1; scale: 1; } }
```
**feedback-fade-out:** Feedback popover scaling out. Timing: .2s cubic-bezier(.16, 1, .3, 1) forwards.
```css
@keyframes feedback-fade-out { 0% { opacity: 1; scale: 1; } 100% { opacity: 0; scale: 0.95; } }
```
**skeleton:** Loading placeholder sweep. Timing: 1.5s ease-in-out infinite reverse.
```css
@keyframes skeleton { 100% { transform: translate(-50%); } }
```
**shimmer:** Loading shimmer across a wide gradient (docs and marketing bundles).
```css
@keyframes shimmer { 0% { background-position: 200% 0px; } 100% { background-position: -200% 0px; } }
```
**spinner-opacity:** Spinner blades fading in turn.
```css
@keyframes spinner-opacity { 0% { opacity: 1; } 100% { opacity: 0.15; } }
```
**spin:** Loading icon rotation. Timing: 1s linear infinite.
```css
@keyframes spin { 100% { transform: rotate(360deg); } }
```
**caret-blink:** Blinking caret; where it is applied was not observed.
```css
@keyframes caret-blink { 0%, 70%, 100% { opacity: 1; } 20%, 50% { opacity: 0; } }
```
**marquee:** A sideways-scrolling row. At 390 the customer logo row is cropped mid-logo, which fits it; not seen running. Timing: var(--marquee-speed,40s) linear infinite.
```css
@keyframes marquee { 0% { transform: translate(0px); } 100% { transform: translateX(calc(-100% - var(--marquee-gap))); } }
```
**logo-carousel:** Logos taking turns in one slot: visible for about a fifth of the cycle. Timing: ease-in-out infinite (duration set per element, not recorded).
```css
@keyframes logo-carousel { 0% { opacity: 0; } 3% { opacity: 1; } 22% { opacity: 1; } 25% { opacity: 0; } 100% { opacity: 0; } }
```
**letter-reveal:** Home: letters leaving by blurring and growing.
```css
@keyframes letter-reveal { 100% { opacity: 0; filter: blur(4px); transform: scale(1.3); } }
```
**slide-up-fade-in:** Marketing blocks rising 8px into view.
```css
@keyframes slide-up-fade-in { 0% { opacity: 0; transform: translateY(8px); } 100% { opacity: 1; transform: translateY(0px); } }
```
### Not measured
- Hover on filled and outlined buttons: forced hover produced no measurable change on any of them, so their hover colour is not recorded. The only observed variant is #383838 on the dark auth button right after a click.
- Running durations of most keyframes: the CSS is recorded but nothing was running when measured. Timings above come from the platform's --animate-* variables where one names the keyframe; the rest have none.
- The home hero: a canvas fades in over 1.2s linear and the triangle mark is drawn in it; what the canvas animates is script-driven and not specified.
- The three hero lines cycle by script. Only their CSS transitions (colour 0.5s, height 0.2s, detail opacity 0.3s) were measured, not the interval.
- Everything on home below the second showcase rendered blank in the capture (it loads on scroll), so those sections and their motion are not recorded.
- Sign up: a script-driven Web Animation (Motion) runs filter blur(0px) to blur(5px) on a div over 5100ms with a 110ms delay and a long linear() spring curve. The customer line under the card changes between screenshots; that this animation drives it is likely but not confirmed.
- The mega menu, dropdowns and accordions were seen open, but their open and close motion was not captured as it ran.
- Focus on the auth email field: no measured difference; screenshots show a soft grey double ring.
## Flow: Log in
Starts at `/login`. Canvas #fafafa, no card. 64px header with the logo mark at the left and a 32px secondary Sign Up button at the right (24px side padding, 16px at 390). One 320px column centred horizontally, its 32px title about 156px from the top of a 900px viewport. 40px controls; 16px between them. A 64px footer holds two 12px #a8a8a8 legal links, centred.
### 1. Choose a method or enter email
- Title naming the action ("Log in to <product>"), 32px/600, centred
- Email field, placeholder "Email Address"
- Dark primary button: continue with email, full column width
- 1px hairline divider, 16px above and below
- Five secondary provider buttons, each a brand icon left of the label: three OAuth providers, SAML SSO, passkey
- Ghost button: show other options
- 16px line: a question with a blue sign-up link
- Action: Continue with email submits the field in place; there is no separate email screen, the URL stays /login
- Action: Provider buttons leave for the provider (not followed)
- Action: Show other options reveals more methods (not recorded)
- Action: Sign-up link goes to /signup
- Validation: Empty submit: the browser's native bubble ("Please fill out this field.") under the field. Malformed address: the native bubble asking for an '@'. The page stays put and no custom inline error appears; the dark button reads #383838 while the pointer is still on it.
Not recorded: Everything after a valid email (code or magic link), the provider and SSO hand-offs, the 'other options' content, and a dialog the state crawler saw open on /login (it changed the address and was not captured as an image).
## Flow: Sign up
Starts at `/signup`. Canvas #fafafa. 64px header with the full wordmark at the left and a 32px Log In button (#fafafa fill, #ebebeb ring) at the right. A white card centred horizontally: 550px wide, 12px radius, border-small shadow, top at 136px, 600px tall at 1440 (358px wide with 16px margins, top 104px, at 390). Inside, a 390px column. Under the card, a single centred line pairing a customer logo with a 14px result that changes between visits.
### 1. Choose a method
- Title in two centred lines, 32px/600, -1.28px tracking
- Four secondary provider buttons, brand icon left of the label, 40px with 16px between
- Ghost button: show other options
- Blue 16px text link: continue with email, with a trailing arrow
- 13px #4d4d4d terms line at the bottom of the card with #171717 links
- Action: Continue with email swaps the card content to step 2 in place; the URL stays /signup
- Action: Provider buttons leave for the provider (not followed)
- Action: Log In in the header goes to /login
### 2. Enter email
- Same title
- Email field, focused on arrival (grey ring visible), placeholder is an example address
- Dark primary button: continue with email, full column width
- 1px hairline
- Blue text link with a leading arrow back to the other sign-up options
- Terms line
- Action: Enter or the button submits
- Action: The back link returns to step 1
- Validation: Same as log in: native browser bubbles only, for empty and malformed input; no custom inline error.
Not recorded: Email verification and everything after it (account details, team or plan choice, onboarding) sit behind an account.
## Libraries
Detected in the pages Vercel serves. Use these before reaching for an alternative.
| Name | npm | Purpose | Evidence |
| --- | --- | --- | --- |
| React | react | UI runtime | "react.transitional.element" in scripts on all five pages |
| Next.js | next | Framework for site, docs and auth | window.next defined on every page; "__next_f" and "next/dist/" in scripts |
| Tailwind CSS | tailwindcss | Styling | --tw-* custom properties on rendered elements and Tailwind v4 theme variables (--spacing, --text-*, --ease-*); data-slot attributes on rendered elements, the convention shadcn/ui uses (weak evidence for shadcn itself) |
| Radix UI | radix-ui | Accordion, navigation menu and other unstyled primitives | data-radix-collection-item, data-state and id^=radix- on rendered elements in docs; "data-radix-" in scripts on every page; --radix-accordion-content-height in keyframes |
| React Aria | react-aria-components | Press handling and accessible primitives | an element with id^=react-aria-pressable-style rendered on home, docs and log in; "react-aria-" in scripts |
| Base UI | @base-ui/react | Unstyled primitives | "data-base-ui-" in scripts on every page; no rendered attribute seen, so weaker than Radix and React Aria |
| Motion | motion | Script-driven animation | "framerAppearId" in scripts on home, pricing and auth; a running Web Animation with a linear() spring curve on sign up |
| cmdk | cmdk | Command menu behind the docs search | "[cmdk-" selector in a docs script; cmdkFadeIn, cmdkScaleIn and cmdkLoading keyframes on every page |
| tailwindcss-animate or tw-animate-css | (not on npm) | enter and exit animation utilities | keyframes named enter and exit built on --tw-enter-* and --tw-exit-* variables. A keyframe signature, not a package name |
| TanStack Query | @tanstack/react-query | Server state in docs | "No QueryClient set" in a docs script |
| Shiki | shiki | Code highlighting in docs | the bare string "shiki" in a docs script. Weak evidence |
| Prism | prismjs | Code highlighting | the bare string "prismjs" in scripts on every page. Weak evidence |
| Geist | geist | Sans and mono typefaces | loaded font faces "GeistSans 100 900" and "Geist Mono 100 900" |
Recommended for the parts that could not be identified:
| Name | npm | Purpose |
| --- | --- | --- |
| Lucide | lucide-react | 16px line icons; the platform's own icon set was not identified as a public package |
| Sonner | sonner | Toasts; no toast was observed or detected |