Coinbase
MIT
Clean, professional fintech design system with bright blue accents and minimal aesthetic, built for React/Next.js applications and financial platforms
Colour (47)
color.navbgtransparent
color.tabbgvar(--coinbase-bg-dark)
color.inputbgvar(--coinbase-bg-surface)
color.scrimcolorrgba(10, 11, 13, 0.5)
color.inputbordervar(--coinbase-border-default)
color.borderaccent1px solid var(--coinbase-accent)
color.btnprimarybgvar(--coinbase-accent)
color.coinbasetabbgrgb(40, 43, 49)
color.borderhairline1px solid var(--coinbase-border-default)
color.btnsecondarybgtransparent
color.coinbaseaccentrgb(0, 82, 255)
color.coinbasebgdarkrgb(40, 43, 49)
color.coinbasebgpagergb(238, 240, 243)
color.primitiveblackrgb(0, 0, 0)
color.primitivewhitergb(255, 255, 255)
color.brandprimaryctargb(0, 82, 255)
color.primitivegrey50rgb(238, 240, 243)
color.btnprimarybordervar(--coinbase-accent)
color.inputborderfocusvar(--coinbase-border-accent)
color.primitiveblue600rgb(0, 82, 255)
color.primitiveblue700rgb(1, 76, 236)
color.primitiveblue800rgb(0, 63, 196)
color.primitivedark800rgb(40, 43, 49)
color.primitivegrey100rgb(209, 209, 209)
color.primitivegrey400rgb(91, 97, 110)
color.primitivegrey900rgb(10, 11, 13)
color.btnprimarybghovervar(--coinbase-accent-hover)
color.coinbasebgsurfacergb(255, 255, 255)
color.btnprimarybgactivevar(--coinbase-accent-pressed)
color.coinbasebgelevatedvar(--primitive-white)
color.btnsecondarybghovervar(--color-bgSecondaryHovered)
color.coinbaseaccenthoverrgb(1, 76, 236)
color.coinbasetextprimaryrgb(10, 11, 13)
color.colorbgbrandhoveredrgb(1, 76, 236)
color.colorbgbrandpressedrgb(0, 63, 196)
color.coinbaseborderaccentrgb(0, 82, 255)
color.coinbasesurfacewhitergb(255, 255, 255)
color.coinbasetextonaccentrgb(255, 255, 255)
color.coinbaseaccentpressedrgb(0, 63, 196)
color.coinbaseborderdefaultrgb(209, 209, 209)
color.coinbasetextsecondaryrgb(91, 97, 110)
color.colorbgprimaryhoveredrgba(255, 255, 255, 0.8)
color.colorbgprimarypressedrgba(240, 241, 243, 1)
color.colorbgtertiaryhoveredrgba(40, 43, 49, 0.08)
color.colorbgtertiarypressedrgba(40, 43, 49, 0.14)
color.colorbgsecondaryhoveredrgba(238, 240, 243, 0.8)
color.colorbgsecondarypressedrgba(220, 222, 226, 0.9)
Spacing (23)
spacing.spacexs4px
spacing.coinbasespacexs4px
spacing.spacesm8px
spacing.coinbasespacesm8px
spacing.spacemd10px
spacing.coinbasespacemd10px
spacing.spacelg12px
spacing.coinbasespacelg12px
spacing.spacexl16px
spacing.coinbasespacexl16px
spacing.space2xl24px
spacing.coinbasespace2xl24px
spacing.space3xl32px
spacing.coinbasespace3xl32px
spacing.coinbasespace4xl48px
spacing.coinbasespace5xl64px
spacing.coinbasespace6xl96px
spacing.containersm540px
spacing.containermd720px
spacing.containerlg960px
spacing.containerxl1200px
spacing.container2xl1440px
spacing.containermax1600px
Radius (8)
radiussm2px
coinbaseradiussm2px
radiusmd4px
coinbaseradiusmd4px
radiuslg16px
coinbaseradiuslg16px
radiusfull40px
coinbaseradiusfull56px
# 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

Vercel
MITClean, minimal developer-focused design system built on Geist typography with light surfaces, precise spacing, and fast interactions for modern web applications
00
lightminimaldeveloper-toolsaas

Sentry
MITDark, minimal design system for developer tools with a sophisticated purple palette and refined typography, tailored for error monitoring and performance platforms
00
darkminimaldeveloper-toolsaas

OpenAI
MITClean, minimal design system for AI-native products built on Next.js and Tailwind, featuring a light monochromatic palette with precise token-based spacing and typography
02
lightminimalsaasdeveloper-tool