Coinbase
MIT
Clean, professional fintech design system with bright blue accents and minimal aesthetic, built for React/Next.js applications and financial platforms
Layout StudioImport this kit into a Studio project and start editing.
CLI installRun it in any project. No account needed.
npx @layoutdesign/context install coinbase# layout.md — Coinbase Design System
---
## 0. Quick Reference
**Stack:** React/Next.js · Tailwind + Bootstrap detected · Token source: reconstructed-from-computed (medium confidence, 6 CSS vars found, remainder synthesised from computed styles)
**How to apply:** Use as `var(--coinbase-accent)` in CSS, `style={{ color: 'var(--coinbase-accent)' }}` in JSX, or `bg-[var(--coinbase-accent)]` in Tailwind.
```css
:root {
/* Colour */
--coinbase-accent: rgb(0, 82, 255); /* Primary CTA background & brand blue */
--coinbase-bg-page: rgb(238, 240, 243); /* Page/surface background */
--coinbase-text-primary: rgb(10, 11, 13); /* Headings, primary text */
--coinbase-text-secondary: rgb(91, 97, 110); /* Subdued labels, captions */
--coinbase-text-on-accent: rgb(255, 255, 255); /* Text on blue CTA buttons */
--coinbase-surface-white: rgb(255, 255, 255); /* Cards, dropdowns, inputs */
--coinbase-tab-bg: rgb(40, 43, 49); /* Dark tab/pill background */
/* Hover/active states (semantic CDS tokens) */
--color-bgBrandHovered: var(--coinbase-accent-hover); /* Brand button hover */
--color-bgBrandPressed: var(--coinbase-accent-pressed); /* Brand button active */
/* Typography */
--cds-font-display: CoinbaseDisplay, var(--cds-font-fallback);
--cds-font-sans: CoinbaseSans, var(--cds-font-fallback);
--cds-font-text: CoinbaseText, var(--cds-font-fallback);
--cds-font-mono: CoinbaseMono, var(--cds-font-fallback);
--cds-font-fallback: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica", "Arial", sans-serif;
/* Spacing */
--coinbase-space-xs: 4px; --coinbase-space-sm: 8px;
--coinbase-space-md: 10px; --coinbase-space-lg: 12px;
--coinbase-space-xl: 16px; --coinbase-space-2xl: 24px;
--coinbase-space-3xl: 32px;
/* Radius */
--coinbase-radius-sm: 2px; --coinbase-radius-md: 4px;
--coinbase-radius-lg: 16px; --coinbase-radius-full: 56px; /* pill buttons */
/* Motion */
--coinbase-duration-fast: 0.2s; --coinbase-ease-default: ease;
}
```
```tsx
// Primary CTA Button — production-ready
<button
style={{
backgroundColor: 'var(--coinbase-accent)',
color: 'var(--coinbase-text-on-accent)',
fontFamily: 'var(--cds-font-sans)',
fontSize: '16px', fontWeight: 600, lineHeight: '18.4px',
padding: '16px 32px', borderRadius: 'var(--coinbase-radius-full)',
border: '1px solid var(--coinbase-accent)',
transition: `background-color var(--coinbase-duration-fast) var(--coinbase-ease-default)`,
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}
onMouseEnter={e => e.currentTarget.style.backgroundColor = 'var(--color-bgBrandHovered)'}
onMouseLeave={e => e.currentTarget.style.backgroundColor = 'var(--coinbase-accent)'}
>Get started</button>
```
**NEVER rules:**
1. **NEVER** use a font other than CoinbaseSans/CoinbaseDisplay/CoinbaseText/CoinbaseMono — no Inter, Roboto, or Arial as primary.
2. **NEVER** use a border-radius between 5px–15px for buttons — use `--coinbase-radius-full` (56px pill) for CTAs or `--coinbase-radius-lg` (16px) for containers.
3. **NEVER** hardcode `#0052FF` — always use `var(--coinbase-accent)`.
4. **NEVER** use spacing values not in the token scale — the closest on-grid value to 10px is `--coinbase-space-md`.
5. **NEVER** omit hover/active states on interactive elements — `--color-bgBrandHovered` / `--color-bgBrandPressed` are required.
6. **NEVER** use font-weight 700 or 800 for UI text — only 400 (`regular`) and 600 (`medium`) are used.
**Full design system → see layout.md**
---
## 1. Design Direction & Philosophy
### Character & Aesthetic Intent
Coinbase's visual language is **clean, institutional-grade fintech** — designed to project trust, transparency, and ease-of-access for both retail and institutional users. It is a product-forward design: the interface steps aside to let price data and primary CTAs lead.
**Mood:** Calm confidence. Precision without coldness. Accessible but authoritative.
**Dominant traits:**
- Heavy reliance on a single accent colour (`rgb(0, 82, 255)`) — used exclusively for primary action. Nothing else competes with it.
- A restrained near-black (`rgb(10, 11, 13)`) for all primary text — not pure black, subtly warmer.
- A cool light-grey page surface (`rgb(238, 240, 243)`) that reads as white but reduces eye strain for dashboard-heavy screens.
- Pill-shaped CTAs (56px border-radius) signal friendliness within an otherwise precise grid.
- Custom typeface family (CoinbaseSans, CoinbaseDisplay, etc.) as a proprietary brand signal — never substituted.
### What This Design Explicitly Rejects
- **No warm tones** in UI chrome — no orange, no amber, no gold (despite crypto associations).
- **No decorative border-radius mixing** — radii are always either near-zero (2–4px for micro elements), 16px for containers, or full-pill for buttons.
- **No heavy shadows or skeuomorphism** — elevation is achieved through background colour change, not drop shadows.
- **No font-weight extremes** — no 700/800 weight in UI; headline weight is 400 on Display face.
- **No arbitrary spacing** — every gap ties to the 4px-based token scale.
- **No multi-colour palettes** — single accent only. Secondary interactions use surface/background colour shifts (`bgSecondaryHovered`, etc.) not new hues.
---
## 2. Colour System
### Tier 1 — Primitive Values
```css
/* Primitive palette — raw values, not used directly in components */
:root {
--primitive-blue-600: rgb(0, 82, 255); /* Coinbase brand blue */
--primitive-blue-700: rgb(1, 76, 236); /* Blue darkened ~5% for hover — reconstructed: moderate confidence */
--primitive-blue-800: rgb(0, 63, 196); /* Blue darkened further for active — reconstructed: low confidence, inferred */
--primitive-grey-50: rgb(238, 240, 243); /* Page surface */
--primitive-grey-100: rgb(209, 209, 209); /* Input border */
--primitive-grey-400: rgb(91, 97, 110); /* Secondary text */
--primitive-grey-900: rgb(10, 11, 13); /* Primary text / near-black */
--primitive-dark-800: rgb(40, 43, 49); /* Dark tab/nav surface */
--primitive-white: rgb(255, 255, 255); /* Card/input background */
--primitive-black: rgb(0, 0, 0); /* Absolute black (forms only) */
}
```
### Tier 2 — Semantic Aliases
```css
/* Semantic tokens — intent over appearance. USE THESE in components. */
:root {
/* Backgrounds */
--coinbase-bg-page: var(--primitive-grey-50); /* Page/site background */
--coinbase-bg-surface: var(--primitive-white); /* Cards, panels, dropdowns */
--coinbase-bg-elevated: var(--primitive-white); /* Modals, overlays */
--coinbase-bg-dark: var(--primitive-dark-800); /* Dark nav tabs, toggle */
/* Brand / Action */
--coinbase-accent: var(--primitive-blue-600); /* Primary CTA bg & border */
--coinbase-accent-hover: var(--primitive-blue-700); /* CTA hover state — reconstructed: moderate confidence */
--coinbase-accent-pressed: var(--primitive-blue-800); /* CTA active/pressed state — reconstructed: low confidence */
/* CDS interactive state tokens (preserved from extraction) */
--color-bgBrandHovered: var(--coinbase-accent-hover);
--color-bgBrandPressed: var(--coinbase-accent-pressed);
--color-bgSecondaryHovered: rgba(238, 240, 243, 0.8); /* reconstructed: moderate confidence */
--color-bgSecondaryPressed: rgba(220, 222, 226, 0.9); /* reconstructed: moderate confidence */
--color-bgPrimaryHovered: rgba(255, 255, 255, 0.8); /* reconstructed: moderate confidence */
--color-bgPrimaryPressed: rgba(240, 241, 243, 1); /* reconstructed: moderate confidence */
--color-bgTertiaryHovered: rgba(40, 43, 49, 0.08); /* reconstructed: moderate confidence */
--color-bgTertiaryPressed: rgba(40, 43, 49, 0.14); /* reconstructed: moderate confidence */
/* Text */
--coinbase-text-primary: var(--primitive-grey-900); /* All headings, body */
--coinbase-text-secondary: var(--primitive-grey-400); /* Captions, labels, metadata */
--coinbase-text-on-accent: var(--primitive-white); /* Text on blue buttons */
--coinbase-text-on-dark: var(--primitive-grey-900); /* Text on dark tab surface */
/* Border */
--coinbase-border-default: var(--primitive-grey-100); /* Input, card outlines */
--coinbase-border-accent: var(--primitive-blue-600); /* Focused inputs, active tabs */
}
```
### Tier 3 — Component Tokens
```css
/* Component-scoped — consumed directly by component styles */
:root {
--btn-primary-bg: var(--coinbase-accent);
--btn-primary-bg-hover: var(--coinbase-accent-hover);
--btn-primary-bg-active: var(--coinbase-accent-pressed);
--btn-primary-text: var(--coinbase-text-on-accent);
--btn-primary-border: var(--coinbase-accent);
--btn-secondary-bg: transparent;
--btn-secondary-bg-hover: var(--color-bgSecondaryHovered);
--btn-secondary-text: var(--coinbase-text-primary);
--input-bg: var(--coinbase-bg-surface);
--input-border: var(--coinbase-border-default);
--input-border-focus: var(--coinbase-border-accent);
--tab-bg: var(--coinbase-bg-dark);
--tab-text: var(--coinbase-text-primary);
--nav-bg: transparent;
--nav-text: var(--coinbase-text-primary);
}
```
### Colour Usage Table
| Token | Value | Usage |
|---|---|---|
| `--coinbase-accent` | `rgb(0, 82, 255)` | Primary CTAs, active borders |
| `--coinbase-bg-page` | `rgb(238, 240, 243)` | Site background |
| `--coinbase-text-primary` | `rgb(10, 11, 13)` | Headings, body text |
| `--coinbase-text-secondary` | `rgb(91, 97, 110)` | Labels, metadata |
| `--coinbase-bg-dark` | `rgb(40, 43, 49)` | Dark pill tabs |
| `--coinbase-bg-surface` | `rgb(255, 255, 255)` | Cards, dropdowns |
---
## 3. Typography System
### Font Families (Preserved CSS Vars)
```css
:root {
--cds-font-fallback: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Helvetica", "Arial", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
--cds-font-display: CoinbaseDisplay, var(--cds-font-fallback); /* Hero, large display headlines — weight 400 only */
--cds-font-sans: CoinbaseSans, var(--cds-font-fallback); /* Body, UI text, labels, buttons — weight 400/600 */
--cds-font-text: CoinbaseText, var(--cds-font-fallback); /* Long-form editorial content — weight 400/600 */
--cds-font-mono: CoinbaseMono, var(--cds-font-fallback); /* Code, addresses, numeric data — weight 400/600 */
--cds-font-condensed: CoinbaseCondensed, var(--cds-font-fallback); /* Compact labels, badges — weight 400/600 */
/* Note: CoinbaseIcons is an icon font, not for text rendering */
}
```
### Composite Typography Tokens
**NEVER split these groups. Always apply as a complete set.**
```css
/* T-1: Hero Display — h1 only */
.type-hero {
font-family: var(--cds-font-display);
font-size: 80px;
font-weight: 400;
line-height: 80px; /* 1:1 tight leading */
letter-spacing: normal;
color: var(--coinbase-text-primary);
/* extracted: high confidence */
}
/* T-2: Section heading — h3-level content titles */
.type-heading-lg {
font-family: var(--cds-font-sans);
font-size: 20px;
font-weight: 600;
line-height: 28px;
letter-spacing: normal;
color: var(--coinbase-text-primary);
/* extracted: high confidence */
}
/* T-3: UI label / h2-as-label pattern — small semibold category label */
.type-label {
font-family: var(--cds-font-sans);
font-size: 16px;
font-weight: 600;
line-height: 24px;
letter-spacing: normal;
color: var(--coinbase-text-secondary);
/* extracted: high confidence — h2 computed to 16px/600 with grey colour */
}
/* T-4: Body / default paragraph */
.type-body {
font-family: var(--cds-font-sans);
font-size: 16px;
font-weight: 400;
line-height: 18.4px;
letter-spacing: normal;
color: var(--coinbase-text-primary);
/* extracted: high confidence */
}
/* T-5: Body large — feature descriptions */
.type-body-lg {
font-family: var(--cds-font-sans);
font-size: 18px;
font-weight: 400;
line-height: 24px; /* reconstructed: moderate confidence, extrapolated from scale */
letter-spacing: normal;
color: var(--coinbase-text-primary);
}
/* T-6: Data / price display */
.type-data {
font-family: var(--cds-font-sans);
font-size: 36px;
font-weight: 400;
line-height: 40px; /* reconstructed: moderate confidence */
letter-spacing: normal;
color: var(--coinbase-text-primary);
}
/* T-7: Section title (marketing spans) */
.type-section-title {
font-family: var(--cds-font-display);
font-size: 28px;
font-weight: 400;
line-height: 32px; /* reconstructed: moderate confidence */
letter-spacing: normal;
color: var(--coinbase-text-primary);
}
/* T-8: Caption / small text */
.type-caption {
font-family: var(--cds-font-sans);
font-size: 13px;
font-weight: 400;
line-height: 16.1px;
letter-spacing: normal;
color: var(--coinbase-text-secondary);
/* extracted: high confidence */
}
/* T-9: Nav / menu item */
.type-nav {
font-family: var(--cds-font-sans);
font-size: 14px;
font-weight: 400;
line-height: 16.1px;
letter-spacing: normal;
color: var(--coinbase-text-primary);
/* extracted: high confidence */
}
/* T-10: Button label */
.type-button {
font-family: var(--cds-font-sans);
font-size: 16px;
font-weight: 600;
line-height: 18.4px;
letter-spacing: normal;
/* extracted: high confidence */
}
/* T-11: Monospace / address */
.type-mono {
font-family: var(--cds-font-mono);
font-size: 14px;
font-weight: 400;
line-height: 18.4px;
letter-spacing: normal;
color: var(--coinbase-text-primary);
}
```
### Typographic Pairing Rules
- `CoinbaseDisplay` at 400 weight → **hero H1 only** (80px). Do not use it below 28px.
- `CoinbaseSans` at 600 → headings H2/H3, button labels, semibold UI labels.
- `CoinbaseSans` at 400 → all body, nav, and paragraph text.
- `CoinbaseText` → long editorial content pages (>3 paragraphs of prose).
- `CoinbaseMono` → price data, wallet addresses, code, numeric tickers.
- **H2 on this site functions as a category label** (16px/600/grey) — not a traditional section title. Treat it as `.type-label`.
### Weight Scale
| Token | Value | Use |
|---|---|---|
| `--coinbase-font-weight-regular` | 400 | Body, nav, display headlines |
| `--coinbase-font-weight-medium` | 600 | Buttons, H2/H3, semibold labels |
---
## 4. Spacing & Layout
### Base Unit & Scale
```css
:root {
/* Base unit: 4px. NOTE: --coinbase-space-md (10px) is off-grid — use with care */
--coinbase-space-xs: 4px; /* Micro gaps: icon-to-label, tight internal padding */
--coinbase-space-sm: 8px; /* Small gaps: nav item gaps, icon margins */
--coinbase-space-md: 10px; /* ⚠ Off-grid (10px). Preserved from extraction — button vertical pad on body element */
--coinbase-space-lg: 12px; /* Role-button vertical padding */
--coinbase-space-xl: 16px; /* Standard content padding, card inner padding */
--coinbase-space-2xl: 24px; /* Tab horizontal padding, section sub-gaps */
--coinbase-space-3xl: 32px; /* Button horizontal padding, section gaps */
/* Larger scales (reconstructed: moderate confidence, inferred from 8px base) */
--coinbase-space-4xl: 48px; /* Section vertical rhythm */
--coinbase-space-5xl: 64px; /* Major section separation */
--coinbase-space-6xl: 96px; /* Hero section padding */
}
```
### Grid & Container
```css
:root {
/* Container widths (reconstructed: moderate confidence from breakpoint census) */
--container-sm: 540px; /* ≤576px viewport */
--container-md: 720px; /* ≤768px viewport */
--container-lg: 960px; /* ≤1280px viewport */
--container-xl: 1200px; /* ≤1440px viewport */
--container-2xl: 1440px; /* ≤1600px viewport */
--container-max: 1600px; /* Maximum content width */
}
```
### Breakpoints
```css
/* Breakpoints extracted from media queries */
@custom-media --bp-xs (min-width: 400px); /* Small phone */
@custom-media --bp-sm (min-width: 576px); /* Phone landscape */
@custom-media --bp-md (min-width: 768px); /* Tablet */
@custom-media --bp-lg (min-width: 1280px); /* Desktop */
@custom-media --bp-xl (min-width: 1440px); /* Wide desktop */
@custom-media --bp-2xl (min-width: 1600px); /* Ultra-wide */
/* Tailwind-compatible aliases */
/* xs: 400px | sm: 576px | md: 768px | lg: 1280px | xl: 1440px | 2xl: 1600px */
```
### Flex vs Grid Decision Rules
- **Flex row** → nav, button groups, badge rows, inline icon+label pairs. Gap: `--coinbase-space-xs` (4px) in nav.
- **Flex column** → stacked content in mobile-first sections, card interiors.
- **CSS Grid** → feature card grids, pricing columns, asset/ticker tables (inferred from inventory).
- **Full-width** → hero sections, announcement banners — no container constraint.
- **Contained** → all body content sections use `--container-xl` centred with `auto` horizontal margins.
---
## 5. Page Structure & Layout Patterns
### 5.1 Section Map
| # | Section | Layout type | Key elements | Notes |
|---|---|---|---|---|
| 1 | Global Navigation / Header | `flex row`, sticky | Logo, nav items (gap: 4px), CTA buttons, language selector | Extracted from `role_navigation` computed styles |
| 2 | Announcement Banner | `flex row`, full-width, `bg: rgb(238,240,243)` | Text + dismiss/CTA | Extracted from `body` computed styles (padding: 10px 16px, flex center) |
| 3 | Hero Section | Full-width, `display:block` | H1 (80px Display), subhead, primary CTA button | Inferred from h1 computed styles |
| 4 | Asset/Price Ticker Strip | `flex row` or grid | Price data (36px CoinbaseSans), asset names | Inferred from `font-size-3xl` elements: "Bitcoin", "Ethereum", "Tether" |
| 5 | Feature Cards Grid | Grid, contained | H3 headings (20px/600), body text (18px), icon/image | Inferred from h3+body-lg computed styles |
| 6 | Learn / Education Row | Grid 3-col | H3 cards with "Mehr erfahren" CTAs | Inferred from component inventory + content patterns |
| 7 | Coinbase One / Product CTA | Full-width or 2-col | Promo text, pill CTA button | Inferred from `font-size-2xl` "Das nächste Kapitel" + button census |
| 8 | Tab/Product Switcher | `flex row`, pill tabs | Dark pill tabs (bg: rgb(40,43,49), radius: 56px), content panels | Extracted from `tab` computed styles |
| 9 | Footer | Grid multi-col | Nav links (14px), legal text (13px), language selector | Inferred from nav link font sizes |
*(Rows 3–9 are inferred — not visually confirmed from screenshots.)*
### 5.2 Layout Patterns
**Global Nav:**
```
display: flex; flex-direction: row; gap: 4px; padding: 0;
align-items: normal; /* extracted */
```
Full-width, no container constraint on the nav rail itself. Items left-aligned with logo, right-aligned CTAs.
**Announcement Banner (body-level):**
```
display: flex; flex-direction: row; justify-content: center; align-items: center;
padding: 10px 16px; background: rgb(238, 240, 243);
```
Full-width, centred content, light grey background distinguishing it from white cards below.
**Primary Button:**
```
display: flex; flex-direction: row; justify-content: center; align-items: center;
padding: 16px 32px; border-radius: 56px; /* pill */
```
**Tab Pill:**
```
display: inline-flex; justify-content: center; align-items: center;
padding: 0 24px; border-radius: 56px; background: rgb(40, 43, 49);
```
**Dropdown/Card:**
```
display: flex; border-radius: 16px; background: rgb(255, 255, 255);
```
**Feature Grid (inferred):** 3-column CSS grid at ≥1280px, 2-column at ≥768px, 1-column below. Gap: `--coinbase-space-2xl` (24px).
### 5.3 Visual Hierarchy
1. **H1 at 80px/400/CoinbaseDisplay** is unambiguously dominant — nothing else competes in scale.
2. **Primary CTA** (`rgb(0, 82, 255)`) is the only saturated colour on the page — it draws the eye immediately against the grey surface.
3. **Tabs** use a dark pill (`rgb(40, 43, 49)`) on a light surface — high contrast, secondary prominence.
4. **Price data** at 36px CoinbaseSans creates a third tier of visual weight for financial data.
5. **Section labels (H2 as category)** at 16px/600/grey (`rgb(91,97,110)`) are purposely subdued — they orient without competing.
6. Whitespace is generous — `--coinbase-space-5xl` (64px) between major sections, `--coinbase-space-3xl` (32px) within.
### 5.4 Content Patterns
**Pattern A — Icon + Title + Body + CTA (Feature Card):**
```
[Icon/Illustration]
[H3 — 20px/600 CoinbaseSans]
[Body — 18px/400 CoinbaseSans]
[Tertiary link CTA — "Mehr erfahren"]
```
**Pattern B — Pill Tab + Swappable Panel:**
```
[Pill tab group — dark bg, 56px radius]
[Active tab selected → content panel below changes]
[Panel contains: title + body + primary button]
```
**Pattern C — Data Row (Asset Ticker):**
```
[Asset name — 36px CoinbaseSans]
[Price — 36px CoinbaseMono]
[Change % badge]
[Sparkline]
```
**Pattern D — Marketing Section (2-col, inferred):**
```
Left: CoinbaseDisplay headline (28–80px) + body + primary CTA button (pill, blue)
Right: Product illustration or screenshot
```
---
## 6. Component Patterns
### 6.1 Primary Button
**Anatomy:** Container pill → Label text → (optional) leading icon
**Token mappings:**
| State | bg | text | border | cursor |
|---|---|---|---|---|
| default | `--coinbase-accent` | `--coinbase-text-on-accent` | `--coinbase-accent` | `pointer` |
| hover | `--color-bgBrandHovered` | `--coinbase-text-on-accent` | `--color-bgBrandHovered` | `pointer` |
| active | `--color-bgBrandPressed` | `--coinbase-text-on-accent` | `--color-bgBrandPressed` | `pointer` |
| focus | `--coinbase-accent` + 2px outline | `--coinbase-text-on-accent` | — | — |
| disabled | `rgba(0,82,255,0.4)` | `rgba(255,255,255,0.6)` | transparent | `not-allowed` |
| loading | `--coinbase-accent` (reduced opacity) | spinner visible | — | `wait` |
```tsx
import { ButtonHTMLAttributes, ReactNode } from 'react';
interface PrimaryButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children: ReactNode;
isLoading?: boolean;
}
export const PrimaryButton = ({ children, isLoading, disabled, ...props }: PrimaryButtonProps) => (
<button
{...props}
disabled={disabled || isLoading}
style={{
fontFamily: 'var(--cds-font-sans)',
fontSize: '16px',
fontWeight: 600,
lineHeight: '18.4px',
letterSpacing: 'normal',
color: 'var(--coinbase-text-on-accent)',
backgroundColor: 'var(--coinbase-accent)',
border: '1px solid var(--coinbase-accent)',
borderRadius: 'var(--coinbase-radius-full)',
padding: '16px 32px',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
gap: 'var(--coinbase-space-sm)',
cursor: disabled || isLoading ? 'not-allowed' : 'pointer',
opacity: disabled ? 0.4 : 1,
transition: `background-color var(--coinbase-duration-fast) var(--coinbase-ease-default),
border-color var(--coinbase-duration-fast) var(--coinbase-ease-default),
opacity var(--coinbase-duration-fast) var(--coinbase-ease-default)`,
outline: 'none',
textDecoration: 'none',
whiteSpace: 'nowrap',
}}
onMouseEnter={e => {
if (!disabled && !isLoading)
(e.currentTarget as HTMLButtonElement).style.backgroundColor = 'var(--color-bgBrandHovered)';
}}
onMouseLeave={e => {
(e.currentTarget as HTMLButtonElement).style.backgroundColor = 'var(--coinbase-accent)';
}}
onMouseDown={e => {
if (!disabled && !isLoading)
(e.currentTarget as HTMLButtonElement).style.backgroundColor = 'var(--color-bgBrandPressed)';
}}
onMouseUp={e => {
(e.currentTarget as HTMLButtonElement).style.backgroundColor = 'var(--color-bgBrandHovered)';
}}
onFocus={e => {
e.currentTarget.style.outlineOffset = '2px';
e.currentTarget.style.outline = '2px solid var(--coinbase-accent)';
}}
onBlur={e => { e.currentTarget.style.outline = 'none'; }}
>
{isLoading ? <span aria-label="Loading…" role="status">⟳</span> : children}
</button>
);
```
### 6.2 Secondary / Ghost Button
**Anatomy:** Pill container (transparent) → Label
| State | bg | text | border |
|---|---|---|---|
| default | transparent | `--coinbase-text-primary` | transparent |
| hover | `--color-bgSecondaryHovered` | `--coinbase-text-primary` | transparent |
| active | `--color-bgSecondaryPressed` | `--coinbase-text-primary` | transparent |
| focus | transparent + 2px outline | `--coinbase-text-primary` | — |
| disabled | transparent | `rgba(10,11,13,0.4)` | — |
```tsx
export const SecondaryButton = ({ children, disabled, ...props }: PrimaryButtonProps) => (
<button
{...props}
disabled={disabled}
className="btn-secondary"
style={{
fontFamily: 'var(--cds-font-sans)',
fontSize: '16px',
fontWeight: 600,
lineHeight: '18.4px',
color: disabled ? 'rgba(10,11,13,0.4)' : 'var(--coinbase-text-primary)',
backgroundColor: 'transparent',
border: 'none',
borderRadius: 'var(--coinbase-radius-full)',
padding: '16px 32px',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
cursor: disabled ? 'not-allowed' : 'pointer',
transition: `background-color var(--coinbase-duration-fast) var(--coinbase-ease-default)`,
outline: 'none',
}}
>
{children}
</button>
);
// Add CSS: .btn-secondary:hover { background-color: var(--color-bgSecondaryHovered); }
// .btn-secondary:active { background-color: var(--color-bgSecondaryPressed); }
// .btn-secondary:focus-visible { outline: 2px solid var(--coinbase-accent); outline-offset: 2px; }
```
### 6.3 Pill Tab
**Anatomy:** Tab container (dark bg, pill) → Label text
| State | bg | text | border |
|---|---|---|---|
| default | `--coinbase-bg-dark` (`rgb(40,43,49)`) | `--coinbase-text-primary` | `rgb(40,43,49)` |
| hover | `--color-bgTertiaryHovered` | `--coinbase-text-primary` | transparent |
| active/selected | `--coinbase-accent` | `--coinbase-text-on-accent` | `--coinbase-accent` |
| focus | + 2px accent outline | — | — |
| disabled | opacity 0.4 | — | — |
```tsx
interface TabProps {
label: string;
isSelected?: boolean;
disabled?: boolean;
onClick?: () => void;
}
export const PillTab = ({ label, isSelected, disabled, onClick }: TabProps) => (
<button
role="tab"
aria-selected={isSelected}
disabled={disabled}
onClick={onClick}
style={{
fontFamily: 'var(--cds-font-sans)',
fontSize: '16px',
fontWeight: 600,
lineHeight: '18.4px',
color: isSelected ? 'var(--coinbase-text-on-accent)' : 'var(--coinbase-text-primary)',
backgroundColor: isSelected ? 'var(--coinbase-accent)' : 'var(--coinbase-bg-dark)',
border: `1px solid ${isSelected ? 'var(--coinbase-accent)' : 'rgb(40,43,49)'}`,
borderRadius: 'var(--coinbase-radius-full)',
padding: '0 var(--coinbase-space-2xl)',
height: '40px',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
cursor: disabled ? 'not-allowed' : 'pointer',
opacity: disabled ? 0.4 : 1,
transition: `background-color var(--coinbase-duration-fast) var(--coinbase-ease-default)`,
outline: 'none',
whiteSpace: 'nowrap',
}}
>
{label}
</button>
);
```
### 6.4 Text Input
**Anatomy:** Pill input → Placeholder → (optional) trailing icon
| State | bg | border | text |
|---|---|---|---|
| default | `--coinbase-bg-surface` | `rgb(209,209,209)` | `rgb(0,0,0)` |
| hover | `--coinbase-bg-surface` | `rgb(160,160,160)` — reconstructed | `rgb(0,0,0)` |
| focus | `--coinbase-bg-surface` | `rgb(0,99,155)` 2px outline | `rgb(0,0,0)` |
| disabled | `rgba(255,255,255,0.5)` | `rgb(209,209,209)` | `rgba(0,0,0,0.4)` |
| error | `--coinbase-bg-surface` | `rgb(255,0,0)` — reconstructed | `rgb(0,0,0)` |
```tsx
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
hasError?: boolean;
}
export const TextInput = ({ hasError, disabled, ...props }: InputProps) => (
<input
{...props}
disabled={disabled}
style={{
fontFamily: 'var(--cds-font-sans)',
fontSize: '16px',
fontWeight: 400,
lineHeight: '18.4px',
color: disabled ? 'rgba(0,0,0,0.4)' : 'rgb(0,0,0)',
backgroundColor: 'var(--coinbase-bg-surface)',
border: `1px solid ${hasError ? 'rgb(200,40,40)' : 'rgb(209,209,209)'}`,
borderRadius: 'var(--coinbase-radius-full)', /* 50px pill extracted */
padding: '6px 35px 6px 15px',
display: 'block',
width: '100%',
outline: 'none',
opacity: disabled ? 0.5 : 1,
cursor: disabled ? 'not-allowed' : 'text',
transition: `border-color var(--coinbase-duration-fast) var(--coinbase-ease-default)`,
}}
onFocus={e => {
if (!disabled) {
e.currentTarget.style.outline = '2px solid rgb(0,99,155)';
e.currentTarget.style.outlineOffset = '-1px';
e.currentTarget.style.borderColor = 'transparent';
}
}}
onBlur={e => {
e.currentTarget.style.outline = 'none';
e.currentTarget.style.borderColor = hasError ? 'rgb(200,40,40)' : 'rgb(209,209,209)';
}}
/>
);
```
### 6.5 Nav Item
**Anatomy:** `<a>` or `<button>` → (optional) icon → Label → (optional) chevron
| State | bg | text | decoration |
|---|---|---|---|
| default | transparent | `--coinbase-text-primary` | none |
| hover | `--color-bgTertiaryHovered` | `--coinbase-text-primary` | none |
| active/current | `--color-bgTertiaryPressed` | `--coinbase-text-primary` | none |
| focus-visible | transparent + 2px outline | `--coinbase-text-primary` | — |
| disabled | transparent | `rgba(10,11,13,0.4)` | none |
```tsx
interface NavItemProps {
label: string;
href?: string;
isActive?: boolean;
disabled?: boolean;
}
export const NavItem = ({ label, href, isActive, disabled }: NavItemProps) => (
<a
href={disabled ? undefined : href}
aria-current={isActive ? 'page' : undefined}
aria-disabled={disabled}
className="nav-item"
style={{
fontFamily: 'var(--cds-font-sans)',
fontSize: '14px',
fontWeight: 400,
lineHeight: '16.1px',
color: disabled ? 'rgba(10,11,13,0.4)' : 'var(--coinbase-text-primary)',
backgroundColor: isActive ? 'var(--color-bgTertiaryPressed)' : 'transparent',
borderRadius: 'var(--coinbase-radius-full)',
padding: 'var(--coinbase-space-lg) var(--coinbase-space-2xl)', /* 12px 24px */
display: 'inline-flex',
alignItems: 'center',
gap: 'var(--coinbase-space-xs)', /* 4px */
textDecoration: 'none',
cursor: disabled ? 'not-allowed' : 'pointer',
transition: `background-color var(--coinbase-duration-fast) var(--coinbase-ease-default)`,
outline: 'none',
}}
>
{label}
</a>
// Add CSS:
// .nav-item:hover { background-color: var(--color-bgTertiaryHovered); }
// .nav-item:focus-visible { outline: 2px solid var(--coinbase-accent); outline-offset: 2px; }
);
```
### 6.6 Badge
**Anatomy:** Small pill → text/number
| State | bg | text | border |
|---|---|---|---|
| default | `--coinbase-bg-surface` | `--coinbase-text-primary` | `--coinbase-border-default` |
| new/active | `--coinbase-accent` | `--coinbase-text-on-accent` | none |
| disabled | `rgba(238,240,243,0.5)` | `rgba(10,11,13,0.4)` | none |
```tsx
interface BadgeProps {
label: string;
variant?: 'default' | 'active' | 'disabled';
}
export const Badge = ({ label, variant = 'default' }: BadgeProps) => {
const styles = {
default: { bg: 'var(--coinbase-bg-surface)', color: 'var(--coinbase-text-primary)', border: '1px solid rgb(209,209,209)' },
active: { bg: 'var(--coinbase-accent)', color: 'var(--coinbase-text-on-accent)', border: 'none' },
disabled:{ bg: 'rgba(238,240,243,0.5)', color: 'rgba(10,11,13,0.4)', border: 'none' },
}[variant];
return (
<span style={{
fontFamily: 'var(--cds-font-sans)',
fontSize: '13px',
fontWeight: 400,
lineHeight: '16.1px',
color: styles.color,
backgroundColor: styles.bg,
border: styles.border,
borderRadius: 'var(--coinbase-radius-lg)', /* 16px for badge containers */
padding: '2px var(--coinbase-space-sm)', /* 2px 8px */
display: 'inline-flex',
alignItems: 'center',
whiteSpace: 'nowrap',
}}>
{label}
</span>
);
};
```
---
## 7. Elevation & Depth
```css
:root {
/* Coinbase uses background-colour-based elevation, NOT drop shadows */
/* extracted: high confidence — boxShadow: "none" on all computed elements */
/* Elevation tiers — achieved via surface colour, not shadow */
--elevation-0: var(--coinbase-bg-page); /* Page base: rgb(238,240,243) */
--elevation-1: var(--coinbase-bg-surface); /* Cards, panels: rgb(255,255,255) */
--elevation-2: var(--coinbase-bg-surface); /* Dropdowns, tooltips: rgb(255,255,255) + border */
--elevation-modal: var(--coinbase-bg-surface); /* Modal overlays: rgb(255,255,255) */
/* Border tokens for elevation separation */
--border-hairline: 1px solid var(--coinbase-border-default); /* Card edges, input borders */
--border-accent: 1px solid var(--coinbase-accent); /* Focused states, active cards */
/* Overlay scrim (reconstructed: moderate confidence) */
--scrim-color: rgba(10, 11, 13, 0.5); /* Modal backdrop */
/* Z-index scale */
--z-base: 0;
--z-raised: 10; /* Sticky nav */
--z-dropdown: 100; /* Dropdowns, popovers */
--z-modal: 200; /* Modals */
--z-toast: 300; /* Toasts, notifications */
--z-top: 400; /* Critical overlays */
}
```
**Depth principle:** Coinbase separates layers via background colour (grey page → white card) rather than shadows. Adding a box-shadow to components is an anti-pattern here.
---
## 8. Motion
```css
:root {
/* Duration tokens */
--coinbase-duration-fast: 0.2s; /* Standard transitions: hover, focus, active — extracted: high confidence */
--coinbase-duration-medium: 0.3s; /* Panel/drawer open — reconstructed: moderate confidence */
--coinbase-duration-slow: 0.5s; /* Page transitions, hero entrances — reconstructed: low confidence */
/* Easing tokens */
--coinbase-ease-default: ease; /* All standard UI transitions — extracted: high confidence */
--coinbase-ease-in: ease-in; /* Elements leaving the screen — reconstructed */
--coinbase-ease-out: ease-out; /* Elements entering the screen — reconstructed */
/* Standard transition shorthand */
--transition-default:
background-color var(--coinbase-duration-fast) var(--coinbase-ease-default),
border-color var(--coinbase-duration-fast) var(--coinbase-ease-default),
color var(--coinbase-duration-fast) var(--coinbase-ease-default),
opacity var(--coinbase-duration-fast) var(--coinbase-ease-default);
}
/* Usage rules */
/* ✅ DO: transition background-color, border-color, color, opacity */
/* ✅ DO: 0.2s ease on all interactive component state changes */
/* ❌ NEVER: transition: all — creates performance cost and jank on transform-heavy elements */
/* ❌ NEVER: animate layout properties (width, height, padding) — use transform instead */
/* ❌ NEVER: motion on text content — only on container backgrounds and borders */
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
```
---
## 9. Anti-Patterns & Constraints
1. **NEVER hardcode hex/rgb colour values → AI defaults to nearest named colour or generic blue → Always use `var(--coinbase-accent)` for the brand blue, `var(--coinbase-text-primary)` for near-black text.** When you write `color: #0052FF` you bypass the token system entirely: dark mode support breaks, theme changes require global find-and-replace, and future colour tweaks miss the component.
2. **NEVER use Inter, Roboto, Arial, or system fonts as the primary typeface → AI defaults to `font-family: sans-serif` or `font-family: Inter` when no font is specified → Always specify `font-family: var(--cds-font-sans)` as the default, `var(--cds-font-display)` for hero headlines, `var(--cds-font-mono)` for numeric data.** Coinbase's custom typeface family is a core brand signal. Generic fallbacks are visually discordant and break brand recognition immediately.
3. **NEVER use a border-radius between 5px and 15px on interactive elements → AI applies a generic `rounded-md` (8px) to buttons → Use `--coinbase-radius-full` (56px) for buttons/tabs/pills, `--coinbase-radius-lg` (16px) for cards/dropdowns.** The 5–15px range exists nowhere in Coinbase's design system. An 8px button radius signals a different brand entirely.
4. **NEVER use font-weight 700 or 800 in UI components → AI over-bolds headers to create visual hierarchy → Use only 400 (regular) and 600 (semibold).** The CoinbaseDisplay headline at 80px is weight 400. Bold hierarchy is created by font-size and family choices, not weight extremes.
5. **NEVER use spacing values outside the token scale → AI invents values like 14px, 20px, 22px for "round-feeling" gaps → Map all spacing to the nearest `--coinbase-space-*` token.** `--coinbase-space-md` (10px) is the only off-grid token and is preserved specifically from extraction; do not add more off-grid values.
6. **NEVER apply `box-shadow` for elevation → AI adds `box-shadow: 0 4px 12px rgba(0,0,0,0.1)` to card components → Use background colour tiers (grey page → white card) for depth.** Every extracted element has `boxShadow: "none"`. Coinbase's depth language is surface colour contrast, not shadow.
7. **NEVER omit hover AND active states on any interactive element → AI generates default and hover states but skips active/pressed → Implement all four: default, hover, active, focus-visible.** The extraction revealed distinct `bgBrandHovered` AND `bgBrandPressed` tokens. Components without active states feel unresponsive on touch and desktop click-hold.
8. **NEVER construct Tailwind class names dynamically → AI writes `` `bg-[${color}]` `` or `text-${size}` → Use static class names or inline `var()` references.** Tailwind purges classes that aren't statically analysable. Dynamically constructed classes are stripped at build time and produce invisible styling at runtime.
9. **NEVER use `transition: all` → AI writes `transition: all 0.2s ease` as a shorthand convenience → Always list specific properties: `background-color, border-color, color, opacity`.** `transition: all` triggers layout recalculation on any style change (including transforms and clip-paths), causing GPU layer thrashing and perceptible jank at 60fps.
10. **NEVER use H2 as a traditional large section title → AI treats H2 as the second-largest heading (typically 24–32px, bold) → H2 on coinbase.com is a category label (16px/600/grey rgb(91,97,110)).** The computed style extraction clearly shows `h2: fontSize 16px, fontWeight 600, color rgb(91,97,110)`. Using H2 as a large visual heading breaks the semantic structure and the visual hierarchy.
11. **NEVER add `!important` to override component states → AI uses `!important` to force hover colour changes in utility-class contexts → Use CSS specificity correctly or inline `onMouseEnter`/`onMouseLeave` handlers.** `!important` breaks the cascade at exactly the places where state tokens need to override defaults — disabling the hover/active/focus system across all instances.
---
## Appendix A: Complete Token Reference
Every token extracted from the source. §0 CORE TOKENS is the primary AI signal; this appendix is reference material an AI can cross-check against when a curated role is missing.
```css
/* Colours (47) */
--brand-primary-cta: rgb(0, 82, 255); /* Primary CTA background, dominant on 4 buttons — e.g. "Registrieren" /* mined from computed styles */ */
--coinbase-accent: rgb(0, 82, 255);
--coinbase-bg-page: rgb(238, 240, 243);
--coinbase-text-primary: rgb(10, 11, 13);
--coinbase-text-secondary: rgb(91, 97, 110);
--coinbase-text-on-accent: rgb(255, 255, 255);
--coinbase-surface-white: rgb(255, 255, 255);
--coinbase-tab-bg: rgb(40, 43, 49);
--color-bgBrandHovered: rgb(1, 76, 236);
--color-bgBrandPressed: rgb(0, 63, 196);
--primitive-blue-600: rgb(0, 82, 255);
--primitive-blue-700: rgb(1, 76, 236);
--primitive-blue-800: rgb(0, 63, 196);
--primitive-grey-50: rgb(238, 240, 243);
--primitive-grey-100: rgb(209, 209, 209);
--primitive-grey-400: rgb(91, 97, 110);
--primitive-grey-900: rgb(10, 11, 13);
--primitive-dark-800: rgb(40, 43, 49);
--primitive-white: rgb(255, 255, 255);
--primitive-black: rgb(0, 0, 0);
--coinbase-bg-surface: rgb(255, 255, 255);
--coinbase-bg-elevated: var(--primitive-white);
--coinbase-bg-dark: rgb(40, 43, 49);
--color-bgSecondaryHovered: rgba(238, 240, 243, 0.8);
--color-bgSecondaryPressed: rgba(220, 222, 226, 0.9);
--color-bgPrimaryHovered: rgba(255, 255, 255, 0.8);
--color-bgPrimaryPressed: rgba(240, 241, 243, 1);
--color-bgTertiaryHovered: rgba(40, 43, 49, 0.08);
--color-bgTertiaryPressed: rgba(40, 43, 49, 0.14);
--coinbase-border-default: rgb(209, 209, 209);
--coinbase-border-accent: rgb(0, 82, 255);
--btn-primary-bg: var(--coinbase-accent);
--btn-primary-bg-hover: var(--coinbase-accent-hover);
--btn-primary-bg-active: var(--coinbase-accent-pressed);
--btn-primary-border: var(--coinbase-accent);
--btn-secondary-bg: transparent;
--btn-secondary-bg-hover: var(--color-bgSecondaryHovered);
--input-bg: var(--coinbase-bg-surface);
--input-border: var(--coinbase-border-default);
--input-border-focus: var(--coinbase-border-accent);
--tab-bg: var(--coinbase-bg-dark);
--nav-bg: transparent;
--border-hairline: 1px solid var(--coinbase-border-default);
--border-accent: 1px solid var(--coinbase-accent);
--scrim-color: rgba(10, 11, 13, 0.5);
--coinbase-accent-hover: rgb(1, 76, 236);
--coinbase-accent-pressed: rgb(0, 63, 196);
/* Typography (36) */
--cds-font-fallback: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica", "Arial", sans-serif, …;
--cds-font-display: CoinbaseDisplay, var(--cds-font-fallback);
--cds-font-sans: CoinbaseSans, var(--cds-font-fallback);
--cds-font-text: CoinbaseText, var(--cds-font-fallback);
--cds-font-mono: CoinbaseMono, var(--cds-font-fallback);
--cds-font-condensed: CoinbaseCondensed, var(--cds-font-fallback);
--font-size-xs: 13px; /* 5 elements — e.g. p "Für bestimmte Krypto", span "Direkt zu den Inhalt", span "Weiter zum Seitenind" /* mined from computed styles */ */
--font-size-sm: 14px; /* 32 elements — e.g. a "KryptoKryptowährun", a "DerivateNeuVerstär", a "AdvancedProfession" /* mined from computed styles */ */
--font-size-md: 16px; /* 170 elements — e.g. h2 "Sprache und Region", p "System-Update 2025Da", p "Commerce-Zahlungspro" /* mined from computed styles */ */
--font-size-lg: 18px; /* 4 elements — e.g. p "Kaufen, verkaufen un", p "Mit Staking auf Coin", span "Mehr erfahren" /* mined from computed styles */ */
--font-size-xl: 20px; /* 6 elements — e.g. h3 "Mehr Kryptos entdeck", h3 "Die Grundlagen verst", h3 "Konto- und Datenschu" /* mined from computed styles */ */
--font-size-2xl: 28px; /* 4 elements — e.g. span "System-Update 2025", span "Das nächste Kapitel ", span "Commerce-Zahlungspro" /* mined from computed styles */ */
--font-size-3xl: 36px; /* 6 elements — e.g. p "Bitcoin", p "Ethereum", p "Tether" /* mined from computed styles */ */
--font-weight-regular: 400; /* 188 elements — e.g. h1 "Einfach und sicher K", h2 "Bis zu 14 % Rewards ", h2 "Entdecken Sie Krypto" /* mined from computed styles */ */
--font-weight-medium: 600; /* 45 elements — e.g. h2 "Sprache und Region", h3 "Mehr Kryptos entdeck", h3 "Die Grundlagen verst" /* mined from computed styles */ */
--line-height-tight: 16.1px; /* 32 elements — e.g. a "KryptoKryptowährun", a "DerivateNeuVerstär", a "AdvancedProfession" /* mined from computed styles */ */
--line-height-normal: 18.4px; /* 79 elements — e.g. p "System-Update 2025Da", p "Commerce-Zahlungspro", p "Unsere KundenWir gen" /* mined from computed styles */ */
--line-height-loose: 24px; /* 71 elements — e.g. h2 "Sprache und Region", p "Einfach und sicher H", p "COINBASE ONE" /* mined from computed styles */ */
--coinbase-text-on-dark: var(--primitive-grey-900);
--btn-primary-text: var(--coinbase-text-on-accent);
--btn-secondary-text: var(--coinbase-text-primary);
--tab-text: var(--coinbase-text-primary);
--nav-text: var(--coinbase-text-primary);
--coinbase-font-weight-regular: 400;
--coinbase-font-weight-medium: 600;
--coinbase-font-size-xs: 13px;
--coinbase-font-size-sm: 14px;
--coinbase-font-size-md: 16px;
--coinbase-font-size-lg: 18px;
--coinbase-font-size-xl: 20px;
--coinbase-font-size-2xl: 28px;
--coinbase-font-size-3xl: 36px;
--coinbase-font-size-hero: 80px;
--coinbase-line-height-tight: 16.1px;
--coinbase-line-height-normal: 18.4px;
--coinbase-line-height-loose: 24px;
/* Spacing (23) */
--space-xs: 4px; /* 6 elements — e.g. nav .MainNav__LinksWrapper-sc-483e0f05-2, nav .MainNav__LinksWrapper-sc-483e0f05-2, nav .MainNav__LinksWrapper-sc-483e0f05-2 /* mined from computed styles */ */
--space-sm: 8px; /* 84 elements — e.g. div ., div ., div . /* mined from computed styles */ */
--space-md: 10px; /* 48 elements — e.g. div ., div ., div . /* mined from computed styles */ */
--space-lg: 12px; /* 12 elements — e.g. div ., div ., div . /* mined from computed styles */ */
--space-xl: 16px; /* 178 elements — e.g. div ., div ., div . /* mined from computed styles */ */
--space-2xl: 24px; /* 8 elements — e.g. div ., div ., div . /* mined from computed styles */ */
--space-3xl: 32px; /* 36 elements — e.g. div ., div ., div . /* mined from computed styles */ */
--coinbase-space-xs: 4px;
--coinbase-space-sm: 8px;
--coinbase-space-md: 10px;
--coinbase-space-lg: 12px;
--coinbase-space-xl: 16px;
--coinbase-space-2xl: 24px;
--coinbase-space-3xl: 32px;
--coinbase-space-4xl: 48px;
--coinbase-space-5xl: 64px;
--coinbase-space-6xl: 96px;
--container-sm: 540px;
--container-md: 720px;
--container-lg: 960px;
--container-xl: 1200px;
--container-2xl: 1440px;
--container-max: 1600px;
/* Radius (8) */
--radius-sm: 2px; /* 1 element — e.g. button .ot-link-btn "Back Button" /* mined from computed styles */ */
--radius-md: 4px; /* 2 elements — e.g. button .onetrust-close-btn-handler, button .onetrust-close-btn-handler /* mined from computed styles */ */
--radius-lg: 16px; /* 46 elements — e.g. button . "EspañolUnited States", button . "EnglishUnited States", button . "DeutschGermany" /* mined from computed styles */ */
--radius-full: 40px; /* 1 element — e.g. button .save-preference-btn-handler "Meine Auswahl bestät" /* mined from computed styles */ */
--coinbase-radius-sm: 2px;
--coinbase-radius-md: 4px;
--coinbase-radius-lg: 16px;
--coinbase-radius-full: 56px;
/* Motion (2) */
--duration-fast: 0.2s; /* 26 elements — e.g. a, a, a /* mined from computed styles */ */
--ease-default: ease; /* 166 elements — e.g. button, button, button /* mined from computed styles */ */
```
## Appendix B: Token Source Metadata
```
tokenSource: reconstructed-from-computed
confidence: medium
cssVarsFound: 6 (--cds-font-display, --cds-font-sans, --cds-font-text,
--cds-font-mono, --cds-font-condensed, --cds-font-fallback)
syntheticTokenCount: 23 tokens synthesised from computed styles
figmaSource: none
```
**Clustering method:**
- **Colours:** Clustered by computed RGB values. Identified 3 hue families: blue (0,82,255), near-black (10,11,13), cool-grey (91,97,110 / 238,240,243). Single accent pattern confirmed by button census (4 blue CTAs). Interactive state hover/active values (`--color-bgBrandHovered` etc.) preserved from CSS rule extraction verbatim.
- **Spacing:** 4px base grid confirmed (4, 8, 12, 16, 24, 32 all present). 10px is a documented off-grid outlier preserved from the body/announcement element.
- **Border-radius:** Census of 46+ elements at 16px confirms `--coinbase-radius-lg: 16px` as the dominant container radius. Pill shape confirmed from `button_primary: 56px`, `role_button: 100000px`, `input: 50px` — all aliased to `--coinbase-radius-full: 56px`. Values from OneTrust cookie banner (2px, 4px, 40px) treated as third-party UI, not Coinbase design system.
- **Typography:** Font families extracted directly from `@font-face` declarations and `--cds-font-*` CSS vars — high confidence. Size scale derived from element census (5–170 elements per size); line-height ratios validated against extracted 80px/80px and 20px/28px confirmed pairs.
- **Motion:** `transition: all` with `0.2s ease` found on 166+ buttons/links — duration and easing extracted at high confidence. Additional durations (0.3s, 0.5s) are reconstructed.
**Caveats:**
- Interactive state colour values (`--color-bgBrandHovered`, `--color-bgBrandPressed`, etc.) are referenced in extracted CSS rules but their resolved RGB values were not computed. Approximate values are reconstructed by darkening `--coinbase-accent` by ~5–20%.
- Some OneTrust cookie consent banner styles are included in the interactive state extraction — these do NOT represent Coinbase's design system and are excluded from component tokens.
- No screenshots were provided. Section 5 (Page Structure) is inferred from computed styles, component inventory, and typography hierarchy. All inferred sections are marked.More from the gallery
Browse all kits →You may also like

Contra
MITPlayful yet professional design system with teal and purple accents, bold typography, and vibrant accent surfaces—built for modern SaaS platforms and landing pages
03
lightboldsaaslanding-page

DoorDash
MITClean, accessible food-delivery system with DoorDash's signature red accent, light neutral palette, and system-font typography—built for rapid product development
03
lightecommsaasmobile

Mercedes-Benz
MITLuxe, minimalist design system with sharp black-and-white contrast and serif typography, crafted for premium automotive and lifestyle brands
05
darkminimalboldecomm