mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
feat(design-systems): add tokens.css + components.html for 10 devtool / fintech / docs brands (#2029)
Brands added (each with full 56-token :root + self-contained fixture): - Devtools / data infra: clickhouse, hashicorp, mongodb, mintlify, sentry-adjacent (lovable, superhuman) - AI-app builder / messaging: intercom, lovable, superhuman - Fintech / crypto: coinbase, binance, wise All 10 declare the complete shared schema (26 A1 + 26 A2 + 4 B-slot) with no C-extensions; pnpm guard reports all 6 contract checks passing. Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
08d6bc73ac
commit
b603a4ec54
20 changed files with 7218 additions and 0 deletions
550
design-systems/binance/components.html
Normal file
550
design-systems/binance/components.html
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Binance — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/binance. White trading-floor canvas
|
||||
alternating with deep #222126 panels, Binance Yellow (#F0B90B) as the singular
|
||||
accent, BinancePlex headlines, pill CTAs, and whisper-light 5%-opacity shadows."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--surface: #ffffff;
|
||||
--surface-warm: #f5f5f5;
|
||||
|
||||
--fg: #1e2026;
|
||||
--fg-2: #32313a;
|
||||
--muted: #848e9c;
|
||||
--meta: #777e90;
|
||||
|
||||
--border: #e6e8ea;
|
||||
--border-soft: #f0f1f2;
|
||||
|
||||
--accent: #f0b90b;
|
||||
--accent-on: #1e2026;
|
||||
--accent-hover: #1eaedb;
|
||||
--accent-active: #d0980b;
|
||||
|
||||
--success: #0ecb81;
|
||||
--warn: #eab308;
|
||||
--danger: #f6465d;
|
||||
|
||||
--font-display: BinancePlex, Arial, sans-serif;
|
||||
--font-body: BinancePlex, Arial, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 11px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 20px;
|
||||
--text-xl: 24px;
|
||||
--text-2xl: 28px;
|
||||
--text-3xl: 34px;
|
||||
--text-4xl: 60px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0;
|
||||
--tracking-display: 0;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 48px;
|
||||
--section-y-phone: 32px;
|
||||
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 12px;
|
||||
--radius-lg: 24px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 3px 5px 0 rgba(32, 32, 37, 0.05);
|
||||
|
||||
--focus-ring: 0 0 0 2px #1eaedb;
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 32px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 16px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-feature-settings: "tnum" 1;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* Dark section variant — DESIGN.md §1 alternating light/dark rhythm. */
|
||||
.section-dark {
|
||||
background: #222126;
|
||||
color: #ffffff;
|
||||
}
|
||||
.section-dark .body-muted,
|
||||
.section-dark .eyebrow,
|
||||
.section-dark .lead { color: rgba(255, 255, 255, 0.7); }
|
||||
|
||||
/* ─── Typography — BinancePlex, weights 500–700 only ────── */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
margin: 0;
|
||||
}
|
||||
h1 { font-size: var(--text-4xl); font-weight: 700; }
|
||||
h2 { font-size: var(--text-3xl); font-weight: 700; }
|
||||
h3 { font-size: var(--text-lg); font-weight: 600; line-height: 1.25; }
|
||||
p { margin: 0; }
|
||||
.eyebrow {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 600;
|
||||
}
|
||||
.lead { font-size: var(--text-lg); color: var(--muted); font-weight: 500; line-height: var(--leading-body); }
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); font-weight: 500; }
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-5 > * + * { margin-block-start: var(--space-5); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — DESIGN.md §4 ────────────────────────────── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
padding: 12px 28px;
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
letter-spacing: 0.01em;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
transition: background-color var(--motion-base) var(--ease-standard),
|
||||
color var(--motion-base) var(--ease-standard),
|
||||
border-color var(--motion-base) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
/* Primary pill CTA — Binance Yellow, full-round (signature shape) */
|
||||
.btn-primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
border-radius: var(--radius-pill);
|
||||
box-shadow: rgb(153, 153, 153) 0 2px 10px -3px;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-hover);
|
||||
color: #ffffff;
|
||||
}
|
||||
.btn-primary:active { background: var(--accent-active); color: var(--accent-on); }
|
||||
/* Secondary pill — white with yellow outline */
|
||||
.btn-secondary {
|
||||
background: #ffffff;
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: var(--accent-hover);
|
||||
color: #ffffff;
|
||||
border-color: var(--accent-hover);
|
||||
}
|
||||
/* Ghost — for dark sections */
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: #ffffff;
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
.btn-ghost:hover { background: rgba(255, 255, 255, 0.08); border-color: #ffffff; }
|
||||
|
||||
/* ─── Inputs ────────────────────────────────────────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label { font-size: var(--text-sm); font-weight: 600; color: var(--fg); }
|
||||
.field input {
|
||||
padding: 14px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface-warm);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
outline: none;
|
||||
transition: border-color var(--motion-base) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input:focus-visible {
|
||||
border-color: #000000;
|
||||
box-shadow: var(--focus-ring);
|
||||
background: #ffffff;
|
||||
}
|
||||
.field input::placeholder { color: var(--muted); font-weight: 500; }
|
||||
.field-help { font-size: var(--text-xs); color: var(--meta); font-weight: 500; }
|
||||
|
||||
/* ─── Cards ─────────────────────────────────────────────── */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
box-shadow: var(--elev-raised);
|
||||
transition: box-shadow var(--motion-base) var(--ease-standard);
|
||||
}
|
||||
.card:hover { box-shadow: 0 3px 5px 5px rgba(8, 8, 8, 0.05); }
|
||||
.card-icon {
|
||||
width: 48px; height: 48px;
|
||||
border-radius: var(--radius-pill);
|
||||
background: color-mix(in oklab, var(--accent), white 78%);
|
||||
color: var(--accent-active);
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.card .card-meta {
|
||||
margin-block-start: auto;
|
||||
padding-block-start: var(--space-4);
|
||||
border-block-start: 1px solid var(--border-soft);
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
|
||||
/* ─── Price ticker — the "numbers build trust" surface ──── */
|
||||
.ticker {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1px;
|
||||
background: var(--border);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
@media (max-width: 639px) { .ticker { grid-template-columns: repeat(2, 1fr); } }
|
||||
.ticker-cell {
|
||||
background: var(--surface);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.ticker-symbol { font-size: var(--text-xs); font-weight: 600; color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase; }
|
||||
.ticker-price { font-size: var(--text-lg); font-weight: 600; color: var(--fg); }
|
||||
.ticker-change { font-size: var(--text-sm); font-weight: 600; }
|
||||
.ticker-change.up { color: var(--success); }
|
||||
.ticker-change.down { color: var(--danger); }
|
||||
|
||||
/* ─── Badges ────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex; align-items: center; gap: var(--space-2);
|
||||
padding: 3px 10px;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: var(--text-xs); font-weight: 600; line-height: 1.6;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.badge-success { color: var(--success); background: color-mix(in oklab, var(--success), transparent 88%); }
|
||||
.badge-danger { color: var(--danger); background: color-mix(in oklab, var(--danger), transparent 88%); }
|
||||
.badge-accent { color: var(--accent-active); background: color-mix(in oklab, var(--accent), white 82%); }
|
||||
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
/* ─── Links ─────────────────────────────────────────────── */
|
||||
a { color: var(--accent); text-decoration: none; font-weight: 600; transition: color var(--motion-fast) var(--ease-standard); }
|
||||
a:hover { color: #1a1a1a; }
|
||||
.section-dark a:hover { color: var(--accent); }
|
||||
kbd {
|
||||
font-family: var(--font-mono); font-size: var(--text-xs);
|
||||
padding: 2px 6px; border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border); background: var(--surface-warm); color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Layout helpers ────────────────────────────────────── */
|
||||
.hero-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--space-12); align-items: center; }
|
||||
@media (max-width: 1023px) { .hero-grid { grid-template-columns: 1fr; gap: var(--space-8); } }
|
||||
.hero-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-6); flex-wrap: wrap; }
|
||||
.hero-art {
|
||||
aspect-ratio: 4 / 3;
|
||||
border-radius: var(--radius-lg);
|
||||
background:
|
||||
radial-gradient(circle at 50% 45%, #f0b90b 0%, #fcd535 38%, #f8d12f 72%, rgba(248, 209, 47, 0) 100%),
|
||||
#ffffff;
|
||||
display: grid; place-items: center;
|
||||
box-shadow: var(--elev-raised);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.hero-art-device {
|
||||
width: 58%;
|
||||
aspect-ratio: 9 / 16;
|
||||
background: #222126;
|
||||
border-radius: 28px;
|
||||
border: 6px solid #1a1a1a;
|
||||
padding: var(--space-4);
|
||||
display: flex; flex-direction: column; gap: var(--space-3);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 24px 40px -16px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
.hero-art-row { display: flex; justify-content: space-between; align-items: baseline; font-variant-numeric: tabular-nums; }
|
||||
.hero-art-row .sym { font-size: 11px; font-weight: 600; color: rgba(255, 255, 255, 0.7); letter-spacing: 0.06em; }
|
||||
.hero-art-row .pr { font-size: 13px; font-weight: 600; }
|
||||
|
||||
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-6); }
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
|
||||
.form-row { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--space-12); align-items: start; }
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form {
|
||||
display: flex; flex-direction: column; gap: var(--space-4);
|
||||
max-width: 460px;
|
||||
padding: var(--space-6);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); flex-wrap: wrap; }
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
|
||||
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-6); }
|
||||
@media (max-width: 639px) { .stat-grid { grid-template-columns: 1fr; } }
|
||||
.stat-num { font-size: var(--text-3xl); font-weight: 700; line-height: var(--leading-tight); color: var(--accent); font-variant-numeric: tabular-nums; }
|
||||
.stat-label { font-size: var(--text-sm); font-weight: 500; color: rgba(255, 255, 255, 0.7); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-5">
|
||||
<p class="eyebrow">Reference fixture · binance</p>
|
||||
<h1>The world's leading cryptocurrency exchange.</h1>
|
||||
<p class="lead" style="max-width: 56ch">
|
||||
Trade 350+ coins on the platform millions trust for low fees, deep liquidity,
|
||||
and a security record built for the long term. Buy, sell, and stake in seconds.
|
||||
</p>
|
||||
<div class="ticker" aria-label="Live crypto prices">
|
||||
<div class="ticker-cell">
|
||||
<span class="ticker-symbol">BTC / USD</span>
|
||||
<span class="ticker-price">$68,432.10</span>
|
||||
<span class="ticker-change up">+2.41%</span>
|
||||
</div>
|
||||
<div class="ticker-cell">
|
||||
<span class="ticker-symbol">ETH / USD</span>
|
||||
<span class="ticker-price">$3,584.20</span>
|
||||
<span class="ticker-change up">+1.18%</span>
|
||||
</div>
|
||||
<div class="ticker-cell">
|
||||
<span class="ticker-symbol">BNB / USD</span>
|
||||
<span class="ticker-price">$612.55</span>
|
||||
<span class="ticker-change down">−0.73%</span>
|
||||
</div>
|
||||
<div class="ticker-cell">
|
||||
<span class="ticker-symbol">SOL / USD</span>
|
||||
<span class="ticker-price">$148.07</span>
|
||||
<span class="ticker-change up">+4.92%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Get started
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-secondary">View markets</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-art" aria-hidden="true">
|
||||
<div class="hero-art-device">
|
||||
<div class="hero-art-row" style="margin-block-end: 4px">
|
||||
<span class="sym" style="color: var(--accent); letter-spacing: 0.08em">PORTFOLIO</span>
|
||||
<span class="pr" style="color: var(--success)">+8.42%</span>
|
||||
</div>
|
||||
<div class="hero-art-row"><span class="sym">BTC</span><span class="pr">$68,432.10</span></div>
|
||||
<div class="hero-art-row"><span class="sym">ETH</span><span class="pr">$3,584.20</span></div>
|
||||
<div class="hero-art-row"><span class="sym">BNB</span><span class="pr">$612.55</span></div>
|
||||
<div class="hero-art-row"><span class="sym">SOL</span><span class="pr">$148.07</span></div>
|
||||
<div class="hero-art-row"><span class="sym">USDT</span><span class="pr">$1.00</span></div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">Built for traders</p>
|
||||
<h2 style="max-width: 24ch">Operational clarity, every screen.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card">
|
||||
<span class="card-icon" aria-hidden="true">
|
||||
<svg class="icon" width="22" height="22" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2l3 7h7l-5.5 4.5L18 21l-6-4-6 4 1.5-7.5L2 9h7z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Industry-low fees</h3>
|
||||
<p class="body-muted body-sm">
|
||||
0.10% spot trading fee — discounted further when paying in BNB.
|
||||
Tabular numerics keep price columns aligned across portfolios.
|
||||
</p>
|
||||
<div class="card-meta">
|
||||
<span class="badge badge-accent">Spot · 0.10%</span>
|
||||
<a href="./tokens.css" class="body-sm">Fees →</a>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<span class="card-icon" aria-hidden="true">
|
||||
<svg class="icon" width="22" height="22" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2l8 4v6c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6z"/>
|
||||
<path d="M9 12l2 2 4-4"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Security & SAFU</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Cold-storage majority, real-time risk monitoring, and the SAFU fund —
|
||||
an insurance reserve protecting user assets since 2018.
|
||||
</p>
|
||||
<div class="card-meta">
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Operational
|
||||
</span>
|
||||
<a href="./DESIGN.md" class="body-sm">Trust →</a>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<span class="card-icon" aria-hidden="true">
|
||||
<svg class="icon" width="22" height="22" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 17l6-6 4 4 8-9"/>
|
||||
<path d="M14 6h7v7"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Deep liquidity</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Execute size on 350+ markets with the order-book depth of the world's
|
||||
busiest exchange. Sub-millisecond matching engine across global regions.
|
||||
</p>
|
||||
<div class="card-meta">
|
||||
<span class="badge badge-danger">24h vol −1.2%</span>
|
||||
<a href="./tokens.css" class="body-sm">Markets →</a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="trust" class="section-dark" style="margin-inline: calc(var(--container-gutter-desktop) * -1); padding-inline: var(--container-gutter-desktop);">
|
||||
<div class="stack-6">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">Trusted by millions</p>
|
||||
<h2 style="color: #ffffff; max-width: 22ch">A platform engineered to scale.</h2>
|
||||
</div>
|
||||
<div class="stat-grid">
|
||||
<div>
|
||||
<p class="stat-num">$76B+</p>
|
||||
<p class="stat-label">24h trading volume across spot and derivatives</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="stat-num">180M+</p>
|
||||
<p class="stat-label">Registered users in 180+ countries worldwide</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="stat-num">350+</p>
|
||||
<p class="stat-label">Cryptocurrencies and trading pairs available today</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="./tokens.css" class="btn btn-ghost">
|
||||
Read the security report
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Open an account</p>
|
||||
<h2 style="max-width: 18ch">Start trading in minutes.</h2>
|
||||
<p class="body-muted" style="max-width: 50ch">
|
||||
KYC verification is fast and runs entirely in-app. Sign up with email,
|
||||
verify your identity, fund your account, and place your first trade.
|
||||
Press <kbd>⌘</kbd> <kbd>K</kbd> anytime to search markets.
|
||||
</p>
|
||||
<p class="body-sm">
|
||||
Already have an account?
|
||||
<a href="./DESIGN.md">Log in →</a>
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Email address</label>
|
||||
<input id="email" type="email" placeholder="you@example.com" autocomplete="email" required />
|
||||
<p class="field-help">We'll send a verification code — no marketing.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="referral">Referral ID <span style="color: var(--meta); font-weight: 500">(optional)</span></label>
|
||||
<input id="referral" type="text" placeholder="e.g. 35480123" autocomplete="off" />
|
||||
<p class="field-help">Get up to 20% trading-fee kickback on your first trades.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Create account</button>
|
||||
<button type="button" class="btn btn-secondary">Continue with passkey</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
255
design-systems/binance/tokens.css
Normal file
255
design-systems/binance/tokens.css
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/binance/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by Binance.US"
|
||||
* — the polished urgency of a crypto trading floor: white surfaces and
|
||||
* deep near-black `#222126` panels alternating in rhythm, Binance Yellow
|
||||
* `#F0B90B` cutting through the monochrome as the single brand signal,
|
||||
* BinancePlex headlines that carry proprietary gravitas, pill-shaped CTAs
|
||||
* (50px+ radius) demanding attention, and whisper-light 5%-opacity card
|
||||
* shadows that ground floating surfaces without ever feeling decorative.
|
||||
*
|
||||
* This file pre-compiles the values described in `DESIGN.md` into the
|
||||
* shared schema. Agents generating a Binance-flavored artifact should
|
||||
* paste the `:root { … }` block verbatim into the first `<style>` of
|
||||
* the artifact, then reference every value through `var(--name)`.
|
||||
*
|
||||
* Brand-specific schema decisions (each one bends a schema convention
|
||||
* to match Binance's voice rather than the cross-brand default):
|
||||
*
|
||||
* 1. `--accent` is Binance Yellow (`#F0B90B`) — the singular point
|
||||
* of brand color. DESIGN.md §7 is unambiguous: "Don't introduce
|
||||
* additional brand colors — Binance Yellow is the only accent;
|
||||
* all other color is data-driven (green up, red down)". The
|
||||
* yellow lives inside a system of cold neutrals on purpose;
|
||||
* every CTA, link, and active state resolves to this one value.
|
||||
*
|
||||
* 2. `--accent-on` is Ink (`#1E2026`), not white. Yellow on white
|
||||
* text would smear; yellow on near-black text is the high-contrast
|
||||
* pairing DESIGN.md §4 documents for every primary button.
|
||||
*
|
||||
* 3. `--accent-hover` is Focus Blue (`#1EAEDB`), NOT a darker yellow.
|
||||
* DESIGN.md §4 explicitly defines the hover for every interactive
|
||||
* yellow surface as "shifts to Focus Blue with white text" — the
|
||||
* hue change IS the brand interaction. The hovered button's text
|
||||
* becomes white (component-level override), not Ink. This is the
|
||||
* single most counter-intuitive token in the file; rebinding to
|
||||
* a yellow-darken mix erases Binance's signature hover.
|
||||
*
|
||||
* 4. `--accent-active` is Active Yellow (`#D0980B`) — the documented
|
||||
* "clicked" gold from DESIGN.md §2, hand-picked rather than
|
||||
* formula-derived so the pressed state stays warm rather than
|
||||
* shifting cool with the hover.
|
||||
*
|
||||
* 5. Foreground ramp binds the full four-tier neutral scale from
|
||||
* DESIGN.md §2: Ink `#1E2026` (primary), Secondary `#32313A`
|
||||
* (nav links / descriptive copy), Slate `#848E9C` (the workhorse
|
||||
* grey for metadata / timestamps), Muted `#777E90` (secondary
|
||||
* nav / less-prominent footer text). Binance genuinely uses four
|
||||
* distinct text tiers across trading dashboards, so `--fg-2` and
|
||||
* `--meta` are independently bound, not aliased.
|
||||
*
|
||||
* 6. `--surface-warm` is Snow (`#F5F5F5`) — DESIGN.md §2 calls it
|
||||
* out as the "subtle surface differentiation, input backgrounds,
|
||||
* alternating row fills" tier. Bound independently (not aliased
|
||||
* to `--surface`) because dense data tables use it to visually
|
||||
* stripe rows without introducing a border weight.
|
||||
*
|
||||
* 7. `--success` is Crypto Green (`#0ECB81`) and `--danger` is
|
||||
* Crypto Red (`#F6465D`) — these are not generic semantic
|
||||
* colors, they are the bull/bear price-movement signals that
|
||||
* define the entire crypto-trading visual language. Binding the
|
||||
* schema slots to the documented brand values keeps semantic
|
||||
* pills, badges, and tickers on-brand without per-component
|
||||
* overrides.
|
||||
*
|
||||
* 8. Type scale tops out at 60px (`--text-4xl`). DESIGN.md §3
|
||||
* caps Display Hero at 60px / 700 with line-height 1.08 — the
|
||||
* ceiling expresses authority through weight, not size. Smaller
|
||||
* tiers map directly to the documented hierarchy table:
|
||||
* 11 / 14 / 16 / 20 / 24 / 28 / 34 / 60.
|
||||
*
|
||||
* 9. `--leading-tight` is `1.0`, not the schema's 1.2. DESIGN.md §3
|
||||
* explicitly sets headings 1–4 to line-height 1.00 ("stacked,
|
||||
* compressed feel that mirrors the density of trading
|
||||
* dashboards"). `--tracking-display` is `0` — the brand uses
|
||||
* weight (600–700) and size, not negative letter-spacing.
|
||||
*
|
||||
* 10. `--radius-pill` is `9999px`, not the literal 50px DESIGN.md
|
||||
* cites for CTAs. 9999 is the schema convention for "always
|
||||
* fully rounded"; both values render identically at any button
|
||||
* height below 4998px tall, and 9999 is what other brands ship.
|
||||
*
|
||||
* 11. `--elev-raised` is the literal "whisper" card shadow from
|
||||
* DESIGN.md §6 — `0 3px 5px 0 rgba(32, 32, 37, 0.05)`. At 5%
|
||||
* opacity the shadow is barely perceptible by design; DESIGN.md
|
||||
* §6 calls heavier shadows "frivolous" for a financial platform.
|
||||
* Components that hover-elevate (per DESIGN.md §4) inline the
|
||||
* richer `rgba(8, 8, 8, 0.05) 0 3px 5px 5px` variant.
|
||||
*
|
||||
* 12. `--focus-ring` is a SOLID 2px Focus Blue (`#1EAEDB`) ring, NOT
|
||||
* the schema's accent-tinted alpha glow. DESIGN.md §2 specifies
|
||||
* Focus Blue as the universal "Accessibility focus state" color
|
||||
* for all interactive elements — reproducing it as a sharp 2px
|
||||
* box-shadow keeps keyboard focus razor-legible against either
|
||||
* white or `#222126` surfaces.
|
||||
*
|
||||
* 13. Section rhythm is 80 / 48 / 32 (`--section-y-*`). DESIGN.md §5
|
||||
* lists `space-10: 80px` as "Large section spacing" and `space-8:
|
||||
* 48px` as "Major section padding" — the desktop hero gets the
|
||||
* 80px tier, tablet collapses to 48px, phone tightens to 32px.
|
||||
* Container caps at 1200px per DESIGN.md §5; gutters compress
|
||||
* 32 → 16 → 16 (DESIGN.md mobile = 16, no separate tablet step).
|
||||
*
|
||||
* Brand-specific extensions (Layer C): none. Crypto Green / Red /
|
||||
* Focus Blue / Dark Card `#2B2F36` / Binance Dark `#222126` are used
|
||||
* as inline expressions in components.html where dark sections and
|
||||
* price-ticker tints are rendered. They are not promoted to shared
|
||||
* tokens because no cross-brand component needs to reference them by
|
||||
* name — DESIGN.md §7 forbids dark-section colorization in shared
|
||||
* components anyway.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface (3 levels) ──────────────────────────────────────────
|
||||
* Pure white canvas for trust, Snow for input fields and alternating
|
||||
* data-table rows. Dark sections (`#222126`) are component-scoped:
|
||||
* shared components stay light-canvas; sections that flip dark
|
||||
* carry their own inline backgrounds. */
|
||||
--bg: #ffffff; /* Pure White — primary page canvas */
|
||||
--surface: #ffffff; /* White cards on light sections */
|
||||
--surface-warm: #f5f5f5; /* Snow — input bg, alternating rows */
|
||||
|
||||
/* ─── Foreground ramp (4 tiers) ──────────────────────────────────
|
||||
* Four distinct text tiers from DESIGN.md §2 — Ink for headings,
|
||||
* Secondary for nav links, Slate for metadata (the workhorse grey),
|
||||
* Muted for tertiary nav and quiet footer text. */
|
||||
--fg: #1e2026; /* Ink — primary text, headings */
|
||||
--fg-2: #32313a; /* Secondary — nav links, descriptive copy */
|
||||
--muted: #848e9c; /* Slate — metadata, timestamps, captions */
|
||||
--meta: #777e90; /* Muted — tertiary nav, footer text */
|
||||
|
||||
/* ─── Border (2 levels) ──────────────────────────────────────────
|
||||
* One light border tier for cards and forms; a softer inner tier
|
||||
* for row separators in dense data tables that must not compete
|
||||
* with the card edge. */
|
||||
--border: #e6e8ea; /* Border Light — cards, inputs, sections */
|
||||
--border-soft: #f0f1f2; /* Softer inner row separator */
|
||||
|
||||
/* ─── Accent ─────────────────────────────────────────────────────
|
||||
* The signature. Binance Yellow is the ONE non-neutral color in
|
||||
* the system — every primary CTA, every brand accent, every active
|
||||
* state resolves here. DESIGN.md §7 forbids introducing additional
|
||||
* brand colors. */
|
||||
--accent: #f0b90b; /* Binance Yellow */
|
||||
--accent-on: #1e2026; /* Ink — high-contrast label on yellow */
|
||||
--accent-hover: #1eaedb; /* Focus Blue — DESIGN.md §4 hover hue-shift */
|
||||
--accent-active: #d0980b; /* Active Yellow — pressed state */
|
||||
|
||||
/* ─── Semantic ───────────────────────────────────────────────────
|
||||
* Crypto-native semantics: green is "up", red is "down". These are
|
||||
* the bull/bear price-movement signals, not generic status colors,
|
||||
* and they bind directly to the shared semantic slots so tickers
|
||||
* and badges resolve on-brand without overrides. */
|
||||
--success: #0ecb81; /* Crypto Green — up indicators */
|
||||
--warn: #eab308; /* schema default — DESIGN.md has no warn tier */
|
||||
--danger: #f6465d; /* Crypto Red — down indicators */
|
||||
|
||||
/* ─── Typography ─────────────────────────────────────────────────
|
||||
* BinancePlex is the custom proprietary face; Arial is the
|
||||
* documented fallback (DESIGN.md §3 — "replaced DIN Next to solve
|
||||
* multi-language spacing issues"). Display and body share the
|
||||
* stack; weight (500–700) and size carry the entire hierarchy. */
|
||||
--font-display: BinancePlex, Arial, sans-serif;
|
||||
--font-body: BinancePlex, Arial, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale (px) — direct mapping of DESIGN.md §3 hierarchy:
|
||||
* 11 (Tiny) / 14 (Caption) / 16 (Body) / 20 (H4, Body Large) /
|
||||
* 24 (H2/H3) / 28 (H1) / 34 (Display Secondary) / 60 (Display Hero).
|
||||
* The 12px Small tier is collapsed into 11px (--text-xs); the 14.4px
|
||||
* Button Small variant is inlined per-component. */
|
||||
--text-xs: 11px; /* Tiny — micro-labels, chart annotations */
|
||||
--text-sm: 14px; /* Caption — metadata, prices, button-small */
|
||||
--text-base: 16px; /* Body — standard reading text, buttons */
|
||||
--text-lg: 20px; /* Body Large / Heading 4 — card titles */
|
||||
--text-xl: 24px; /* Heading 2 / Heading 3 — feature headings */
|
||||
--text-2xl: 28px; /* Heading 1 — major section headings */
|
||||
--text-3xl: 34px; /* Display Secondary — section titles on dark */
|
||||
--text-4xl: 60px; /* Display Hero — maximum impact */
|
||||
|
||||
/* Leading & tracking — DESIGN.md §3 sets headings at 1.00 line-height
|
||||
* (the "stacked, compressed feel that mirrors trading-dashboard
|
||||
* density"). Body opens to 1.5 for reading. No letter-spacing on
|
||||
* display — weight and size carry authority, not tracking. */
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0;
|
||||
--tracking-display: 0;
|
||||
|
||||
/* ─── Spacing ────────────────────────────────────────────────────
|
||||
* 8px base unit per DESIGN.md §5. 4/8/12/16/20/24/32/48 covers the
|
||||
* structural ladder; the 64px/80px hero/section tiers live in
|
||||
* --section-y-* below. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5 "Large section spacing" 80px desktop,
|
||||
* "Major section padding" 48px tablet, "Section breaks" 32px phone.
|
||||
* The alternating light/dark rhythm DESIGN.md §1 calls out is handled
|
||||
* per-section in components.html, not at the token level. */
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 48px;
|
||||
--section-y-phone: 32px;
|
||||
|
||||
/* ─── Radius ─────────────────────────────────────────────────────
|
||||
* DESIGN.md §5 scale: 1/2/6/8/10/12/24/50. We bind: 8 (form inputs,
|
||||
* data cards), 12 (content cards — the polished-but-not-overly-
|
||||
* rounded middle), 24 (hero/video containers), 9999 (pill CTAs —
|
||||
* DESIGN.md cites 50px but 9999 is the schema's "always full"
|
||||
* convention and renders identically). */
|
||||
--radius-sm: 8px; /* Form inputs, data cards */
|
||||
--radius-md: 12px; /* Content cards, feature containers */
|
||||
--radius-lg: 24px; /* Hero imagery, video containers */
|
||||
--radius-pill: 9999px; /* Pill CTAs — the signature interactive shape */
|
||||
|
||||
/* ─── Elevation (3 levels) ───────────────────────────────────────
|
||||
* Whisper-light: DESIGN.md §6 caps card shadows at 5% opacity ("in
|
||||
* a financial context, heavy shadows feel frivolous"). The raised
|
||||
* shadow is the documented resting-state card; hover-elevated and
|
||||
* pill-CTA shadows are component-scoped because they layer on top
|
||||
* of the base. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 3px 5px 0 rgba(32, 32, 37, 0.05);
|
||||
|
||||
/* ─── Focus ring ─────────────────────────────────────────────────
|
||||
* Focus Blue (`#1EAEDB`) per DESIGN.md §2 — the universal a11y
|
||||
* focus state for every interactive surface. Sharp 2px solid, not
|
||||
* a soft halo; trading platforms need unambiguous keyboard focus. */
|
||||
--focus-ring: 0 0 0 2px #1eaedb;
|
||||
|
||||
/* ─── Motion ─────────────────────────────────────────────────────
|
||||
* DESIGN.md §7 Don't list: "Don't add animation beyond subtle
|
||||
* transitions (200ms ease) — financial platforms need stability".
|
||||
* The brand voice is precision, not choreography. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────────────
|
||||
* 1200px max content width per DESIGN.md §5. Desktop gutter 32px
|
||||
* (DESIGN.md "Horizontal padding: 32px desktop"); mobile 16px
|
||||
* (DESIGN.md "16px mobile"); tablet sits at 16px because DESIGN.md
|
||||
* does not define a separate tablet gutter — better to match
|
||||
* mobile than over-extend the container on narrow screens. */
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 32px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 16px;
|
||||
}
|
||||
506
design-systems/clickhouse/components.html
Normal file
506
design-systems/clickhouse/components.html
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ClickHouse — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/clickhouse. Pure black canvas,
|
||||
neon volt accent (#faff69), Inter Black (900) display at 96px,
|
||||
charcoal-bordered cards, terminal-grade database aesthetic."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #000000;
|
||||
--surface: #141414;
|
||||
--surface-warm: var(--surface);
|
||||
|
||||
--fg: #ffffff;
|
||||
--fg-2: #a0a0a0;
|
||||
--muted: #a0a0a0;
|
||||
--meta: #585858;
|
||||
|
||||
--border: rgba(65, 65, 65, 0.8);
|
||||
--border-soft: #343434;
|
||||
|
||||
--accent: #faff69;
|
||||
--accent-on: #151515;
|
||||
--accent-hover: #1d1d1d;
|
||||
--accent-active: #f4f692;
|
||||
|
||||
--success: #166534;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
--font-display: "Inter", "Basier", Arial, Helvetica, ui-sans-serif, system-ui, sans-serif;
|
||||
--font-body: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
--font-mono: "Inconsolata", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 20px;
|
||||
--text-xl: 24px;
|
||||
--text-2xl: 36px;
|
||||
--text-3xl: 72px;
|
||||
--text-4xl: 96px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0;
|
||||
--tracking-display: normal;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 64px;
|
||||
--section-y-tablet: 48px;
|
||||
--section-y-phone: 32px;
|
||||
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
--radius-lg: 8px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — weight IS hierarchy ──────────────────── */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
line-height: var(--leading-tight);
|
||||
margin: 0;
|
||||
color: var(--fg);
|
||||
}
|
||||
h1 {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: 900; /* Inter Black — the weapon */
|
||||
letter-spacing: var(--tracking-display);
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 600; /* Basier-style feature heading */
|
||||
line-height: 1.30;
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 700;
|
||||
line-height: 1.17;
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--muted);
|
||||
line-height: 1.56;
|
||||
font-weight: 400;
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
.body-mono { font-family: var(--font-mono); font-weight: 600; }
|
||||
/* Uppercase overline — DESIGN.md: 14px / weight 600 / 1.4px tracking */
|
||||
.eyebrow {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.4px;
|
||||
font-weight: 600;
|
||||
line-height: 1.43;
|
||||
}
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-5 > * + * { margin-block-start: var(--space-5); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — sharp 4px radius, terminal-grade ────────── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 12px 16px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--surface);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
text-decoration: none;
|
||||
transition: background-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard),
|
||||
border-color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
/* Neon Primary — the eye-catching CTA: neon-on-black, hover inverts to dark */
|
||||
.btn-primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
border-color: var(--accent);
|
||||
padding: 0 16px;
|
||||
height: 40px;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-hover);
|
||||
color: var(--accent);
|
||||
}
|
||||
.btn-primary:active { color: var(--accent-active); }
|
||||
/* Forest Green — the "Get Started" conversion button */
|
||||
.btn-success {
|
||||
background: var(--success);
|
||||
color: var(--fg);
|
||||
border-color: var(--surface);
|
||||
}
|
||||
.btn-success:hover { background: #3a3a3a; color: rgba(255, 255, 255, 0.8); }
|
||||
.btn-success:active { color: var(--accent-active); }
|
||||
/* Ghost / Outlined — olive-tinted border, transparent bg */
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
border-color: #4f5100;
|
||||
padding: 0 var(--space-8);
|
||||
height: 40px;
|
||||
}
|
||||
.btn-ghost:hover { background: var(--surface); }
|
||||
.btn-ghost:active { color: var(--accent-active); }
|
||||
/* Dark solid — standard action button */
|
||||
.btn-dark {
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
border-color: var(--surface);
|
||||
}
|
||||
.btn-dark:hover { background: #3a3a3a; color: rgba(255, 255, 255, 0.8); }
|
||||
.btn-dark:active { color: var(--accent-active); }
|
||||
|
||||
/* ─── Inputs — dark fill, charcoal border ───────────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label { font-size: var(--text-sm); font-weight: 600; color: var(--fg); }
|
||||
.field input {
|
||||
padding: 12px 14px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-sm);
|
||||
outline: none;
|
||||
transition: border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field input::placeholder { color: var(--meta); }
|
||||
.field-help { font-size: var(--text-xs); color: var(--muted); }
|
||||
|
||||
/* ─── Cards — charcoal-bordered containment ─────────────── */
|
||||
.card {
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.card-neon {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.card-stat {
|
||||
background: transparent;
|
||||
border: 1px solid var(--border-soft);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
.stat-number {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 700;
|
||||
line-height: 1.0;
|
||||
color: var(--fg);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.stat-number-accent { color: var(--accent); }
|
||||
.stat-label {
|
||||
margin-block-start: var(--space-3);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Badges ────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex; align-items: center; gap: var(--space-2);
|
||||
padding: 4px var(--space-3);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: var(--text-xs); font-weight: 600; line-height: 1.6;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
.badge-success {
|
||||
color: var(--accent);
|
||||
background: color-mix(in oklab, var(--accent), transparent 92%);
|
||||
border-color: color-mix(in oklab, var(--accent), transparent 70%);
|
||||
}
|
||||
.badge-muted {
|
||||
color: var(--muted);
|
||||
background: var(--surface);
|
||||
border-color: var(--border-soft);
|
||||
}
|
||||
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
/* ─── Links — always hover to neon ──────────────────────── */
|
||||
a { color: var(--fg); text-decoration: none; transition: color var(--motion-fast) var(--ease-standard); }
|
||||
a:hover { color: var(--accent); }
|
||||
.link-accent { color: var(--accent); }
|
||||
kbd {
|
||||
font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 600;
|
||||
padding: 2px 6px; border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border); background: var(--surface); color: var(--fg-2);
|
||||
}
|
||||
|
||||
/* ─── Code block — Inconsolata, terminal aesthetic ──────── */
|
||||
.code-block {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600;
|
||||
line-height: var(--leading-body);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
color: var(--fg);
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
}
|
||||
.code-block .tok-kw { color: var(--accent); }
|
||||
.code-block .tok-com { color: var(--meta); }
|
||||
.code-block .tok-str { color: var(--fg-2); }
|
||||
|
||||
/* ─── Layout helpers ────────────────────────────────────── */
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: end;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.hero-grid { grid-template-columns: 1fr; gap: var(--space-8); align-items: stretch; }
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex; gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.hero-meta {
|
||||
display: flex; flex-direction: column; gap: var(--space-4);
|
||||
padding: var(--space-5);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
}
|
||||
.stats-bar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
margin-block-start: var(--space-8);
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.stats-bar { grid-template-columns: 1fr; }
|
||||
}
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 440px; }
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); }
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-5">
|
||||
<p class="eyebrow">Reference fixture · clickhouse</p>
|
||||
<h1>The fastest open-source OLAP database.</h1>
|
||||
<p class="lead" style="max-width: 56ch">
|
||||
Sub-second analytical queries over petabytes. A columnar engine built
|
||||
for real-time analytics, observability, and the agentic workloads of
|
||||
the next decade — running on commodity hardware.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Run a query
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-success">Get started</a>
|
||||
<a href="./tokens.css" class="btn btn-ghost">Read the docs</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-meta" aria-label="Cluster status">
|
||||
<div class="row-between">
|
||||
<span class="body-sm body-muted">Cluster</span>
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Operational
|
||||
</span>
|
||||
</div>
|
||||
<pre class="code-block" aria-label="Sample query"><span class="tok-com">-- 1.2B rows · 38ms</span>
|
||||
<span class="tok-kw">SELECT</span> country,
|
||||
<span class="tok-kw">count</span>(*) <span class="tok-kw">AS</span> hits
|
||||
<span class="tok-kw">FROM</span> events
|
||||
<span class="tok-kw">WHERE</span> ts > <span class="tok-str">'2026-05-01'</span>
|
||||
<span class="tok-kw">GROUP BY</span> country
|
||||
<span class="tok-kw">ORDER BY</span> hits <span class="tok-kw">DESC</span>
|
||||
<span class="tok-kw">LIMIT</span> 10;</pre>
|
||||
<p class="body-sm body-muted">Press <kbd>⌘</kbd> <kbd>K</kbd> to open the query palette.</p>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="stats-bar" role="list">
|
||||
<article class="card-stat" role="listitem">
|
||||
<div class="stat-number stat-number-accent">100×</div>
|
||||
<p class="stat-label">Faster than row-oriented stores on analytical workloads.</p>
|
||||
</article>
|
||||
<article class="card-stat" role="listitem">
|
||||
<div class="stat-number">38<span style="font-size: var(--text-2xl); color: var(--muted)">ms</span></div>
|
||||
<p class="stat-label">P95 latency on 1.2B-row aggregations, single replica.</p>
|
||||
</article>
|
||||
<article class="card-stat" role="listitem">
|
||||
<div class="stat-number">2.2PB</div>
|
||||
<p class="stat-label">Largest production cluster — and growing every quarter.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 26ch">Engineered for the workloads other databases can't keep up with.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card card-neon">
|
||||
<p class="eyebrow" style="color: var(--accent)">Featured</p>
|
||||
<h3>Columnar at the core</h3>
|
||||
<p class="body-muted body-sm">
|
||||
A vectorized execution engine reads only the columns a query touches.
|
||||
Compression ratios of 10–100× shrink storage and accelerate scans.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm link-accent">Inspect tokens →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Real-time ingestion</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Millions of rows per second per node. Kafka, S3, JDBC, HTTP —
|
||||
ingest from anywhere, query while writes are still in flight.
|
||||
</p>
|
||||
<a href="./DESIGN.md" class="body-sm">Read the spec →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>SQL you already know</h3>
|
||||
<p class="body-muted body-sm">
|
||||
ANSI SQL plus a powerful expression library. Window functions,
|
||||
JSON, geospatial, arrays — every analytical primitive, native.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Browse functions →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Form components</p>
|
||||
<h2>Spin up a cluster in 30 seconds.</h2>
|
||||
<p class="body-muted" style="max-width: 48ch">
|
||||
Inputs use the same charcoal-bordered geometry as the cards. Focus
|
||||
ring is neon volt — unified interactive feedback across the system.
|
||||
</p>
|
||||
<p class="body-sm body-muted">
|
||||
Already running ClickHouse? <a href="#" class="link-accent">Connect an existing cluster</a>.
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Work email</label>
|
||||
<input id="email" type="email" placeholder="you@company.com" autocomplete="email" required />
|
||||
<p class="field-help">We'll send your free-tier credentials and nothing else.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="region">Region</label>
|
||||
<input id="region" type="text" placeholder="us-east-1" value="us-east-1" />
|
||||
<p class="field-help">Pick a region close to your data sources for lowest latency.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-success">Create cluster</button>
|
||||
<button type="button" class="btn btn-ghost">View pricing</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
135
design-systems/clickhouse/tokens.css
Normal file
135
design-systems/clickhouse/tokens.css
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/clickhouse/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by ClickHouse".
|
||||
* High-performance cockpit in acid yellow-green on obsidian black —
|
||||
* pure black canvas, neon volt accents, extra-heavy Inter (900) display,
|
||||
* charcoal-bordered cards, terminal-grade aesthetic.
|
||||
*
|
||||
* Key brand decisions encoded here:
|
||||
* - Pure Black (#000000) page bg — never dark gray as page bg
|
||||
* - Neon Volt (#faff69) as sole chromatic accent — maximum contrast on black
|
||||
* - Charcoal borders (rgba(65,65,65,0.8)) — primary depth mechanism
|
||||
* - Inter as primary, Basier as secondary display, Inconsolata for code
|
||||
* - 96px display headlines with weight 900 — text as physical mass
|
||||
* - Tight 1.0 leading on display sizes — billboard scale
|
||||
* - Sharp 4px radius on buttons, 8px on cards — database precision geometry
|
||||
* - Forest Green (#166534) doubles as --success — brand-aligned semantic
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* Dark void: pure black canvas, near-black surfaces.
|
||||
* The black is absolute (#000000) — never softened to dark gray. */
|
||||
--bg: #000000; /* Pure Black — the page canvas, absolute */
|
||||
--surface: #141414; /* Near Black — buttons, lifted dark surfaces */
|
||||
--surface-warm: var(--surface); /* alias — no warm tier in the cool-neutral palette */
|
||||
|
||||
/* ─── Foreground ──────────────────────────────────────────────────
|
||||
* Pure White on black for primary, Silver for secondary.
|
||||
* All neutrals are perfectly neutral — no warm undertone. */
|
||||
--fg: #ffffff; /* Pure White — primary text on dark surfaces */
|
||||
--fg-2: #a0a0a0; /* Silver — secondary body text on dark */
|
||||
--muted: #a0a0a0; /* Silver — captions, muted content */
|
||||
--meta: #585858; /* Mid Gray — metadata, deepest neutral text */
|
||||
|
||||
/* ─── Border ──────────────────────────────────────────────────────
|
||||
* Charcoal at 80% opacity — the workhorse for all card containment.
|
||||
* Deep charcoal for inner separators that should not visually compete. */
|
||||
--border: rgba(65, 65, 65, 0.8); /* Charcoal — primary card edge */
|
||||
--border-soft: #343434; /* Deep Charcoal — inner separator, quieter */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* Neon Volt — the literal ClickHouse brand mark. Sole chromatic
|
||||
* interruption on the obsidian canvas. Used on CTAs, link hovers,
|
||||
* featured borders. Hover/active swap to dark variants per DESIGN.md:
|
||||
* the neon CTA's hover INVERTS to near-black bg; active dims to pale. */
|
||||
--accent: #faff69; /* Neon Volt — signature acid yellow-green */
|
||||
--accent-on: #151515; /* Near Black text on neon — maximum readability */
|
||||
--accent-hover: #1d1d1d; /* Brand-specific: neon CTA inverts to dark on hover */
|
||||
--accent-active: #f4f692; /* Pale Yellow — DESIGN.md active/pressed state */
|
||||
|
||||
/* ─── Semantic ────────────────────────────────────────────────────
|
||||
* Forest Green doubles as success — it's already the brand's
|
||||
* "Get Started" CTA color, so it's natively part of the palette.
|
||||
* Warn and danger use schema defaults to stay distinguishable. */
|
||||
--success: #166534; /* Forest Green — brand-aligned secondary CTA / success */
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
/* ─── Typography ──────────────────────────────────────────────────
|
||||
* Inter is the primary face — full weight spectrum (400/500/600/700/900).
|
||||
* Basier is the secondary display face for feature anchors at weight 600.
|
||||
* Inconsolata for code blocks at weight 600 — terminal-like rendering. */
|
||||
--font-display: "Inter", "Basier", Arial, Helvetica, ui-sans-serif, system-ui, sans-serif;
|
||||
--font-body: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
--font-mono: "Inconsolata", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale — DESIGN.md §3. 96px display mega, 72px hero, 36px feature.
|
||||
* Weight 900 is reserved for --text-4xl in components; 700 carries the
|
||||
* rest. Tight leading at scale — text feels architectural. */
|
||||
--text-xs: 12px; /* Small — smallest text */
|
||||
--text-sm: 14px; /* Caption / Uppercase Label (1.4px tracking) */
|
||||
--text-base: 16px; /* Body / Button / Code */
|
||||
--text-lg: 20px; /* Feature Title */
|
||||
--text-xl: 24px; /* Sub-heading / Card title */
|
||||
--text-2xl: 36px; /* Feature Heading (Basier 600) */
|
||||
--text-3xl: 72px; /* Display / Hero (Inter 700) */
|
||||
--text-4xl: 96px; /* Display Mega — Inter Black (900) */
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0; /* Display ultra-tight — physical mass */
|
||||
--tracking-display: normal; /* DESIGN.md: normal letter-spacing on display */
|
||||
|
||||
/* ─── Spacing ─────────────────────────────────────────────────────
|
||||
* 8px base grid. Section vertical spacing 48–64px (generous). */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 64px; /* DESIGN.md: 48–64px generous section rhythm */
|
||||
--section-y-tablet: 48px;
|
||||
--section-y-phone: 32px;
|
||||
|
||||
/* ─── Radius ──────────────────────────────────────────────────────
|
||||
* Sharp (4px) on buttons / badges / code blocks — database precision.
|
||||
* Comfortable (8px) on cards. Never round corners beyond 8px. */
|
||||
--radius-sm: 4px; /* Sharp — buttons, badges, small elements */
|
||||
--radius-md: 8px; /* Comfortable — cards, containers */
|
||||
--radius-lg: 8px; /* Same — DESIGN.md caps radius at 8px */
|
||||
--radius-pill: 9999px; /* Pill — toggle indicators, status badges */
|
||||
|
||||
/* ─── Elevation ───────────────────────────────────────────────────
|
||||
* Shadows are barely visible on black — depth comes from borders.
|
||||
* Level 2 subtle shadow declared for parity; the real depth signal
|
||||
* is --elev-ring (charcoal hairline) and neon-border highlights. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
/* ─── Focus ring ──────────────────────────────────────────────────
|
||||
* Neon-tinted focus — unified interactive feedback signal across
|
||||
* links, buttons, and inputs. Always shifts toward the accent. */
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||||
|
||||
/* ─── Motion ──────────────────────────────────────────────────────
|
||||
* Standard durations — ClickHouse's intensity is in color and weight,
|
||||
* not motion. Snappy enough to feel performant. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ──────────────────────────────────────────────────────
|
||||
* 1280px container — wide enough for multi-column dense data layouts
|
||||
* while still tractable on standard desktops (DESIGN.md tops at 2200px
|
||||
* for ultra-wide; 1280px is the workable default). */
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
501
design-systems/coinbase/components.html
Normal file
501
design-systems/coinbase/components.html
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Coinbase — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/coinbase. Coinbase Blue (#0052ff)
|
||||
as the singular functional accent, white canvas with cool-gray panels,
|
||||
56px pill CTAs, ultra-tight 1.00 display leading."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--surface: #eef0f3;
|
||||
--surface-warm: var(--surface);
|
||||
|
||||
--fg: #0a0b0d;
|
||||
--fg-2: var(--fg);
|
||||
--muted: #5b616e;
|
||||
--meta: var(--muted);
|
||||
|
||||
--border: rgba(91, 97, 110, 0.2);
|
||||
--border-soft: var(--border);
|
||||
|
||||
--accent: #0052ff;
|
||||
--accent-on: #ffffff;
|
||||
--accent-hover: #578bfa;
|
||||
--accent-active: #0667d0;
|
||||
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
--font-display:
|
||||
"CoinbaseDisplay", "Coinbase Display",
|
||||
"Inter", ui-sans-serif, system-ui, -apple-system,
|
||||
"Segoe UI", Arial, sans-serif;
|
||||
--font-body:
|
||||
"CoinbaseText", "CoinbaseSans", "Coinbase Sans",
|
||||
"Inter", ui-sans-serif, system-ui, -apple-system,
|
||||
"Segoe UI", Arial, sans-serif;
|
||||
--font-mono:
|
||||
ui-monospace, "SF Mono", "JetBrains Mono",
|
||||
Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 18px;
|
||||
--text-xl: 32px;
|
||||
--text-2xl: 36px;
|
||||
--text-3xl: 52px;
|
||||
--text-4xl: 80px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0;
|
||||
--tracking-display: -0.01em;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 16px;
|
||||
--radius-lg: 32px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 1px 2px color-mix(in oklab, var(--fg), transparent 92%);
|
||||
|
||||
--focus-ring: 0 0 0 2px var(--fg);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 16px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--container-gutter-desktop); }
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Section variants — dark/light alternation per DESIGN.md §1 */
|
||||
.section-dark { background: var(--fg); color: #ffffff; }
|
||||
.section-dark h1, .section-dark h2, .section-dark h3 { color: #ffffff; }
|
||||
.section-dark .lead, .section-dark .body-muted { color: color-mix(in oklab, #ffffff, transparent 28%); }
|
||||
.section-dark a { color: var(--accent); }
|
||||
.section-dark + section { border-top: none; }
|
||||
|
||||
/* ─── Typography — display ultra-tight, body regular ────── */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 400; /* CoinbaseDisplay carries weight via drawing, not 700 */
|
||||
line-height: var(--leading-tight);
|
||||
margin: 0;
|
||||
color: var(--fg);
|
||||
}
|
||||
h1 { font-size: var(--text-4xl); letter-spacing: var(--tracking-display); }
|
||||
h2 { font-size: var(--text-2xl); }
|
||||
h3 {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600; /* Feature title 18/600 per DESIGN.md §3 */
|
||||
font-family: var(--font-body);
|
||||
line-height: 1.33;
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead { font-size: var(--text-lg); color: var(--muted); line-height: 1.56; max-width: 56ch; }
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
.eyebrow {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-5 > * + * { margin-block-start: var(--space-5); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — 56px pill, blue functional accent ───────── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 14px 24px;
|
||||
border-radius: 56px; /* DESIGN.md §4 — primary CTA pill */
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600; /* Button 16/600 per DESIGN.md §3 */
|
||||
line-height: 1.2;
|
||||
letter-spacing: 0.01em; /* ≈ +0.16px tracking per DESIGN.md §3 */
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--motion-fast) var(--ease-standard),
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
.btn:active { transform: translateY(0); }
|
||||
|
||||
/* Primary: cool-gray surface with blue text — Coinbase consumer CTA */
|
||||
.btn-primary {
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
border-color: var(--surface);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-hover);
|
||||
border-color: var(--accent-hover);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Secondary: dark solid for inverse contexts and product moments */
|
||||
.btn-secondary {
|
||||
background: #282b31; /* Dark Card per DESIGN.md §2 */
|
||||
color: #ffffff;
|
||||
border-color: #282b31;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: var(--accent-hover);
|
||||
border-color: var(--accent-hover);
|
||||
}
|
||||
|
||||
/* Outline: blue-bordered, transparent — DESIGN.md §4 "Blue Bordered" */
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.btn-outline:hover {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
.btn-link:hover { color: var(--accent-active); text-decoration: underline; text-underline-offset: 3px; }
|
||||
|
||||
/* ─── Inputs ────────────────────────────────────────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label { font-size: var(--text-sm); font-weight: 600; color: var(--fg); }
|
||||
.field input {
|
||||
padding: 14px 16px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: #ffffff;
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
outline: none;
|
||||
transition:
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input::placeholder { color: var(--muted); }
|
||||
.field input:hover { border-color: color-mix(in oklab, var(--fg), transparent 70%); }
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field-help { font-size: var(--text-sm); color: var(--muted); }
|
||||
|
||||
/* ─── Cards ─────────────────────────────────────────────── */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.card-feature {
|
||||
background: var(--surface);
|
||||
border-color: transparent;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-8);
|
||||
gap: var(--space-4);
|
||||
}
|
||||
.card-icon {
|
||||
width: 40px; height: 40px;
|
||||
border-radius: var(--radius-pill);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
color: var(--accent);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
.card-feature .card-icon { background: var(--bg); border-color: var(--border); }
|
||||
|
||||
/* ─── Badges ────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 4px 10px;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 13px; /* DESIGN.md §3 Small 13/600 — inlined */
|
||||
font-weight: 600;
|
||||
line-height: 1.23;
|
||||
}
|
||||
.badge-success { color: var(--success); background: color-mix(in oklab, var(--success), transparent 88%); }
|
||||
.badge-muted { color: var(--muted); background: var(--surface); }
|
||||
.badge-accent { color: var(--accent); background: color-mix(in oklab, var(--accent), transparent 92%); }
|
||||
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
/* ─── Links ─────────────────────────────────────────────── */
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; text-underline-offset: 3px; }
|
||||
a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 2px; }
|
||||
kbd {
|
||||
font-family: var(--font-mono); font-size: var(--text-xs);
|
||||
padding: 2px 6px; border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border); background: #ffffff; color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Layout helpers ────────────────────────────────────── */
|
||||
.hero-grid { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--space-12); align-items: end; }
|
||||
@media (max-width: 1023px) { .hero-grid { grid-template-columns: 1fr; gap: var(--space-8); } }
|
||||
.hero-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-6); flex-wrap: wrap; }
|
||||
.hero-meta {
|
||||
display: flex; flex-direction: column; gap: var(--space-4);
|
||||
padding: var(--space-6);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: #ffffff;
|
||||
}
|
||||
.price-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
|
||||
.price-symbol { display: inline-flex; align-items: center; gap: var(--space-3); }
|
||||
.price-symbol-icon {
|
||||
width: 32px; height: 32px; border-radius: var(--radius-pill);
|
||||
background: var(--surface); color: var(--accent);
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
font-family: var(--font-body); font-weight: 700; font-size: var(--text-sm);
|
||||
}
|
||||
.price-symbol .ticker { font-weight: 600; font-size: var(--text-base); }
|
||||
.price-value { font-family: var(--font-display); font-size: var(--text-lg); font-variant-numeric: tabular-nums; }
|
||||
.price-change-up { color: var(--success); font-size: var(--text-sm); font-weight: 600; }
|
||||
.price-change-dn { color: var(--danger); font-size: var(--text-sm); font-weight: 600; }
|
||||
.row-divider { height: 1px; background: var(--border-soft); }
|
||||
|
||||
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
|
||||
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-12); align-items: center; }
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 440px; }
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); flex-wrap: wrap; }
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Reference fixture · coinbase</p>
|
||||
<h1>The easiest place to buy, sell, and manage crypto.</h1>
|
||||
<p class="lead">
|
||||
From your first satoshi to a long-term portfolio — Coinbase is the
|
||||
trusted on-ramp for over 100 million people worldwide. Get started
|
||||
in minutes, secure your assets, and trade with confidence.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Get started
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-outline">View prices</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-meta" aria-label="Market preview">
|
||||
<div class="row-between">
|
||||
<span class="eyebrow" style="color: var(--fg)">Markets</span>
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Live
|
||||
</span>
|
||||
</div>
|
||||
<div class="stack-3">
|
||||
<div class="price-row">
|
||||
<span class="price-symbol">
|
||||
<span class="price-symbol-icon" aria-hidden="true">B</span>
|
||||
<span class="ticker">BTC</span>
|
||||
</span>
|
||||
<span class="price-value">$68,420.50</span>
|
||||
<span class="price-change-up">+2.41%</span>
|
||||
</div>
|
||||
<div class="row-divider" aria-hidden="true"></div>
|
||||
<div class="price-row">
|
||||
<span class="price-symbol">
|
||||
<span class="price-symbol-icon" aria-hidden="true">E</span>
|
||||
<span class="ticker">ETH</span>
|
||||
</span>
|
||||
<span class="price-value">$3,512.18</span>
|
||||
<span class="price-change-up">+1.18%</span>
|
||||
</div>
|
||||
<div class="row-divider" aria-hidden="true"></div>
|
||||
<div class="price-row">
|
||||
<span class="price-symbol">
|
||||
<span class="price-symbol-icon" aria-hidden="true">S</span>
|
||||
<span class="ticker">SOL</span>
|
||||
</span>
|
||||
<span class="price-value">$182.04</span>
|
||||
<span class="price-change-dn">−0.62%</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="body-sm" style="color: var(--muted)">
|
||||
Press <kbd>⌘</kbd> <kbd>K</kbd> to search assets.
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Why Coinbase</p>
|
||||
<h2 style="max-width: 24ch">A mainstream-friendly home for digital money.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card card-feature">
|
||||
<span class="card-icon" aria-hidden="true">
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2 4 6v6c0 5 3.5 8.5 8 10 4.5-1.5 8-5 8-10V6l-8-4z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Trusted security</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Industry-leading custody, cold storage for the majority of customer
|
||||
assets, and FDIC-insured USD balances up to $250,000.
|
||||
</p>
|
||||
<a href="./tokens.css" class="btn-link body-sm">Learn how →</a>
|
||||
</article>
|
||||
<article class="card card-feature">
|
||||
<span class="card-icon" aria-hidden="true">
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
<path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3>200+ assets</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Buy and trade Bitcoin, Ethereum, and hundreds of other supported
|
||||
cryptocurrencies — all from a single, regulated platform.
|
||||
</p>
|
||||
<a href="./DESIGN.md" class="btn-link body-sm">See all assets →</a>
|
||||
</article>
|
||||
<article class="card card-feature">
|
||||
<span class="card-icon" aria-hidden="true">
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 12h4l3-8 4 16 3-8h4"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Instant on-ramp</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Link a bank or card, verify your identity, and place your first
|
||||
trade in minutes. Recurring buys keep your portfolio on autopilot.
|
||||
</p>
|
||||
<a href="./tokens.css" class="btn-link body-sm">Start in minutes →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form" class="section-dark">
|
||||
<div class="container" style="padding-inline: 0">
|
||||
<div class="form-row">
|
||||
<div class="stack-5">
|
||||
<p class="eyebrow" style="color: color-mix(in oklab, #ffffff, transparent 30%)">
|
||||
Get the app
|
||||
</p>
|
||||
<h2>Start with as little as $1.</h2>
|
||||
<p class="body-muted" style="max-width: 48ch">
|
||||
Create your account and we'll send setup instructions, recurring-buy
|
||||
templates, and a guide to keeping your assets safe — nothing else.
|
||||
</p>
|
||||
<div class="row-between" style="gap: var(--space-3); justify-content: flex-start">
|
||||
<span class="badge badge-accent">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
No platform fees on USDC
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email" style="color: #ffffff">Work or personal email</label>
|
||||
<input id="email" type="email" placeholder="you@example.com" autocomplete="email" required />
|
||||
<p class="field-help" style="color: color-mix(in oklab, #ffffff, transparent 40%)">
|
||||
By continuing, you agree to Coinbase's User Agreement and Privacy Policy.
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Get started</button>
|
||||
<button type="button" class="btn btn-secondary">Sign in</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
257
design-systems/coinbase/tokens.css
Normal file
257
design-systems/coinbase/tokens.css
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/coinbase/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Inspired by Coinbase" — the consumer
|
||||
* crypto exchange dressed in singular Coinbase Blue, near-black product
|
||||
* surfaces, and the 56px pill CTAs that make the brand instantly
|
||||
* recognisable. Mainstream-friendly fintech polish: white canvas,
|
||||
* one functional accent, restrained type, generous radii.
|
||||
*
|
||||
* Agents generating a Coinbase-flavored artifact should paste the
|
||||
* `:root { … }` block verbatim into the first `<style>` of the artifact,
|
||||
* then reference every value through `var(--name)` — never re-author the
|
||||
* brand blue inline.
|
||||
*
|
||||
* Schema notes (Coinbase binds the shared schema in seven brand-
|
||||
* specific ways — see `#Coinbase N` tags inline for each decision):
|
||||
*
|
||||
* #Coinbase 1 — `--surface` is the cool-gray `#eef0f3` from
|
||||
* DESIGN.md §2 — the secondary button background and
|
||||
* panel surface. It carries a barely-perceptible blue
|
||||
* tint that ties it to Coinbase Blue without competing.
|
||||
* `--surface-warm` aliases `var(--surface)` because the
|
||||
* brand has no warm tier at all (cool palette only).
|
||||
*
|
||||
* #Coinbase 2 — Single foreground tier: Near Black (`#0a0b0d`).
|
||||
* DESIGN.md §1 calls out the alternating dark / light
|
||||
* section model, but text within either section uses
|
||||
* one weight. `--fg-2` aliases `--fg` because Coinbase
|
||||
* does not differentiate a "subhead" gray. `--muted`
|
||||
* is the muted blue-gray `#5b616e` from DESIGN.md §2,
|
||||
* used for captions and secondary copy; `--meta`
|
||||
* aliases `--muted`.
|
||||
*
|
||||
* #Coinbase 3 — `--border` is `rgba(91, 97, 110, 0.2)` — the exact
|
||||
* 20% Muted Blue value DESIGN.md §2 names. Binding the
|
||||
* border to an alpha (not a solid hex) lets the same
|
||||
* value paint over white surfaces AND the cool-gray
|
||||
* `--surface` without re-tinting per context.
|
||||
* `--border-soft` aliases — DESIGN.md describes no
|
||||
* separate row-separator weight.
|
||||
*
|
||||
* #Coinbase 4 — `--accent` is Coinbase Blue (`#0052ff`). Per
|
||||
* DESIGN.md §7 Don't list, blue is "functional only,
|
||||
* never decorative" — the ≤2-accent-uses-per-screen
|
||||
* lint is doubly important on this brand. `--accent-hover`
|
||||
* binds to the explicit `#578bfa` (light hover blue
|
||||
* from DESIGN.md §4) and `--accent-active` binds to
|
||||
* `#0667d0` (the documented Link Blue, repurposed as
|
||||
* the deeper pressed state). Coinbase Blue is too
|
||||
* saturated for a black-mix formula to produce the
|
||||
* same shifts — use the brand's own values.
|
||||
*
|
||||
* #Coinbase 5 — Type scale tops out at 80px (`--text-4xl`).
|
||||
* DESIGN.md §3 puts Display Hero at 80px / weight 400
|
||||
* with `line-height: 1.00`. The 64px and 52px display
|
||||
* tiers from DESIGN.md slot into `--text-3xl` /
|
||||
* intermediate; smaller marketing tiers (Caption 14px,
|
||||
* Small 13px) bind to `--text-sm` with the 13px micro-
|
||||
* tier inlined per-component where used.
|
||||
*
|
||||
* #Coinbase 6 — `--leading-tight` is `1.00` — the ultra-tight
|
||||
* display rhythm DESIGN.md §1 calls out as a key
|
||||
* characteristic. Body reading stays at `1.5`; the
|
||||
* 18px body / 1.56 ratio from DESIGN.md §3 is
|
||||
* expressible as `--leading-body: 1.5` rounded for
|
||||
* the schema's single body lh.
|
||||
*
|
||||
* #Coinbase 7 — `--focus-ring` is a sharp 2px solid ring at
|
||||
* `var(--fg)` — DESIGN.md §4 specifies "Focus: 2px
|
||||
* solid black outline" on every interactive element.
|
||||
* We reproduce that as a `box-shadow` so the ring sits
|
||||
* outside the element without affecting layout. This
|
||||
* differs from the schema default (3px alpha glow at
|
||||
* --accent) because Coinbase's focus is mechanical,
|
||||
* not atmospheric.
|
||||
*
|
||||
* Brand-specific extensions (Layer C):
|
||||
* None. The 56px pill-CTA radius from DESIGN.md §4 is *component-
|
||||
* specific* (only primary CTAs use it) and lives inline in
|
||||
* components.html rather than as a new token; promoting it would
|
||||
* force every other brand to declare a matching slot.
|
||||
*
|
||||
* Source contracts:
|
||||
* - Standard token names: design-systems/_schema/tokens.schema.ts
|
||||
* - A2 fallback parity: design-systems/_schema/defaults.css
|
||||
* - Lint enforcement: apps/daemon/src/lint-artifact.ts
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface (3 levels — #Coinbase 1) ────────────────────────────
|
||||
* White canvas, cool-gray panel surface. The `--surface` tint is
|
||||
* the same `#eef0f3` Coinbase uses behind secondary buttons — it
|
||||
* carries just enough blue cast to feel of-a-piece with the brand
|
||||
* accent without competing with it. No warm tier exists; the
|
||||
* alias keeps cross-brand components resolvable. */
|
||||
--bg: #ffffff;
|
||||
--surface: #eef0f3; /* Cool Gray — secondary surface, panels */
|
||||
--surface-warm: var(--surface); /* alias — Coinbase has no warm tier */
|
||||
|
||||
/* ─── Foreground ramp (2 tiers — #Coinbase 2) ────────────────────
|
||||
* Near Black (`#0a0b0d`) carries every heading and body line —
|
||||
* Coinbase's product surfaces invert to this color on dark
|
||||
* sections (DESIGN.md §1). Muted Blue (`#5b616e`) is the caption /
|
||||
* placeholder tier. No third or fourth tier — both B-slots alias. */
|
||||
--fg: #0a0b0d; /* Near Black — text, dark section bg */
|
||||
--fg-2: var(--fg); /* alias — single text weight throughout */
|
||||
--muted: #5b616e; /* Muted Blue — captions, secondary copy */
|
||||
--meta: var(--muted); /* alias — no separate metadata tier */
|
||||
|
||||
/* ─── Border (1 tier — #Coinbase 3) ──────────────────────────────
|
||||
* DESIGN.md §2 names the border explicitly: 20% Muted Blue.
|
||||
* Binding to an alpha (not a solid hex) lets the same value paint
|
||||
* over white AND the cool-gray surface without re-tinting per
|
||||
* context. `--border-soft` aliases — Coinbase has one border
|
||||
* weight for everything. */
|
||||
--border: rgba(91, 97, 110, 0.2); /* Muted Blue @ 20% — DESIGN.md §2 */
|
||||
--border-soft: var(--border); /* alias — one border weight */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* Coinbase Blue — the singular brand accent. Used for CTA borders,
|
||||
* focus accents, link text. Hard cap of ≤2 visible uses per screen
|
||||
* (lint enforced) is doubly important here because DESIGN.md §7
|
||||
* forbids decorative use: "Don't use the blue decoratively — it's
|
||||
* functional only". */
|
||||
--accent: #0052ff; /* Coinbase Blue — brand mark */
|
||||
--accent-on: #ffffff; /* white label on saturated blue */
|
||||
--accent-hover: #578bfa; /* light hover blue — DESIGN.md §4 */
|
||||
--accent-active: #0667d0; /* deeper pressed — Link Blue, DESIGN.md §2 */
|
||||
|
||||
/* ─── Semantic ───────────────────────────────────────────────────
|
||||
* Standard semantic colors. DESIGN.md does not redefine success /
|
||||
* warn / danger; Coinbase's product UI uses them at the schema
|
||||
* defaults so the financial-status palette stays distinct from the
|
||||
* brand-blue moment. */
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
/* ─── Typography — fonts ─────────────────────────────────────────
|
||||
* Coinbase's four-font proprietary family (Display, Sans, Text,
|
||||
* Icons) reduces to two stacks here: display headlines use
|
||||
* CoinbaseDisplay; everything else uses CoinbaseText / Sans. Both
|
||||
* stacks degrade through Inter (the closest open-source match) to
|
||||
* system sans so artifacts render legibly without the licensed
|
||||
* faces. CoinbaseIcons is an icon font, not a text face, and is
|
||||
* not bound to a schema slot. */
|
||||
--font-display:
|
||||
"CoinbaseDisplay", "Coinbase Display",
|
||||
"Inter", ui-sans-serif, system-ui, -apple-system,
|
||||
"Segoe UI", Arial, sans-serif;
|
||||
--font-body:
|
||||
"CoinbaseText", "CoinbaseSans", "Coinbase Sans",
|
||||
"Inter", ui-sans-serif, system-ui, -apple-system,
|
||||
"Segoe UI", Arial, sans-serif;
|
||||
--font-mono:
|
||||
ui-monospace, "SF Mono", "JetBrains Mono",
|
||||
Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* ─── Typography — type scale (#Coinbase 5) ─────────────────────
|
||||
* Direct mapping of DESIGN.md §3: 12 / 14 / 16 / 18 / 32 / 36 /
|
||||
* 52 / 80. Display Hero hits 80px (the full marketing scale);
|
||||
* Section Heading 36px and Card Title 32px sit a step apart for
|
||||
* visual gear-shifting. The 13px tag size from DESIGN.md is a
|
||||
* one-off micro tier and is inlined per-component. */
|
||||
--text-xs: 12px; /* extra small — tags, dense labels */
|
||||
--text-sm: 14px; /* caption, small UI */
|
||||
--text-base: 16px; /* body small, button, navigation */
|
||||
--text-lg: 18px; /* feature title, body reading */
|
||||
--text-xl: 32px; /* card title */
|
||||
--text-2xl: 36px; /* section heading */
|
||||
--text-3xl: 52px; /* display third tier */
|
||||
--text-4xl: 80px; /* display hero — full scale */
|
||||
|
||||
/* ─── Typography — leading & tracking (#Coinbase 6) ─────────────
|
||||
* `--leading-tight` is 1.00 — DESIGN.md §1 lists "1.00 line-height
|
||||
* on display headings — ultra-tight" as a defining characteristic.
|
||||
* `--leading-body` is 1.5 (the body reading rhythm). Tracking
|
||||
* compresses subtly at display sizes; CoinbaseDisplay is already
|
||||
* tightly drawn, so -0.01em is enough — bigger negative tracking
|
||||
* would over-collapse the wordmark. */
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0; /* ultra-tight — display headings */
|
||||
--tracking-display: -0.01em; /* subtle compression at hero scale */
|
||||
|
||||
/* ─── Spacing ────────────────────────────────────────────────────
|
||||
* 8px base unit per DESIGN.md §5. The schema's
|
||||
* 4/8/12/16/20/24/32/48 ladder covers Coinbase's rhythm; the
|
||||
* sub-tier 1/3/5/6/10/15/25 fine-grain values from DESIGN.md are
|
||||
* inlined where they appear (chart axes, button micro-padding). */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* ─── Section rhythm ─────────────────────────────────────────────
|
||||
* Generous vertical breathing room desktop-side so the 80px
|
||||
* display hero has air above and below. Tightens to 64px on
|
||||
* tablet, 40px on phone. */
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
/* ─── Radius ─────────────────────────────────────────────────────
|
||||
* DESIGN.md §5 radius scale: 4–8 (small), 12–16 (standard),
|
||||
* 24–32 (large), 40 (XL), 56 (pill CTAs), 100000 (full). The
|
||||
* schema's four tiers map to: 8 (functional), 16 (cards), 32
|
||||
* (feature containers), 9999 (badges / avatars). The 56px pill-
|
||||
* CTA radius is component-specific (primary buttons only) and
|
||||
* lives inline in components.html rather than as a new token. */
|
||||
--radius-sm: 8px; /* inputs, chips, small cards */
|
||||
--radius-md: 16px; /* cards, panels */
|
||||
--radius-lg: 32px; /* feature containers, hero panels */
|
||||
--radius-pill: 9999px; /* badges, avatars, full pill */
|
||||
|
||||
/* ─── Elevation (3 levels) ───────────────────────────────────────
|
||||
* DESIGN.md §6: "Minimal shadow system — depth from color contrast
|
||||
* between dark/light sections." The cascade is intentionally quiet:
|
||||
*
|
||||
* --elev-flat no shadow (page surface, text blocks)
|
||||
* --elev-ring hairline 1px ring (cards on white)
|
||||
* --elev-raised the lightest possible drop — used sparingly on
|
||||
* floating panels / dropdowns. Depth on Coinbase
|
||||
* comes from the dark / light section contrast,
|
||||
* not from elevation per element. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 1px 2px color-mix(in oklab, var(--fg), transparent 92%);
|
||||
|
||||
/* ─── Focus ring (#Coinbase 7) ──────────────────────────────────
|
||||
* DESIGN.md §4 specifies "Focus: 2px solid black outline" on
|
||||
* every interactive element. We reproduce that as a 2px solid
|
||||
* box-shadow at `var(--fg)` so the ring sits outside the element
|
||||
* without shifting layout. This is sharper and more mechanical
|
||||
* than the schema's atmospheric glow — by design. */
|
||||
--focus-ring: 0 0 0 2px var(--fg);
|
||||
|
||||
/* ─── Motion ─────────────────────────────────────────────────────
|
||||
* Standard durations + standard easing. Coinbase's surface motion
|
||||
* is restrained — buttons transition background on hover but
|
||||
* never transform; the brand voice is precision, not bounce. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────────────
|
||||
* 1280px max content width — DESIGN.md §8 breakpoints climb to
|
||||
* 1600px, but the body content centers at 1280 with the marketing
|
||||
* imagery bleeding wider. Gutters: 24 → 16 → 16. */
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 16px;
|
||||
}
|
||||
502
design-systems/hashicorp/components.html
Normal file
502
design-systems/hashicorp/components.html
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>HashiCorp — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/hashicorp. Dramatic near-black
|
||||
canvas (#15181e), HashiCorp Sans at 82px display with kerning enabled,
|
||||
whisper-level dual-layer shadows, single functional blue accent.
|
||||
Every visible value comes from tokens.css."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #15181e;
|
||||
--surface: #0d0e12;
|
||||
--surface-warm: var(--surface);
|
||||
|
||||
--fg: #efeff1;
|
||||
--fg-2: #d5d7db;
|
||||
--muted: #b2b6bd;
|
||||
--meta: #656a76;
|
||||
|
||||
--border: rgba(178, 182, 189, 0.4);
|
||||
--border-soft: rgba(178, 182, 189, 0.15);
|
||||
|
||||
--accent: #1060ff;
|
||||
--accent-on: #ffffff;
|
||||
--accent-hover: #2b89ff;
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||||
|
||||
--success: #16a34a;
|
||||
--warn: #bb5a00;
|
||||
--danger: #dc2626;
|
||||
|
||||
--font-display: "HashiCorp Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 13px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 20px;
|
||||
--text-xl: 26px;
|
||||
--text-2xl: 42px;
|
||||
--text-3xl: 52px;
|
||||
--text-4xl: 82px;
|
||||
|
||||
--leading-body: 1.63;
|
||||
--leading-tight: 1.17;
|
||||
--tracking-display: normal;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 56px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
--radius-sm: 5px;
|
||||
--radius-md: 8px;
|
||||
--radius-lg: 8px;
|
||||
--radius-pill: 5px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised:
|
||||
rgba(97, 104, 117, 0.05) 0px 1px 1px,
|
||||
rgba(97, 104, 117, 0.05) 0px 2px 2px;
|
||||
|
||||
--focus-ring: 0 0 0 3px var(--accent);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1150px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg-2);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border-soft); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — HashiCorp Sans for headings, system-ui for body ─ */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
color: var(--fg);
|
||||
margin: 0;
|
||||
line-height: var(--leading-tight);
|
||||
font-feature-settings: "kern"; /* DESIGN.md §3: kern always on */
|
||||
}
|
||||
h1 {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: 600; /* DESIGN.md hero: 600 */
|
||||
letter-spacing: var(--tracking-display);
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 600; /* DESIGN.md section heading: 600 */
|
||||
line-height: 1.19;
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 700; /* DESIGN.md card title: 700 */
|
||||
line-height: 1.19;
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-size: var(--text-lg);
|
||||
line-height: 1.50;
|
||||
color: var(--fg-2);
|
||||
font-weight: 400;
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
.body-meta { color: var(--meta); font-size: var(--text-sm); }
|
||||
|
||||
/* DESIGN.md §3 uppercase wayfinding label.
|
||||
13px HashiCorp Sans weight 600, 1.3px tracking. */
|
||||
.eyebrow {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
line-height: 1.69;
|
||||
letter-spacing: 1.3px;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
font-feature-settings: "kern";
|
||||
}
|
||||
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — DESIGN.md §4 ─────────────────────────────── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--motion-fast) var(--ease-standard),
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
.btn:active { transform: translateY(0.5px); }
|
||||
|
||||
/* Primary Dark — DESIGN.md §4: asymmetric 9px 9px 9px 15px padding,
|
||||
5px radius, 1px border at rgba(178,182,189,0.4), whisper shadow. */
|
||||
.btn-primary {
|
||||
background: var(--bg);
|
||||
color: var(--fg-2);
|
||||
padding: 9px 9px 9px 15px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: color-mix(in oklab, var(--bg), white 4%);
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
/* Secondary White — DESIGN.md §4: 4px radius, 8px 12px padding,
|
||||
clean white surface on the dark canvas. */
|
||||
.btn-secondary {
|
||||
background: #ffffff;
|
||||
color: #3b3d45; /* DESIGN.md Charcoal text on white */
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: color-mix(in oklab, #ffffff, black 4%);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
|
||||
/* CTA Accent — Action Blue, reserved for the single highest-signal
|
||||
CTA on the page. Hard cap of ≤2 visible accent uses per screen. */
|
||||
.btn-accent {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
padding: 9px 15px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid transparent;
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
.btn-accent:hover { background: var(--accent-hover); }
|
||||
.btn-accent:active { background: var(--accent-active); }
|
||||
|
||||
/* ─── Inputs — dark mode form fields ─────────────────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--fg-2);
|
||||
}
|
||||
.field input {
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--meta); /* DESIGN.md §4: rgb(97,104,117) — same hue as --meta */
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 11px;
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
outline: none;
|
||||
transition:
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input::placeholder { color: var(--meta); }
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field-help { font-size: var(--text-xs); color: var(--meta); }
|
||||
|
||||
/* ─── Cards — DESIGN.md §4 ───────────────────────────────── */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-soft);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
box-shadow: var(--elev-raised); /* whisper shadow — barely there */
|
||||
}
|
||||
|
||||
/* ─── Badges — 5px radius, deep purple per DESIGN.md ─────── */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 3px 7px; /* DESIGN.md §4 badge padding */
|
||||
border-radius: var(--radius-pill); /* 5px, not 9999px — see tokens.css */
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.badge-status {
|
||||
background: color-mix(in oklab, var(--success), transparent 80%);
|
||||
color: color-mix(in oklab, var(--success), white 30%);
|
||||
border: 1px solid color-mix(in oklab, var(--success), transparent 60%);
|
||||
}
|
||||
.badge-dot {
|
||||
width: 6px; height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ─── Links ──────────────────────────────────────────────── */
|
||||
a {
|
||||
color: var(--accent-hover); /* Bright Blue — DESIGN.md links on dark */
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: border-color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
a:hover { border-bottom-color: currentColor; }
|
||||
kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px; /* DESIGN.md "Subtle" 3px radius */
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg-2);
|
||||
}
|
||||
|
||||
/* ─── Layout helpers ─────────────────────────────────────── */
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: end;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.hero-grid { grid-template-columns: 1fr; gap: var(--space-8); }
|
||||
h1 { font-size: var(--text-3xl); } /* 82 → 52 collapse per DESIGN.md §8 */
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
h1 { font-size: var(--text-2xl); } /* 52 → 42 collapse per DESIGN.md §8 */
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-meta {
|
||||
display: flex; flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-5);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-soft);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.3fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form {
|
||||
display: flex; flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
max-width: 420px;
|
||||
}
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); }
|
||||
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.mono { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<!-- HERO ───────────────────────────────────────────────── -->
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Reference fixture · hashicorp</p>
|
||||
<h1>Infrastructure for any application, on any cloud.</h1>
|
||||
<p class="lead" style="max-width: 52ch">
|
||||
Provision, secure, connect, and run any application on any
|
||||
infrastructure. The HashiCorp Cloud Platform unifies Terraform,
|
||||
Vault, Consul, and Nomad behind one operating model — built for
|
||||
the platform teams who run production.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-accent">
|
||||
Try HCP free
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="1.75"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-primary">Talk to sales</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="hero-meta" aria-label="Platform status">
|
||||
<p class="eyebrow">Platform status</p>
|
||||
<div class="row-between">
|
||||
<span class="body-sm">HCP control plane</span>
|
||||
<span class="badge badge-status">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Operational
|
||||
</span>
|
||||
</div>
|
||||
<div class="row-between">
|
||||
<span class="body-sm">Terraform Cloud</span>
|
||||
<span class="badge badge-status">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Operational
|
||||
</span>
|
||||
</div>
|
||||
<p class="body-meta">
|
||||
SOC 2 Type II · ISO 27001 · v1.0
|
||||
· <time datetime="2026-05-15">2026-05-15</time>
|
||||
</p>
|
||||
<p class="body-meta">
|
||||
Press <kbd>⌘</kbd> <kbd>K</kbd> to search the docs.
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FEATURES ────────────────────────────────────────────── -->
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 24ch">One operating model for cloud, not many.</h2>
|
||||
</div>
|
||||
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card stack-3">
|
||||
<h3>Provision with Terraform</h3>
|
||||
<p class="body-sm body-muted">
|
||||
Infrastructure as code across AWS, Azure, GCP, and 3,000+
|
||||
providers. Reproducible environments, drift detection, and
|
||||
policy as code — the platform layer for every team.
|
||||
</p>
|
||||
<p class="mono">terraform apply</p>
|
||||
</article>
|
||||
<article class="card stack-3">
|
||||
<h3>Secure with Vault</h3>
|
||||
<p class="body-sm body-muted">
|
||||
Identity-based secrets management and zero-trust security.
|
||||
Dynamic credentials, automatic rotation, encryption as a
|
||||
service — the same primitives behind production at scale.
|
||||
</p>
|
||||
<p class="mono">vault kv get secret/api</p>
|
||||
</article>
|
||||
<article class="card stack-3">
|
||||
<h3>Connect with Consul</h3>
|
||||
<p class="body-sm body-muted">
|
||||
Service mesh and service discovery across any runtime and
|
||||
any cloud. mTLS by default, intentions, and traffic shaping —
|
||||
network automation without the YAML.
|
||||
</p>
|
||||
<p class="mono">consul services register</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FORM ────────────────────────────────────────────────── -->
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Get started</p>
|
||||
<h2>Spin up your first workspace.</h2>
|
||||
<p class="body-muted" style="max-width: 48ch">
|
||||
Free tier includes Terraform Cloud, Vault Secrets, and HCP
|
||||
Boundary. Bring your own cloud account or use HCP-managed
|
||||
infrastructure — production-grade defaults, day one.
|
||||
</p>
|
||||
<p class="body-meta">
|
||||
By signing up you agree to the <a href="./DESIGN.md">terms</a>
|
||||
and <a href="./DESIGN.md">privacy notice</a>.
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Work email</label>
|
||||
<input id="email" type="email" placeholder="you@company.com"
|
||||
autocomplete="email" required />
|
||||
<p class="field-help">We'll send a verification link — nothing else.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="org">Organization name</label>
|
||||
<input id="org" type="text" placeholder="acme-platform"
|
||||
autocomplete="organization" />
|
||||
<p class="field-help">Lowercase, hyphen-separated. Used in resource paths.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-accent">Create workspace</button>
|
||||
<button type="button" class="btn btn-primary">View pricing</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
272
design-systems/hashicorp/tokens.css
Normal file
272
design-systems/hashicorp/tokens.css
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/hashicorp/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by HashiCorp" —
|
||||
* enterprise infrastructure-as-code made tangible: a dramatic near-black
|
||||
* canvas, engineering-grade typography, whisper-level shadows, and one
|
||||
* functional blue accent reserved for actionable signals.
|
||||
*
|
||||
* Brand identity in three sentences:
|
||||
* 1. Dark-mode-native canvas (#15181e Dark Charcoal → #0d0e12 Near Black).
|
||||
* DESIGN.md §1 names these as the "dramatic dark-mode for hero areas
|
||||
* and product showcases" — we bind --bg/--surface to the iconic
|
||||
* pair because HashiCorp's brand-defining surfaces are dark.
|
||||
* 2. HashiCorp Sans for headings (600–700 weight, kern enabled, 1.17
|
||||
* line-height at 82px display); system-ui for body, navigation, and
|
||||
* functional text. The brand font carries the weight; system-ui
|
||||
* carries the words.
|
||||
* 3. Action Blue (#1060ff) as the lone functional accent on dark; the
|
||||
* multi-product palette (Terraform purple, Vault yellow, Waypoint
|
||||
* teal, Vagrant blue) lives in DESIGN.md §2 as product-scoped
|
||||
* colors and intentionally does NOT bind here — DESIGN.md §7 forbids
|
||||
* "product brand colors outside their product context".
|
||||
*
|
||||
* Brand-specific schema decisions (each one bends a schema convention
|
||||
* to match HashiCorp's voice rather than the cross-brand default):
|
||||
*
|
||||
* 1. --bg is #15181e (Dark Charcoal), not white. DESIGN.md describes
|
||||
* the brand's "dual mode" — clean white informational sections AND
|
||||
* dramatic dark hero/product areas — but the dark surfaces are the
|
||||
* identity-defining ones; that is where HashiCorp Sans at 82px,
|
||||
* the multi-product accent colors, and the whisper shadows all
|
||||
* do their work. Binding --bg to the dark canvas honors the
|
||||
* iconic look and matches the "dark-friendly enterprise UI"
|
||||
* identity called out in the brand interpretation.
|
||||
*
|
||||
* 2. --fg ramp is independently bound across all four tiers
|
||||
* (Near White #efeff1 → Mid Gray #d5d7db → Cool Gray #b2b6bd →
|
||||
* Dark Gray #656a76). DESIGN.md §2 lists each as a named role —
|
||||
* "Primary text on dark / Button text on dark / Border accents /
|
||||
* Helper text" — and the brand genuinely walks the full ramp.
|
||||
* Collapsing --fg-2 or --muted to siblings would flatten the
|
||||
* ladder that gives HashiCorp content its enterprise density.
|
||||
*
|
||||
* 3. --border is rgba(178, 182, 189, 0.4) — the literal alpha used
|
||||
* on DESIGN.md §4's "Primary Dark" button border. Binding
|
||||
* --border to the alpha (not a solid hex) lets `--elev-ring`
|
||||
* reproduce the cool-gray hairline and lets components reach the
|
||||
* same value via `border: 1px solid var(--border)`.
|
||||
* --border-soft drops to 0.15 alpha for inner separators that
|
||||
* should not visually compete with the button edge.
|
||||
*
|
||||
* 4. --accent is Action Blue (#1060ff), NOT a product brand color.
|
||||
* DESIGN.md §2 explicitly classifies Terraform purple / Vault
|
||||
* yellow / Waypoint teal as product-scoped tokens; the corporate
|
||||
* brand's functional CTA color on dark is #1060ff. --accent-hover
|
||||
* LIFTS to #2b89ff (DESIGN.md "Bright Blue — Active links, hover
|
||||
* accent") instead of darkening — the schema's default black-mix
|
||||
* formula would lose contrast on the dark canvas. --accent-active
|
||||
* then darkens via the standard formula for the press state.
|
||||
*
|
||||
* 5. --warn is #bb5a00 (DESIGN.md Amber-200), not the schema default
|
||||
* #eab308. The brighter yellow would clash with HashiCorp's
|
||||
* muted enterprise palette and read as "Vault product color"
|
||||
* rather than "warning state". The burnt-amber sits warm but
|
||||
* restrained on the dark canvas.
|
||||
*
|
||||
* 6. --font-display loads HashiCorp Sans (the custom brand face
|
||||
* called out throughout DESIGN.md) with a substantive fallback
|
||||
* stack; --font-body uses system-ui per DESIGN.md §3's brand/
|
||||
* system split ("HashiCorp Sans for headings only (17px+),
|
||||
* system-ui for everything else"). Mixing the two is the
|
||||
* structural rule — never set body copy in HashiCorp Sans.
|
||||
*
|
||||
* 7. Type scale tops at 82px (--text-4xl) with 1.17 line-height
|
||||
* (--leading-tight). DESIGN.md §3 lists 82px / 52px / 42px / 34px
|
||||
* / 26px as the documented HashiCorp Sans tiers; the 8 schema
|
||||
* slots map onto five of those plus body sizes 20/16/14/13.
|
||||
* --tracking-display is `normal` because DESIGN.md §3 explicitly
|
||||
* sets the 82px hero to letter-spacing `normal` — the brand
|
||||
* relies on kerning, not tracking, for its monolithic feel.
|
||||
*
|
||||
* 8. --leading-body is 1.63 (DESIGN.md's relaxed 1.63–1.69 body
|
||||
* range) — generous reading rhythm BELOW the tight 1.17 headings
|
||||
* is the brand's "weight at the top of each section" rule.
|
||||
* --leading-tight is 1.17, the documented display line-height.
|
||||
*
|
||||
* 9. --radius scale is tight: 5px / 8px / 8px / 5px. DESIGN.md §5
|
||||
* caps radius at 8px ("nothing pill-shaped or circular") and
|
||||
* uses 5px for primary buttons, badges, and inputs. We bind
|
||||
* --radius-lg to the same 8px ceiling (HashiCorp does not have
|
||||
* a third tier above cards) and --radius-pill to 5px, matching
|
||||
* DESIGN.md §4's "Badges / Pills — Radius: 5px". The brand's
|
||||
* "no true pill" rule is structural, not stylistic.
|
||||
*
|
||||
* 10. --elev-raised is the whisper-shadow VERBATIM from DESIGN.md §6
|
||||
* Level 1: dual-layer at 5% opacity on a cool-gray base. The
|
||||
* doc says it explicitly: "If you can see the shadow, it's too
|
||||
* strong." We must not strengthen this in component CSS —
|
||||
* enterprise stability is communicated through restraint.
|
||||
*
|
||||
* 11. --focus-ring is 3px solid var(--accent) (sharp ring, no halo),
|
||||
* per DESIGN.md §6 ("Focus (Level 2) — 3px solid"). Sharp focus
|
||||
* is the engineered alternative to the schema's 3px alpha glow.
|
||||
*
|
||||
* 12. --section-y-desktop is 80px (DESIGN.md §5 "Enterprise breathing
|
||||
* room: Generous vertical spacing between sections (48px–80px+)").
|
||||
* --container-max is 1150px exactly — DESIGN.md §5 names ~1150px
|
||||
* as the documented xl breakpoint and max content width.
|
||||
*
|
||||
* Source contracts:
|
||||
* - Standard token names: design-systems/_schema/tokens.schema.ts
|
||||
* - A2 fallback parity: design-systems/_schema/defaults.css
|
||||
* - Lint enforcement: apps/daemon/src/lint-artifact.ts
|
||||
*
|
||||
* Keep this file additive: never invent token names not also documented
|
||||
* in DESIGN.md or the schema. The HashiCorp Sans face is referenced by
|
||||
* name only — the stack lists OS fallbacks so artifacts render
|
||||
* acceptably even when the brand font is not loaded.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface (3 levels — dark-mode canvas) ───────────────────────
|
||||
* DESIGN.md §1 names #15181e and #0d0e12 as the two dark-mode
|
||||
* surfaces. --surface-warm aliases --surface because the brand is
|
||||
* famously achromatic on dark — depth comes from luminance steps
|
||||
* and whisper shadows, not from warm-tinting one surface against
|
||||
* another. (DESIGN.md §7: "Don't use pure black (#000000) for dark
|
||||
* backgrounds — use #15181e or #0d0e12.") */
|
||||
--bg: #15181e; /* Dark Charcoal — hero canvas */
|
||||
--surface: #0d0e12; /* Near Black — cards, inputs */
|
||||
--surface-warm: var(--surface); /* alias — no warm tier on dark */
|
||||
|
||||
/* ─── Foreground ramp (4 levels) ──────────────────────────────────
|
||||
* Near White → Mid Gray → Cool Gray → Dark Gray. All four are named
|
||||
* in DESIGN.md §2 with distinct roles, so we bind each independently
|
||||
* (no aliasing). #efeff1 instead of #ffffff matters — pure white
|
||||
* against #15181e reads as harsh; the slight warmth keeps the
|
||||
* enterprise tone from feeling clinical. */
|
||||
--fg: #efeff1; /* Near White — primary text on dark */
|
||||
--fg-2: #d5d7db; /* Mid Gray — body description, button text */
|
||||
--muted: #b2b6bd; /* Cool Gray — captions, tertiary text */
|
||||
--meta: #656a76; /* Dark Gray — helper text, disabled */
|
||||
|
||||
/* ─── Border (2 levels) ──────────────────────────────────────────
|
||||
* DESIGN.md §4 names rgba(178, 182, 189, 0.4) as the primary dark
|
||||
* button border — we lift that exact alpha into --border so
|
||||
* --elev-ring and `border: 1px solid var(--border)` both reproduce
|
||||
* the documented hairline. --border-soft drops to 0.15 for inner
|
||||
* row separators that must not compete with the card edge. */
|
||||
--border: rgba(178, 182, 189, 0.4); /* Cool Gray @ 0.4 — primary button edge */
|
||||
--border-soft: rgba(178, 182, 189, 0.15); /* inner separator — barely-there */
|
||||
|
||||
/* ─── Accent ─────────────────────────────────────────────────────
|
||||
* Action Blue — the corporate brand's single functional CTA color
|
||||
* on dark. Hard cap of ≤2 visible uses per screen aligns with
|
||||
* DESIGN.md §7's restraint: the multi-product palette (Terraform
|
||||
* purple, Vault yellow) is product-scoped and intentionally does
|
||||
* NOT bind here. Hover LIFTS to Bright Blue rather than darkening
|
||||
* (the schema default would lose contrast on dark). */
|
||||
--accent: #1060ff; /* Action Blue — primary CTA on dark */
|
||||
--accent-on: #ffffff; /* white label on saturated blue */
|
||||
--accent-hover: #2b89ff; /* Bright Blue — DESIGN.md §2 active links */
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||||
|
||||
/* ─── Semantic ───────────────────────────────────────────────────
|
||||
* --warn overrides to DESIGN.md §2 Amber #bb5a00 (the schema's
|
||||
* #eab308 would read as "Vault product color" on a HashiCorp
|
||||
* surface). --success and --danger inherit the schema defaults —
|
||||
* DESIGN.md does not define a brand-specific success color, and
|
||||
* #731e25 (DESIGN.md's documented red) is a deep error-background
|
||||
* tone, not the foreground signal a --danger token needs. */
|
||||
--success: #16a34a;
|
||||
--warn: #bb5a00; /* DESIGN.md Amber-200 — warning states */
|
||||
--danger: #dc2626;
|
||||
|
||||
/* ─── Typography ─────────────────────────────────────────────────
|
||||
* Brand/system split per DESIGN.md §3. HashiCorp Sans is the
|
||||
* heading face; system-ui handles body, navigation, and functional
|
||||
* text. The fallback chains let artifacts render acceptably when
|
||||
* the custom face is not loaded. */
|
||||
--font-display: "HashiCorp Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale — DESIGN.md §3 Hierarchy table. The 8 schema slots
|
||||
* map the HashiCorp Sans display tiers (82/52/42/26) plus the
|
||||
* documented body/caption sizes (20/16/14/13). Sub-heading 34px
|
||||
* and small-title 19px live inline in components when needed. */
|
||||
--text-xs: 13px; /* caption / uppercase label */
|
||||
--text-sm: 14px; /* small body */
|
||||
--text-base: 16px; /* body / nav / button text */
|
||||
--text-lg: 20px; /* body large / hero description */
|
||||
--text-xl: 26px; /* card title */
|
||||
--text-2xl: 42px; /* feature heading */
|
||||
--text-3xl: 52px; /* section heading */
|
||||
--text-4xl: 82px; /* display hero — "infrastructure-grade" */
|
||||
|
||||
/* DESIGN.md §3: tight headings (1.17–1.21) over relaxed body
|
||||
* (1.50–1.69). We sit at the documented endpoints — 1.17 hero,
|
||||
* 1.63 body. --tracking-display is `normal` because DESIGN.md §3
|
||||
* lists the 82px hero at letter-spacing `normal` (kerning is on
|
||||
* via font-feature-settings, not tracking). */
|
||||
--leading-body: 1.63;
|
||||
--leading-tight: 1.17;
|
||||
--tracking-display: normal;
|
||||
|
||||
/* ─── Spacing ────────────────────────────────────────────────────
|
||||
* 8px base unit (DESIGN.md §5). The 4/8/12/16/20/24/32/48 tier
|
||||
* covers structural rhythm; sub-tier increments (2/3/6/7/9/11)
|
||||
* live per-component because they are too fine for the shared
|
||||
* schema. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5 "Enterprise breathing room
|
||||
* (48–80px+)". 80px desktop sits at the documented top end;
|
||||
* we collapse to 56px on tablet and 40px on phone. */
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 56px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
/* ─── Radius ─────────────────────────────────────────────────────
|
||||
* DESIGN.md §5 caps radius at 8px and uses 5px for buttons/inputs/
|
||||
* badges. --radius-lg sits at the 8px ceiling (no third tier
|
||||
* exists in the brand). --radius-pill binds to 5px because
|
||||
* DESIGN.md §4 explicitly says "Badges / Pills — Radius: 5px" —
|
||||
* HashiCorp does not have a true 9999px pill shape; the no-pill
|
||||
* rule is structural. */
|
||||
--radius-sm: 5px; /* DESIGN.md "Comfortable" — buttons, inputs */
|
||||
--radius-md: 8px; /* DESIGN.md "Card" — cards, containers */
|
||||
--radius-lg: 8px; /* same 8px ceiling — no third tier */
|
||||
--radius-pill: 5px; /* DESIGN.md §4 — no true pills, 5px chips */
|
||||
|
||||
/* ─── Elevation (3 levels) ───────────────────────────────────────
|
||||
* Whisper shadows VERBATIM from DESIGN.md §6 Level 1: dual-layer
|
||||
* at 5% opacity on a cool-gray (97, 104, 117) base. The doc is
|
||||
* emphatic: "If you can see the shadow, it's too strong." Never
|
||||
* strengthen these values in component overrides. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised:
|
||||
rgba(97, 104, 117, 0.05) 0px 1px 1px,
|
||||
rgba(97, 104, 117, 0.05) 0px 2px 2px;
|
||||
|
||||
/* ─── Focus ring ─────────────────────────────────────────────────
|
||||
* DESIGN.md §6 Level 2: "3px solid var(--mds-color-focus-action-
|
||||
* external)". Sharp 3px ring at --accent, not the schema's alpha
|
||||
* glow — HashiCorp's focus is engineered, not atmospheric. */
|
||||
--focus-ring: 0 0 0 3px var(--accent);
|
||||
|
||||
/* ─── Motion ─────────────────────────────────────────────────────
|
||||
* Standard durations — HashiCorp's enterprise tone leans on type
|
||||
* and shadow restraint, not motion choreography. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────────────
|
||||
* 1150px max content width per DESIGN.md §5 ("Max content width:
|
||||
* ~1150px (xl breakpoint)"). Gutters narrow on mobile to preserve
|
||||
* the line-length-as-craft feel. */
|
||||
--container-max: 1150px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
557
design-systems/intercom/components.html
Normal file
557
design-systems/intercom/components.html
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Intercom — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/intercom. Warm cream canvas,
|
||||
80px Saans display with -2.4px tracking, Fin Orange (#ff5600) accent,
|
||||
sharp 4px radius, scale(1.1) hover."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #faf9f6;
|
||||
--surface: #ffffff;
|
||||
--surface-warm: #faf9f6;
|
||||
|
||||
--fg: #111111;
|
||||
--fg-2: var(--fg);
|
||||
--muted: #7b7b78;
|
||||
--meta: #9c9fa5;
|
||||
|
||||
--border: #dedbd6;
|
||||
--border-soft: #ebe9e4;
|
||||
|
||||
--accent: #ff5600;
|
||||
--accent-on: #ffffff;
|
||||
--accent-hover: color-mix(in oklab, var(--accent), black 8%);
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||||
|
||||
--success: #00da00;
|
||||
--warn: #eab308;
|
||||
--danger: #c41c1c;
|
||||
|
||||
--font-display: "Saans", "Saans Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
|
||||
--font-body: "Saans", "Saans Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
|
||||
--font-mono: "SaansMono", "SaansMono Fallback", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 20px;
|
||||
--text-xl: 24px;
|
||||
--text-2xl: 32px;
|
||||
--text-3xl: 54px;
|
||||
--text-4xl: 80px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0;
|
||||
--tracking-display: -0.03em;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 48px;
|
||||
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 6px;
|
||||
--radius-lg: 8px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 2px 8px color-mix(in oklab, var(--fg), transparent 94%);
|
||||
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--container-gutter-desktop); }
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — Saans, 1.00 leading, negative tracking ─ */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-tight);
|
||||
color: var(--fg);
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: var(--text-4xl);
|
||||
letter-spacing: var(--tracking-display);
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-3xl);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-xl);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
h1 { font-size: var(--text-3xl); }
|
||||
h2 { font-size: var(--text-2xl); }
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--fg);
|
||||
line-height: 1.4;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
.meta { color: var(--meta); font-size: var(--text-sm); }
|
||||
|
||||
/* SaansMono uppercase eyebrow — DESIGN.md §3 mono-label voice */
|
||||
.eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stack-2 > * + * { margin-block-start: var(--space-2); }
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-5 > * + * { margin-block-start: var(--space-5); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — sharp 4px corners, scale(1.1) hover ─────── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 12px 18px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
transform-origin: center;
|
||||
transition:
|
||||
background-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard),
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
transform var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
.btn:active { transform: scale(0.92); }
|
||||
|
||||
/* Primary: Off Black background — the Intercom dark-button move */
|
||||
.btn-primary {
|
||||
background: var(--fg);
|
||||
color: #ffffff;
|
||||
border-color: var(--fg);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: #ffffff;
|
||||
color: var(--fg);
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
/* Outlined: hairline over the warm canvas */
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
border-color: var(--fg);
|
||||
}
|
||||
.btn-outline:hover {
|
||||
background: var(--fg);
|
||||
color: #ffffff;
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
/* Accent: Fin Orange — primary AI / brand moments only */
|
||||
.btn-accent {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.btn-accent:hover {
|
||||
background: var(--accent-hover);
|
||||
border-color: var(--accent-hover);
|
||||
transform: scale(1.04);
|
||||
}
|
||||
.btn-accent:active { background: var(--accent-active); }
|
||||
|
||||
/* ─── Inputs — oat borders, accent focus ─────────────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--fg);
|
||||
}
|
||||
.field input {
|
||||
padding: 14px 16px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: 1.25;
|
||||
outline: none;
|
||||
transition:
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input::placeholder { color: var(--meta); }
|
||||
.field input:hover { border-color: color-mix(in oklab, var(--border), black 10%); }
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field-help { font-size: var(--text-xs); color: var(--muted); }
|
||||
|
||||
/* ─── Cards — warm cream surface, oat border, no shadow ── */
|
||||
.card {
|
||||
background: var(--surface-warm);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
transition:
|
||||
border-color var(--motion-base) var(--ease-standard),
|
||||
box-shadow var(--motion-base) var(--ease-standard);
|
||||
}
|
||||
.card:hover {
|
||||
border-color: color-mix(in oklab, var(--border), black 12%);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
.card-eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.card h3 { font-size: var(--text-2xl); letter-spacing: -0.03em; }
|
||||
|
||||
/* ─── Badges ────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex; align-items: center; gap: var(--space-2);
|
||||
padding: 4px var(--space-3);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
font-family: var(--font-mono);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.badge-success { color: var(--success); background: color-mix(in oklab, var(--success), transparent 88%); }
|
||||
.badge-accent { color: var(--accent); background: color-mix(in oklab, var(--accent), transparent 90%); }
|
||||
.badge-muted { color: var(--muted); background: color-mix(in oklab, var(--muted), transparent 88%); }
|
||||
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
/* ─── Links ─────────────────────────────────────────────── */
|
||||
a { color: var(--fg); text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: 1px; text-decoration-color: var(--border); }
|
||||
a:hover { text-decoration-color: var(--accent); color: var(--accent); }
|
||||
|
||||
kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
padding: 3px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Hero — billboard grid ─────────────────────────────── */
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: end;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.hero-grid { grid-template-columns: 1fr; gap: var(--space-8); align-items: start; }
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex; gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Messenger-style preview panel — Intercom's conversational signature */
|
||||
.messenger {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-5);
|
||||
display: flex; flex-direction: column; gap: var(--space-4);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
.messenger-header {
|
||||
display: flex; align-items: center; gap: var(--space-3);
|
||||
padding-block-end: var(--space-3);
|
||||
border-bottom: 1px solid var(--border-soft);
|
||||
}
|
||||
.messenger-avatar {
|
||||
width: 36px; height: 36px;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.messenger-name {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--fg);
|
||||
line-height: 1.2;
|
||||
}
|
||||
.messenger-status {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
line-height: 1.2;
|
||||
margin-block-start: 2px;
|
||||
}
|
||||
.bubble {
|
||||
max-width: 86%;
|
||||
padding: 10px 14px;
|
||||
font-size: var(--text-sm);
|
||||
line-height: 1.4;
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
.bubble-in {
|
||||
align-self: flex-start;
|
||||
background: var(--surface-warm);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--border-soft);
|
||||
border-bottom-left-radius: var(--radius-sm);
|
||||
}
|
||||
.bubble-out {
|
||||
align-self: flex-end;
|
||||
background: var(--fg);
|
||||
color: #ffffff;
|
||||
border-bottom-right-radius: var(--radius-sm);
|
||||
}
|
||||
.messenger-input {
|
||||
margin-block-start: var(--space-2);
|
||||
padding: 10px 14px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--meta);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
/* ─── Features grid ─────────────────────────────────────── */
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
|
||||
/* ─── Form section ──────────────────────────────────────── */
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; gap: var(--space-8); } }
|
||||
.form {
|
||||
display: flex; flex-direction: column; gap: var(--space-4);
|
||||
max-width: 460px;
|
||||
padding: var(--space-6);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
.form-actions {
|
||||
display: flex; gap: var(--space-3);
|
||||
margin-block-start: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-5">
|
||||
<p class="eyebrow">Reference fixture · intercom</p>
|
||||
<h1>AI-first customer service, built on real conversations.</h1>
|
||||
<p class="lead" style="max-width: 56ch">
|
||||
Fin handles the routine questions instantly, your team handles the rest.
|
||||
One platform for every message — chat, email, phone, ticket — with the
|
||||
warmth of a human and the speed of a machine.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Try Fin free
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-outline">See how it works</a>
|
||||
</div>
|
||||
<p class="meta" style="margin-block-start: var(--space-4)">
|
||||
No credit card · 14-day trial · cancel anytime
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<aside class="messenger" aria-label="Messenger preview">
|
||||
<header class="messenger-header">
|
||||
<span class="messenger-avatar" aria-hidden="true">F</span>
|
||||
<div>
|
||||
<div class="messenger-name">Fin</div>
|
||||
<div class="messenger-status">
|
||||
<span class="badge badge-success" style="padding: 2px 8px">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Online
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="stack-2" style="display: flex; flex-direction: column; gap: var(--space-2)">
|
||||
<div class="bubble bubble-in">Hi there — how can I help today?</div>
|
||||
<div class="bubble bubble-out">Where do I update my billing address?</div>
|
||||
<div class="bubble bubble-in">
|
||||
Settings → Billing → Payment details. Want me to open it for you?
|
||||
</div>
|
||||
</div>
|
||||
<div class="messenger-input" role="presentation">Write a reply…</div>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 22ch">A conversational system, not a help-desk form.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card">
|
||||
<p class="card-eyebrow">Fin AI</p>
|
||||
<h3>Answers in seconds</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Trained on your help center, past conversations, and product docs.
|
||||
Resolves up to 50% of queries with no human escalation.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect tokens →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<p class="card-eyebrow">Inbox</p>
|
||||
<h3>One thread per customer</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Chat, email, phone, and social messages collapse into a single
|
||||
conversation — your team never asks the customer to repeat themselves.
|
||||
</p>
|
||||
<a href="./DESIGN.md" class="body-sm">Read the spec →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<p class="card-eyebrow">Workflows</p>
|
||||
<h3>Sharp by design</h3>
|
||||
<p class="body-muted body-sm">
|
||||
4px button corners, oat-tone borders, 80px Saans display with
|
||||
-2.4px tracking — the system insists on precision.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect type →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Get started</p>
|
||||
<h2>Install the Messenger in three minutes.</h2>
|
||||
<p class="body-muted" style="max-width: 48ch">
|
||||
Drop one script into your site, point Fin at your help center, and
|
||||
the conversation surface is live. No backend rewrites, no design audit.
|
||||
</p>
|
||||
<p class="meta">
|
||||
Press <kbd>⌘</kbd> <kbd>K</kbd> anywhere to search the docs.
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Work email</label>
|
||||
<input id="email" type="email" placeholder="you@company.com" autocomplete="email" required />
|
||||
<p class="field-help">We'll send setup steps and nothing else.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="company">Company</label>
|
||||
<input id="company" type="text" placeholder="Acme, Inc." autocomplete="organization" />
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-accent">
|
||||
Start free trial
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline">Talk to sales</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
150
design-systems/intercom/tokens.css
Normal file
150
design-systems/intercom/tokens.css
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/intercom/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by Intercom".
|
||||
* Editorial customer-service warmth: warm cream canvas, off-black text,
|
||||
* a single Fin Orange signal, and aggressively sharp 4px geometry.
|
||||
*
|
||||
* Key brand decisions encoded here:
|
||||
* - Warm Cream (#faf9f6) canvas — never pure white, but white pops above it
|
||||
* - Fin Orange (#ff5600) — the SINGULAR accent, named after Intercom's AI agent
|
||||
* - Off Black (#111111) — warmer than #000, primary text + dark buttons
|
||||
* - Oat (#dedbd6) borders — warm-tinted, never cool gray
|
||||
* - Saans display: 80px at line-height 1.0 with -2.4px (≈ -0.03em) tracking
|
||||
* - Sharp 4px radius — near-rectangular buttons are the geometric identity
|
||||
*
|
||||
* The "vivid purple/blue" hint sometimes associated with Intercom is the
|
||||
* legacy Messenger SDK palette. The current intercom.com identity is
|
||||
* warm-neutral + Fin Orange (see DESIGN.md §1, §2, §9), and that is what
|
||||
* this token set encodes.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* Warm cream is the foundation — Intercom's website never uses pure
|
||||
* white as the page background. Pure white IS used for the "lifted"
|
||||
* surface tier so cards and panels punch above the warm canvas.
|
||||
* --surface-warm holds the warm-cream value for any component that
|
||||
* wants the warm tier explicitly (cards-on-warm-canvas pattern). */
|
||||
--bg: #faf9f6; /* Warm Cream — the editorial canvas */
|
||||
--surface: #ffffff; /* Pure White — lifted card / panel tier */
|
||||
--surface-warm: #faf9f6; /* Warm Cream — DESIGN.md §4 warm-card pattern */
|
||||
|
||||
/* ─── Foreground ──────────────────────────────────────────────────
|
||||
* Off Black is warmer than #000 — pure black would read harsh against
|
||||
* the warm canvas. DESIGN.md describes a single off-black heading
|
||||
* weight; --fg-2 aliases --fg because the brand expresses hierarchy
|
||||
* through size and tracking, not through tonal text variation. */
|
||||
--fg: #111111; /* Off Black — primary text, dark buttons */
|
||||
--fg-2: var(--fg); /* alias — single heading color throughout */
|
||||
--muted: #7b7b78; /* Black 50 — warm muted text */
|
||||
--meta: #9c9fa5; /* Content Tertiary — captions, metadata */
|
||||
|
||||
/* ─── Border ──────────────────────────────────────────────────────
|
||||
* Oat is THE Intercom border — warm-tinted, never cool gray. The
|
||||
* DESIGN.md "don't" list explicitly forbids cool grays. --border-soft
|
||||
* is a lighter oat for inner row separators that must not compete
|
||||
* with the primary card edge. */
|
||||
--border: #dedbd6; /* Oat — warm card edge */
|
||||
--border-soft: #ebe9e4; /* Lighter oat — inner row separators */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* Fin Orange — named after Intercom's AI agent, the SINGLE chromatic
|
||||
* move against the warm-neutral palette. DESIGN.md §7 forbids
|
||||
* decorative use: reserve for primary CTAs and AI/brand moments. */
|
||||
--accent: #ff5600; /* Fin Orange */
|
||||
--accent-on: #ffffff;
|
||||
--accent-hover: color-mix(in oklab, var(--accent), black 8%);
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||||
|
||||
/* ─── Semantic ────────────────────────────────────────────────────
|
||||
* Pulled from DESIGN.md §2 "Report Palette" so semantic states land
|
||||
* inside the brand vocabulary (green, red), with the schema warn
|
||||
* default for amber. */
|
||||
--success: #00da00; /* Green from report palette */
|
||||
--warn: #eab308;
|
||||
--danger: #c41c1c; /* Report Red */
|
||||
|
||||
/* ─── Typography ──────────────────────────────────────────────────
|
||||
* Saans is Intercom's custom geometric sans — falls back through
|
||||
* Saans Fallback and then through the system ui-sans-serif chain so
|
||||
* artifacts render legibly even when Saans is not loaded. SaansMono
|
||||
* for code and uppercase technical labels (DESIGN.md §3). */
|
||||
--font-display: "Saans", "Saans Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
|
||||
--font-body: "Saans", "Saans Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
|
||||
--font-mono: "SaansMono", "SaansMono Fallback", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
|
||||
|
||||
/* Type scale — DESIGN.md §3 hierarchy: 80 / 54 / 40 / 32 / 24 / 20
|
||||
* down to 14 / 12. The 80px display with -2.4px tracking and 1.00
|
||||
* line-height is the billboard identity. */
|
||||
--text-xs: 12px; /* Mono labels, eyebrows */
|
||||
--text-sm: 14px; /* Body Light, button small */
|
||||
--text-base: 16px; /* Body, button */
|
||||
--text-lg: 20px; /* Body Emphasis */
|
||||
--text-xl: 24px; /* Feature Title */
|
||||
--text-2xl: 32px; /* Card Title */
|
||||
--text-3xl: 54px; /* Section Heading */
|
||||
--text-4xl: 80px; /* Display Hero — billboard scale */
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.0; /* 1.00 across all heading sizes — ultra-compressed */
|
||||
--tracking-display: -0.03em; /* ≈ -2.4px at 80px — aggressive negative tracking */
|
||||
|
||||
/* ─── Spacing ─────────────────────────────────────────────────────
|
||||
* 4px-grid base scale. DESIGN.md §5 lists 8/10/12/14/16/20/24/32/
|
||||
* 40/48/60/64/80/96; the intermediate 10/14/40/60 tiers are
|
||||
* component-internal and not part of the shared schema. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5 documents 80–96px between sections
|
||||
* desktop. Generous editorial whitespace is part of the magazine-
|
||||
* like reading experience. */
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 48px;
|
||||
|
||||
/* ─── Radius ──────────────────────────────────────────────────────
|
||||
* Sharp geometry is the identity. DESIGN.md §7 "Don't" list:
|
||||
* "Don't round buttons beyond 4px". The radius scale tops out at
|
||||
* 8px for cards. No softness. */
|
||||
--radius-sm: 4px; /* Buttons — near-rectangular */
|
||||
--radius-md: 6px; /* Nav items */
|
||||
--radius-lg: 8px; /* Cards, containers */
|
||||
--radius-pill: 9999px; /* Badges, status dots */
|
||||
|
||||
/* ─── Elevation ───────────────────────────────────────────────────
|
||||
* Minimal shadows (DESIGN.md §6). Depth comes from warm borders and
|
||||
* surface tints. The raised tier is a near-invisible whisper using
|
||||
* the warm fg as the shadow color so it tints rather than greys. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 2px 8px color-mix(in oklab, var(--fg), transparent 94%);
|
||||
|
||||
/* ─── Focus ring ──────────────────────────────────────────────────
|
||||
* Orange-tinted to match the Fin accent — keeps keyboard focus
|
||||
* inside the brand voice rather than borrowing browser blue. */
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||||
|
||||
/* ─── Motion ──────────────────────────────────────────────────────
|
||||
* Schema defaults — Intercom's signature interaction is scale(1.1)
|
||||
* hover, which lives in components (button :hover transform), not
|
||||
* in the motion duration tokens. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ──────────────────────────────────────────────────────
|
||||
* 1280px container — comfortable editorial width that accommodates
|
||||
* the 80px display headlines without crowding. */
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
441
design-systems/lovable/components.html
Normal file
441
design-systems/lovable/components.html
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Lovable — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/lovable. Warm parchment canvas
|
||||
(#f7f4ed), opacity-driven gray ramp from charcoal #1c1c1c, Camera Plain
|
||||
Variable display type with -1.5px tracking, borders-not-shadows for cards,
|
||||
the signature inset-shadow on dark CTAs."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f7f4ed;
|
||||
--surface: #f7f4ed;
|
||||
--surface-warm: var(--surface);
|
||||
|
||||
--fg: #1c1c1c;
|
||||
--fg-2: rgba(28, 28, 28, 0.83);
|
||||
--muted: #5f5f5d;
|
||||
--meta: rgba(28, 28, 28, 0.4);
|
||||
|
||||
--border: #eceae4;
|
||||
--border-soft: var(--border);
|
||||
|
||||
--accent: #ff4d8d;
|
||||
--accent-on: #ffffff;
|
||||
--accent-hover: color-mix(in oklab, var(--accent), black 8%);
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||||
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
--font-display: "Camera Plain Variable", "Camera Plain", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-body: "Camera Plain Variable", "Camera Plain", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 18px;
|
||||
--text-xl: 20px;
|
||||
--text-2xl: 36px;
|
||||
--text-3xl: 48px;
|
||||
--text-4xl: 60px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.10;
|
||||
--tracking-display: -0.025em;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 128px;
|
||||
--section-y-tablet: 80px;
|
||||
--section-y-phone: 64px;
|
||||
|
||||
--radius-sm: 6px;
|
||||
--radius-md: 12px;
|
||||
--radius-lg: 16px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
|
||||
--focus-ring: 0 0 0 2px rgba(59, 130, 246, 0.5);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — Camera Plain Variable carries the personality ─ */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
line-height: var(--leading-tight);
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--tracking-display); /* -1.5px @ 60px */
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em; /* -1.2px @ 48px (DESIGN.md §3) */
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400; /* card titles stay 400 */
|
||||
letter-spacing: normal;
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--muted);
|
||||
line-height: 1.38; /* DESIGN.md §3 Body Large */
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
.eyebrow {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
font-weight: 400;
|
||||
letter-spacing: normal; /* Lovable does NOT track up labels */
|
||||
}
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — inset-shadow CTA, ghost outline, pill action ─ */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 8px var(--space-4); /* DESIGN.md §4: 8px 16px */
|
||||
border-radius: var(--radius-sm); /* 6px — functional radius */
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 400; /* DESIGN.md §3: buttons 400 */
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
text-decoration: none;
|
||||
transition: opacity var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard),
|
||||
background-color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:active { opacity: 0.8; } /* DESIGN.md §4 active feedback */
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
|
||||
/* Primary Dark — the signature inset-shadow CTA from DESIGN.md §4 */
|
||||
.btn-primary {
|
||||
background: var(--fg);
|
||||
color: #fcfbf8; /* off-white per DESIGN.md §2 */
|
||||
box-shadow:
|
||||
inset 0 0.5px 0 rgba(255, 255, 255, 0.2),
|
||||
inset 0 0 0 0.5px rgba(0, 0, 0, 0.2),
|
||||
0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
box-shadow:
|
||||
inset 0 0.5px 0 rgba(255, 255, 255, 0.2),
|
||||
inset 0 0 0 0.5px rgba(0, 0, 0, 0.2),
|
||||
0 4px 12px rgba(0, 0, 0, 0.1); /* the warm focus shadow */
|
||||
}
|
||||
|
||||
/* Ghost / Outline — DESIGN.md §4 secondary actions */
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--meta); /* charcoal-40% interactive border */
|
||||
}
|
||||
.btn-ghost:hover {
|
||||
background: rgba(28, 28, 28, 0.04); /* charcoal-4% subtle hover */
|
||||
}
|
||||
|
||||
/* ─── Inputs — warm cream surface, soft cream border ─────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label { font-size: var(--text-sm); font-weight: 400; }
|
||||
.field input,
|
||||
.field textarea {
|
||||
padding: var(--space-3) var(--space-4);
|
||||
border-radius: var(--radius-sm); /* 6px — DESIGN.md §4 inputs */
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
outline: none;
|
||||
transition: box-shadow var(--motion-fast) var(--ease-standard),
|
||||
border-color var(--motion-fast) var(--ease-standard);
|
||||
resize: vertical;
|
||||
}
|
||||
.field input::placeholder,
|
||||
.field textarea::placeholder { color: var(--muted); }
|
||||
.field input:focus-visible,
|
||||
.field textarea:focus-visible {
|
||||
box-shadow: var(--focus-ring); /* 2px ring blue, accessibility */
|
||||
}
|
||||
.field-help { font-size: var(--text-sm); color: var(--muted); }
|
||||
|
||||
/* ─── Cards — borders define edges, NOT shadows ──────────── */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md); /* 12px — DESIGN.md §4 cards */
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
box-shadow: var(--elev-flat); /* explicit: no shadow on cards */
|
||||
transition: border-color var(--motion-base) var(--ease-standard);
|
||||
}
|
||||
.card:hover { border-color: rgba(28, 28, 28, 0.12); } /* subtle darken on hover */
|
||||
|
||||
/* ─── Pills & badges — action pill (9999px) per §4 ────────── */
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 6px var(--space-3);
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--border);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
.pill-dot {
|
||||
width: 6px; height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent); /* the brand pink, used sparingly */
|
||||
}
|
||||
|
||||
/* ─── Links — underline carries the signal, NOT color ────── */
|
||||
a {
|
||||
color: var(--fg);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
text-decoration-thickness: 1px;
|
||||
}
|
||||
a:hover { color: var(--accent); } /* hsl(var(--primary)) per §4 */
|
||||
|
||||
kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Layout helpers ────────────────────────────────────── */
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: end;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.hero-grid { grid-template-columns: 1fr; gap: var(--space-8); }
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.hero-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-4);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
}
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 460px; }
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); flex-wrap: wrap; }
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Reference fixture · lovable</p>
|
||||
<h1>Describe your app.<br />Lovable builds it.</h1>
|
||||
<p class="lead" style="max-width: 52ch">
|
||||
Type a sentence in plain language and watch your idea become a working
|
||||
web app — no setup, no boilerplate, just a preview that updates as you
|
||||
tinker. Built warm, on cream, never on cold white.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Start building
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="1.75"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-ghost">Read the spec</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-meta" aria-label="Build status">
|
||||
<div class="row-between">
|
||||
<span class="body-sm">Preview</span>
|
||||
<span class="pill">
|
||||
<span class="pill-dot" aria-hidden="true"></span>
|
||||
Live
|
||||
</span>
|
||||
</div>
|
||||
<p class="body-sm" style="color: var(--muted)">
|
||||
Last revised <time datetime="2026-05-15">2026-05-15</time> · v1.0
|
||||
</p>
|
||||
<p class="body-sm" style="color: var(--muted)">
|
||||
Press <kbd>⌘</kbd> <kbd>K</kbd> to open the prompt.
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 22ch">Warmth as a system, not a coat of paint.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card">
|
||||
<h3>Cream-on-cream depth</h3>
|
||||
<p class="body-muted body-sm">
|
||||
--bg and --surface are the same warm parchment (#f7f4ed). The 1px
|
||||
#eceae4 border carries the containment — Lovable's depth model is
|
||||
borders, never drop-shadows on cards.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect tokens →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Camera Plain humanism</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Display type runs at 60px / weight 600 / -1.5px tracking. The
|
||||
variable axis lets weight 480 sit between regular and semibold
|
||||
for editorial moments. Body stays at 400, normal tracking.
|
||||
</p>
|
||||
<a href="./DESIGN.md" class="body-sm">Read the rule →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Inset, not lifted</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Dark CTAs press into the cream with a multi-layer inset shadow:
|
||||
white highlight at 0.5px, dark ring at 0.5px, soft drop at 1px.
|
||||
The button feels pressed-into-paper, not floated above it.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect shadow →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Try it</p>
|
||||
<h2>Start with a sentence.</h2>
|
||||
<p class="body-muted" style="max-width: 48ch">
|
||||
The whole product begins from one prompt — the input below uses the
|
||||
same warm cream surface, the same #eceae4 border, the same Tailwind
|
||||
ring blue at 50% for keyboard focus. Form is page is craft.
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="prompt">What do you want to build?</label>
|
||||
<textarea
|
||||
id="prompt"
|
||||
rows="3"
|
||||
placeholder="A todo app that syncs with my calendar and reminds me on my watch."
|
||||
required
|
||||
></textarea>
|
||||
<p class="field-help">Plain language is fine — Lovable handles the scaffolding.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Build my app</button>
|
||||
<button type="button" class="btn btn-ghost">See examples</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
258
design-systems/lovable/tokens.css
Normal file
258
design-systems/lovable/tokens.css
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/lovable/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by Lovable".
|
||||
* Warm parchment canvas, opacity-driven gray ramp, humanist Camera Plain
|
||||
* Variable display type, borders-not-shadows for cards, inset-shadow
|
||||
* tactility on dark CTAs.
|
||||
*
|
||||
* This file pre-compiles the values described in `DESIGN.md` into the
|
||||
* shared schema. Agents generating an artifact for Lovable should paste
|
||||
* the `:root` block verbatim into the first `<style>` of the artifact,
|
||||
* then reference everything via `var(--*)`.
|
||||
*
|
||||
* Brand-specific schema decisions (each one bends a schema convention
|
||||
* to match Lovable's voice rather than the cross-brand default):
|
||||
*
|
||||
* 1. `--bg` and `--surface` BOTH bind to `#f7f4ed` (Cream). DESIGN.md
|
||||
* §4 is explicit: "Cards… background: #f7f4ed (matches page) — for
|
||||
* seamless integration." Lovable's depth model is borders, not
|
||||
* surface tinting, so a card and the page are the same color and
|
||||
* `#eceae4` border carries the containment. `--surface-warm`
|
||||
* collapses to `var(--surface)` because there is no second warm
|
||||
* tier in the system.
|
||||
*
|
||||
* 2. `--fg` is `#1c1c1c` (Charcoal), not `#000000`. DESIGN.md §1 names
|
||||
* the warmth as deliberate: "Not pure black — organic warmth." The
|
||||
* gray ramp is opacity-driven — every "gray" in the system is the
|
||||
* same charcoal hue at a different alpha — so `--fg-2` binds to
|
||||
* `rgba(28, 28, 28, 0.83)` (the documented "strong secondary text"
|
||||
* tier from §2) and `--meta` binds to `rgba(28, 28, 28, 0.4)`
|
||||
* (the documented "interactive borders / placeholders" tier).
|
||||
* `--muted` keeps the named gray `#5f5f5d` for body descriptions
|
||||
* because that one tier is bound to a hex in DESIGN.md, not to an
|
||||
* opacity stop.
|
||||
*
|
||||
* 3. `--border` is the warm `#eceae4` (Light Cream) divider line.
|
||||
* `--border-soft` aliases to `var(--border)` because Lovable does
|
||||
* not differentiate inner / outer border tiers — DESIGN.md §1 names
|
||||
* a SECOND interactive border at `rgba(28, 28, 28, 0.4)`, but that
|
||||
* is the foreground-meta token (already bound above) used as a
|
||||
* button outline, not a separator-tier border.
|
||||
*
|
||||
* 4. `--accent` is Lovable Pink (`#ff4d8d`), even though primary CTAs
|
||||
* in Lovable are Charcoal (`var(--fg)`). DESIGN.md §6 calls out a
|
||||
* "soft, warm multi-color gradient wash (pinks, oranges, blues)
|
||||
* behind hero" and §4 Links references `hsl(var(--primary))` for
|
||||
* hover — the brand mark itself is a pink → coral gradient. The
|
||||
* accent slot is therefore reserved for the chromatic moments
|
||||
* where the brand pink actually appears (link hover, badge tints,
|
||||
* focus moments on warm controls). components.html encodes the
|
||||
* "primary CTA = Charcoal" pattern via `background: var(--fg)`,
|
||||
* so `--accent` does not get burned on every button.
|
||||
*
|
||||
* 5. `--focus-ring` is the Tailwind ring blue at 50% alpha
|
||||
* (`rgba(59, 130, 246, 0.5)`), NOT a pink/charcoal-derived ring.
|
||||
* DESIGN.md §6 names this verbatim as "Ring (Accessibility):
|
||||
* `rgba(59,130,246,0.5)` 2px ring" — it is the one cool moment in
|
||||
* an otherwise warm palette, justified by accessibility (the warm
|
||||
* pink at low alpha would not pass contrast on the cream canvas).
|
||||
* A 2px sharp ring, not the schema's 3px alpha glow.
|
||||
*
|
||||
* 6. `--elev-raised` is the soft warm focus shadow
|
||||
* (`0 4px 12px rgba(0, 0, 0, 0.1)`) — the same value DESIGN.md §6
|
||||
* lists as "Focus (Level 3)". The signature multi-layer inset
|
||||
* shadow on dark buttons (`rgba(255,255,255,0.2) 0 0.5px 0 inset,
|
||||
* rgba(0,0,0,0.2) 0 0 0 0.5px inset, rgba(0,0,0,0.05) 0 1px 2px`)
|
||||
* is component-specific and lives in components.html — it only
|
||||
* reads on a dark surface, so generalizing it to a token would
|
||||
* mis-paint cards on the cream canvas.
|
||||
*
|
||||
* 7. The type scale tops out at 60px (`--text-4xl`) per DESIGN.md §3
|
||||
* "Display Hero, 60px Camera Plain weight 600". `--leading-tight`
|
||||
* is `1.10` (the documented hero range 1.00–1.10) and
|
||||
* `--tracking-display` is `-0.025em`, the em-relative form of
|
||||
* "-1.5px at 60px" so compression scales proportionally with size.
|
||||
* Body text stays at `normal` tracking — Camera Plain Variable's
|
||||
* humanist warmth wants comfortable reading at 16px.
|
||||
*
|
||||
* 8. Section rhythm is generous: `128px` desktop, `80px` tablet,
|
||||
* `64px` phone (`--section-y-*`). DESIGN.md §5 describes
|
||||
* "lavish at section boundaries (80px–208px)"; we sit in the
|
||||
* mid-range so the cream canvas feels cozy rather than empty.
|
||||
* Container caps at `1200px` (DESIGN.md §5 documented max width).
|
||||
*
|
||||
* Source contracts:
|
||||
* - Standard token names: design-systems/_schema/tokens.schema.ts
|
||||
* - A2 fallback parity: design-systems/_schema/defaults.css
|
||||
* - Lint enforcement: apps/daemon/src/lint-artifact.ts
|
||||
*
|
||||
* Keep this file additive: never invent token names not also documented
|
||||
* in DESIGN.md or the schema. Camera Plain Variable does not need a CDN
|
||||
* reference here — the font stack lists ui-sans-serif / system-ui
|
||||
* fallbacks so artifacts render acceptably even when Camera Plain is
|
||||
* not loaded, and any host that wants the real face links it externally.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* Cream is BOTH page and card background — DESIGN.md §4: "Cards…
|
||||
* background: #f7f4ed (matches page) — for seamless integration".
|
||||
* The warm divider line (#eceae4 border) is what separates a card
|
||||
* from the page, not a different surface color. */
|
||||
--bg: #f7f4ed; /* Cream — warm parchment foundation */
|
||||
--surface: #f7f4ed; /* Cards reuse the canvas — borders contain */
|
||||
--surface-warm: var(--surface); /* alias — Lovable has no second warm tier */
|
||||
|
||||
/* ─── Foreground ──────────────────────────────────────────────────
|
||||
* Charcoal #1c1c1c, never pure black. The gray ramp is opacity-driven:
|
||||
* every "gray" in the system is the same charcoal hue at a different
|
||||
* alpha. --fg-2 binds independently to charcoal-83% (the documented
|
||||
* strong-secondary tier). --muted is the named gray #5f5f5d for
|
||||
* body descriptions / captions. --meta drops to charcoal-40% — the
|
||||
* documented "interactive borders / placeholders" alpha. */
|
||||
--fg: #1c1c1c; /* Charcoal — primary text, dark CTA bg */
|
||||
--fg-2: rgba(28, 28, 28, 0.83); /* Charcoal 83% — strong secondary text */
|
||||
--muted: #5f5f5d; /* Muted Gray — descriptions, captions */
|
||||
--meta: rgba(28, 28, 28, 0.4); /* Charcoal 40% — placeholders, faded UI */
|
||||
|
||||
/* ─── Border ──────────────────────────────────────────────────────
|
||||
* Light Cream #eceae4 is the canonical "warm divider line" — DESIGN.md
|
||||
* §1 names it as the passive border used everywhere cards / images /
|
||||
* sections need containment. --border-soft aliases because Lovable
|
||||
* does not differentiate inner / outer separator tiers; depth comes
|
||||
* from the inset-shadow signature on dark buttons (component-level),
|
||||
* not from border weight. */
|
||||
--border: #eceae4; /* Light Cream — card / image edge */
|
||||
--border-soft: var(--border); /* alias — single border tier */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* Lovable Pink — the brand mark color. DESIGN.md §6 calls out a
|
||||
* "soft, warm multi-color gradient wash (pinks, oranges, blues)"
|
||||
* behind hero, and §4 Links references hsl(var(--primary)) for hover.
|
||||
* Primary CTAs are CHARCOAL (var(--fg)), not pink — components.html
|
||||
* encodes that pattern. --accent is reserved for the chromatic
|
||||
* moments where the brand pink actually appears (link hover, badge
|
||||
* tints, brand mark, soft gradient washes). */
|
||||
--accent: #ff4d8d; /* Lovable Pink — brand mark / chromatic */
|
||||
--accent-on: #ffffff; /* white label on saturated pink */
|
||||
--accent-hover: color-mix(in oklab, var(--accent), black 8%);
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||||
|
||||
/* ─── Semantic ────────────────────────────────────────────────────
|
||||
* Schema defaults — Lovable's marketing surface rarely renders state
|
||||
* and DESIGN.md does not specify warm-shift overrides. Success / warn
|
||||
* / danger remain tonally distinct from the warm-neutral palette so
|
||||
* they read as semantic (not decorative) when they appear. */
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
/* ─── Typography ──────────────────────────────────────────────────
|
||||
* Camera Plain Variable carries the humanist personality — slightly
|
||||
* rounded terminals and organic curves, distinct from the geometric
|
||||
* sans-serifs typical of dev tools. The variable axis enables weight
|
||||
* 480 for special display moments; standard weights are 400 (body /
|
||||
* UI / links / buttons) and 600 (headings / emphasis). The
|
||||
* ui-sans-serif / system-ui fallbacks ensure artifacts render
|
||||
* acceptably even when Camera Plain is not loaded. */
|
||||
--font-display: "Camera Plain Variable", "Camera Plain", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-body: "Camera Plain Variable", "Camera Plain", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale (px) — DESIGN.md §3 hierarchy table. Lovable reads BIG
|
||||
* because of -0.025em (≈ -1.5px @ 60px) tracking compression on
|
||||
* display, not because of an extreme px ceiling. The 18 / 20 / 36 /
|
||||
* 48 / 60 ladder mirrors the documented Body Large → Card Title →
|
||||
* Sub-heading → Section Heading → Display Hero progression. */
|
||||
--text-xs: 12px; /* tiny metadata */
|
||||
--text-sm: 14px; /* caption, link small, button small */
|
||||
--text-base: 16px; /* body, button, link */
|
||||
--text-lg: 18px; /* body large, introductions */
|
||||
--text-xl: 20px; /* card title */
|
||||
--text-2xl: 36px; /* sub-heading */
|
||||
--text-3xl: 48px; /* section heading */
|
||||
--text-4xl: 60px; /* display hero */
|
||||
|
||||
/* `--leading-tight` is 1.10 (the documented hero 1.00–1.10 range);
|
||||
* `--leading-body` is 1.5 (the documented 16px body rhythm).
|
||||
* `--tracking-display` is -0.025em — the em-relative form of
|
||||
* Lovable's "-1.5px at 60px" so the compression scales proportionally
|
||||
* with size. Body stays at normal tracking — Camera Plain's humanist
|
||||
* warmth wants comfortable reading. */
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.10;
|
||||
--tracking-display: -0.025em;
|
||||
|
||||
/* ─── Spacing ─────────────────────────────────────────────────────
|
||||
* 8px base. DESIGN.md §5 names the full scale extending to 208px at
|
||||
* the top end for editorial breathing room — those large tiers are
|
||||
* inlined per-section in components.html (section-y-* below carries
|
||||
* the structural rhythm). The shared schema covers the 4 → 48px
|
||||
* structural ladder. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5: "lavish at section boundaries
|
||||
* (80px–208px)". Sit at 128px desktop (the documented mid-range),
|
||||
* collapse to 80 on tablet and 64 on phone. The cream background
|
||||
* makes these expanses feel cozy rather than empty. */
|
||||
--section-y-desktop: 128px;
|
||||
--section-y-tablet: 80px;
|
||||
--section-y-phone: 64px;
|
||||
|
||||
/* ─── Radius ──────────────────────────────────────────────────────
|
||||
* DESIGN.md §5 radius scale: 4 / 6 / 8 / 12 / 16 / 9999. We bind the
|
||||
* four schema tiers to: 6 (button / input / functional), 12 (card /
|
||||
* image container), 16 (large container / footer), 9999 (action pill,
|
||||
* icon toggle). The 4px and 8px tiers are component-specific and not
|
||||
* part of the shared schema. */
|
||||
--radius-sm: 6px; /* buttons, inputs, functional */
|
||||
--radius-md: 12px; /* cards, image containers */
|
||||
--radius-lg: 16px; /* large containers, footer sections */
|
||||
--radius-pill: 9999px; /* action pills, icon toggles */
|
||||
|
||||
/* ─── Elevation ───────────────────────────────────────────────────
|
||||
* Lovable's depth is intentionally shallow — DESIGN.md §6: "borders
|
||||
* are the containment mechanism, not shadows". Three levels:
|
||||
*
|
||||
* --elev-flat no shadow (page surface, most cards)
|
||||
* --elev-ring the warm 1px border-as-ring (cards, images)
|
||||
* --elev-raised the soft warm focus shadow (active / focused moments)
|
||||
*
|
||||
* The signature multi-layer inset shadow on dark buttons (white-line
|
||||
* highlight at 0.5px inset + dark ring + soft drop) is component-
|
||||
* specific and lives in components.html — it only reads on a dark
|
||||
* surface, so generalizing it would mis-paint cards on cream. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 4px 12px rgba(0, 0, 0, 0.1); /* soft warm focus float */
|
||||
|
||||
/* ─── Focus ring ──────────────────────────────────────────────────
|
||||
* The Tailwind ring blue at 50% — DESIGN.md §6 lists this verbatim
|
||||
* as the keyboard accessibility ring. The one cool moment in an
|
||||
* otherwise warm palette, justified by accessibility (the warm pink
|
||||
* accent at low alpha would not pass contrast on cream). 2px sharp
|
||||
* ring, not the schema's 3px alpha glow. */
|
||||
--focus-ring: 0 0 0 2px rgba(59, 130, 246, 0.5);
|
||||
|
||||
/* ─── Motion ──────────────────────────────────────────────────────
|
||||
* Standard durations — Lovable's tactility is in opacity-on-active
|
||||
* (0.8) and the inset-shadow press, not in timed choreography. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ──────────────────────────────────────────────────────
|
||||
* 1200px max content width per DESIGN.md §5. */
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
737
design-systems/mintlify/components.html
Normal file
737
design-systems/mintlify/components.html
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Mintlify — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/mintlify. White-on-white
|
||||
canvas, near-black text, signature mint accent (#18E299) used
|
||||
sparingly, full-pill buttons / inputs / badges, ultra-subtle 5%
|
||||
opacity borders carrying every separation."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--surface: #ffffff;
|
||||
--surface-warm: #fafafa;
|
||||
|
||||
--fg: #0d0d0d;
|
||||
--fg-2: #333333;
|
||||
--muted: #666666;
|
||||
--meta: #888888;
|
||||
|
||||
--border: rgba(0, 0, 0, 0.05);
|
||||
--border-soft: var(--border);
|
||||
|
||||
--accent: #18E299;
|
||||
--accent-on: #0d0d0d;
|
||||
--accent-hover: #0fa76e;
|
||||
--accent-active: color-mix(in oklab, var(--accent-hover), black 12%);
|
||||
|
||||
--success: #16a34a;
|
||||
--warn: #c37d0d;
|
||||
--danger: #d45656;
|
||||
|
||||
--font-display: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-body: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 18px;
|
||||
--text-xl: 20px;
|
||||
--text-2xl: 24px;
|
||||
--text-3xl: 40px;
|
||||
--text-4xl: 64px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.15;
|
||||
--tracking-display: -0.02em;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 48px;
|
||||
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 16px;
|
||||
--radius-lg: 24px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 2px 4px rgba(0, 0, 0, 0.03);
|
||||
|
||||
--focus-ring: 0 0 0 2px var(--accent);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 32px;
|
||||
--container-gutter-tablet: 24px;
|
||||
--container-gutter-phone: 24px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
font-weight: 400;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* ─── Layout primitives ─────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography ────────────────────────────────────────────
|
||||
* Three weights only — 400 (read), 500 (interact), 600
|
||||
* (announce). Display sizes use --tracking-display; smaller
|
||||
* tiers relax toward 0. Headings drop --leading-tight (1.15)
|
||||
* to ~1.30 inline at the smaller sizes per DESIGN.md §3. */
|
||||
h1, h2, h3, h4 {
|
||||
font-family: var(--font-display);
|
||||
line-height: var(--leading-tight);
|
||||
margin: 0;
|
||||
color: var(--fg);
|
||||
}
|
||||
h1 {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--tracking-display);
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 600;
|
||||
line-height: 1.30;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
h4 {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 500;
|
||||
line-height: 1.30;
|
||||
}
|
||||
p { margin: 0; }
|
||||
|
||||
.lede {
|
||||
font-size: var(--text-lg);
|
||||
line-height: var(--leading-body);
|
||||
color: var(--muted);
|
||||
}
|
||||
.body-muted { color: var(--fg-2); }
|
||||
.body-meta { color: var(--muted); font-size: var(--text-sm); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
|
||||
/* Eyebrow uses Geist Mono uppercase — DESIGN.md §3 names the
|
||||
"terminal voice" for technical labels. Tracked-out 0.65px ≈
|
||||
0.05em at 13px. */
|
||||
.eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-5 > * + * { margin-block-start: var(--space-5); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — full-pill, the signature shape ─────────────
|
||||
* DESIGN.md §4: every CTA is `--radius-pill`. Primary is
|
||||
* BLACK on white (the brand's documented dominant CTA),
|
||||
* secondary is white-on-white with a subtle 8% border, ghost
|
||||
* is transparent for nav use. The "brand-accent" variant is
|
||||
* the rare promotional pill that paints the mint fill with
|
||||
* dark text on top. */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 8px 24px;
|
||||
border: none;
|
||||
border-radius: var(--radius-pill);
|
||||
font-family: var(--font-display);
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
transition:
|
||||
background-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard),
|
||||
opacity var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.btn-primary {
|
||||
background: var(--fg);
|
||||
color: var(--bg);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.btn-primary:hover { opacity: 0.9; }
|
||||
.btn-secondary {
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
padding: 7px 24px;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
opacity: 0.9;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.14);
|
||||
}
|
||||
.btn-accent {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
}
|
||||
.btn-accent:hover { background: var(--accent-hover); color: var(--bg); }
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 5px 12px;
|
||||
}
|
||||
.btn-ghost:hover { color: var(--accent-hover); }
|
||||
|
||||
/* ─── Inputs — full-pill, matches button silhouette ───────── */
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
.field label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--fg);
|
||||
}
|
||||
.field input {
|
||||
padding: 10px 16px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
font-family: inherit;
|
||||
font-size: var(--text-sm);
|
||||
line-height: 1.5;
|
||||
outline: none;
|
||||
transition:
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input::placeholder { color: var(--meta); }
|
||||
.field input:hover { border-color: rgba(0, 0, 0, 0.16); }
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field-help {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Cards — border-defined, whisper shadow ────────────────
|
||||
* DESIGN.md §4: standard card uses 16px radius + 5% border +
|
||||
* the 0.03-alpha shadow whisper. Featured card jumps to 24px
|
||||
* radius + 32px padding. Trust card uses --surface-warm to
|
||||
* tint the logo container away from pure white. */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
box-shadow: var(--elev-raised);
|
||||
transition:
|
||||
border-color var(--motion-base) var(--ease-standard),
|
||||
box-shadow var(--motion-base) var(--ease-standard);
|
||||
}
|
||||
.card:hover {
|
||||
border-color: rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.card-featured {
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-8);
|
||||
}
|
||||
.card-trust {
|
||||
background: var(--surface-warm);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 72px;
|
||||
}
|
||||
|
||||
/* ─── Badges — pill, mint-tinted or muted ────────────────── */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
padding: 4px 12px;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
font-family: var(--font-display);
|
||||
}
|
||||
.badge-mint {
|
||||
color: var(--accent-hover);
|
||||
background: color-mix(in oklab, var(--accent), white 78%);
|
||||
}
|
||||
.badge-muted {
|
||||
color: var(--fg-2);
|
||||
background: var(--surface-warm);
|
||||
box-shadow: 0 0 0 1px var(--border);
|
||||
}
|
||||
.badge-success {
|
||||
color: var(--success);
|
||||
background: color-mix(in oklab, var(--success), white 88%);
|
||||
}
|
||||
.badge-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
}
|
||||
/* Mono uppercase tag — DESIGN.md §3 "Mono Code / Mono Badge".
|
||||
Used for technical / API labels where the "terminal voice"
|
||||
is the right register. */
|
||||
.tag-mono {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 5px 10px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--surface-warm);
|
||||
color: var(--fg-2);
|
||||
box-shadow: 0 0 0 1px var(--border);
|
||||
}
|
||||
|
||||
/* ─── Links ────────────────────────────────────────────────
|
||||
* DESIGN.md §2: "Links match text color, relying on
|
||||
* underline/context. Hover: brand green." Default link is
|
||||
* --fg with underline; hover swaps to brand-green-deep so
|
||||
* the underline stays legible on white. */
|
||||
a {
|
||||
color: var(--fg);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
text-decoration-thickness: 1px;
|
||||
text-decoration-color: rgba(0, 0, 0, 0.20);
|
||||
transition:
|
||||
color var(--motion-fast) var(--ease-standard),
|
||||
text-decoration-color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
a:hover {
|
||||
color: var(--accent-hover);
|
||||
text-decoration-color: var(--accent-hover);
|
||||
}
|
||||
a:focus-visible {
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
|
||||
/* ─── Kbd ──────────────────────────────────────────────── */
|
||||
kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
background: var(--surface-warm);
|
||||
color: var(--fg-2);
|
||||
box-shadow: 0 0 0 1px var(--border);
|
||||
}
|
||||
|
||||
/* ─── Distinctive: Atmospheric hero gradient ───────────────
|
||||
* DESIGN.md §1 + §4 name the "soft, cloud-like green-to-
|
||||
* white gradient wash" as the hero's signature. We layer two
|
||||
* blurred radial tints in the brand mint over the white
|
||||
* background — barely registering as a hue shift, more
|
||||
* "atmospheric intelligence" than overt colour. The wash
|
||||
* fades to var(--bg) before reaching the section edges so
|
||||
* the page stays visually white-on-white. */
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.hero::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -20% -10% 30% -10%;
|
||||
background:
|
||||
radial-gradient(60% 80% at 30% 20%, color-mix(in oklab, var(--accent), var(--bg) 78%) 0%, var(--bg) 70%),
|
||||
radial-gradient(50% 60% at 75% 10%, color-mix(in oklab, var(--accent), var(--bg) 86%) 0%, var(--bg) 75%);
|
||||
filter: blur(40px);
|
||||
opacity: 0.9;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.hero > * { position: relative; z-index: 1; }
|
||||
.hero-eyebrow-row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
.hero h1 { max-width: 18ch; }
|
||||
.hero .lede {
|
||||
max-width: 56ch;
|
||||
margin-block-start: var(--space-5);
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-8);
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.hero-meta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
color: var(--muted);
|
||||
font-size: var(--text-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ─── Trust bar — DESIGN.md §4 "Loved by your favorite
|
||||
companies". A horizontal grid of muted logo containers,
|
||||
each on the warm surface tint with the signature 5%
|
||||
border. We render text wordmarks instead of real logos
|
||||
to keep the fixture self-contained. */
|
||||
.trust {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-8);
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.trust { grid-template-columns: repeat(3, 1fr); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.trust { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
.trust-mark {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Feature cards grid ──────────────────────────────────── */
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
margin-block-start: var(--space-8);
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.features-grid { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.features-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
.feature-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: var(--radius-pill);
|
||||
background: color-mix(in oklab, var(--accent), white 78%);
|
||||
color: var(--accent-hover);
|
||||
margin-block-end: var(--space-2);
|
||||
}
|
||||
.feature-icon svg { width: 18px; height: 18px; }
|
||||
|
||||
/* ─── Form card section ───────────────────────────────────── */
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
margin-block-start: var(--space-8);
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.form-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
max-width: 440px;
|
||||
padding: var(--space-6);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-2);
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.row-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<!-- ════════════════════════════════════════════════════════════
|
||||
HERO — exercises: atmospheric mint-on-white gradient wash
|
||||
(DESIGN.md §1 hero signature), h1 at 64px Inter W600 with
|
||||
-0.02em (≈ -1.28px) tracking, .lede in --muted, dual full-
|
||||
pill CTAs (.btn-primary black + .btn-secondary white), kbd
|
||||
hint and .badge-mint status pill. The gradient layers two
|
||||
blurred radial tints in the brand green over the white
|
||||
bg so it reads as "documentation that floats above the
|
||||
noise" without overpowering the page.
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="hero" data-od-id="hero">
|
||||
<div class="hero-eyebrow-row">
|
||||
<span class="tag-mono">v1.0 · stable</span>
|
||||
<p class="eyebrow">Reference fixture · mintlify</p>
|
||||
</div>
|
||||
<h1 style="margin-block-start: var(--space-6)">The documentation your users will love.</h1>
|
||||
<p class="lede">
|
||||
A token block distilled from Mintlify's published design system —
|
||||
Inter with tight -0.02em display tracking, full-pill buttons and
|
||||
inputs, mint accent used sparingly, and 5%-opacity hairlines
|
||||
carrying every section break. The fixture you are reading paints
|
||||
from the same <code style="font-family: var(--font-mono); font-size: 0.95em">:root</code>
|
||||
block agents inline into every Mintlify artifact.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
View tokens
|
||||
<svg
|
||||
class="icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.75"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M5 12h14M13 6l6 6-6 6" />
|
||||
</svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-secondary">Read the spec</a>
|
||||
<a href="#features" class="btn btn-ghost">Skip to components</a>
|
||||
</div>
|
||||
<p class="hero-meta">
|
||||
<span class="badge badge-mint">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
56 tokens · 0 C-extensions
|
||||
</span>
|
||||
<span>Press <kbd>⌘</kbd> <kbd>K</kbd> to search the docs.</span>
|
||||
</p>
|
||||
|
||||
<div class="trust" aria-label="Loved by teams that ship docs">
|
||||
<div class="card-trust"><span class="trust-mark">Anthropic</span></div>
|
||||
<div class="card-trust"><span class="trust-mark">Resend</span></div>
|
||||
<div class="card-trust"><span class="trust-mark">Cursor</span></div>
|
||||
<div class="card-trust"><span class="trust-mark">Replicate</span></div>
|
||||
<div class="card-trust"><span class="trust-mark">ElevenLabs</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════
|
||||
FEATURES — three cards demonstrating the standard card
|
||||
treatment (16px radius, 5% border, 0.03-alpha shadow
|
||||
whisper). Each card opens with a mint-tinted icon disc —
|
||||
the rare moment the brand green is visible on a non-CTA
|
||||
surface — followed by an h3 at 20px W600 with -0.01em
|
||||
tracking and a body line in --fg-2.
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<section data-od-id="features" id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 22ch">Documentation as product, not afterthought.</h2>
|
||||
<p class="body-muted" style="max-width: 56ch; margin-block-start: var(--space-4)">
|
||||
Every component below pulls from <code style="font-family: var(--font-mono); font-size: 0.95em">var(--*)</code> —
|
||||
no raw hex, no off-token type, no shadow heavier than the
|
||||
documented 0.03-alpha whisper.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="features-grid">
|
||||
<article class="card">
|
||||
<span class="feature-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 6h16M4 12h10M4 18h16" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Whisper-thin separation.</h3>
|
||||
<p class="body-muted body-sm">
|
||||
5% black hairlines (<code style="font-family: var(--font-mono); font-size: 0.95em">rgba(0,0,0,0.05)</code>)
|
||||
carry every section break and card edge. No gray section
|
||||
backgrounds, no heavy shadows — the depth system is
|
||||
border-driven, paper-like.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect <code style="font-family: var(--font-mono); font-size: 0.95em">--border</code> →</a>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<span class="feature-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="M3 12h18M12 3a13.5 13.5 0 0 1 0 18M12 3a13.5 13.5 0 0 0 0 18" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>The pill is the signature.</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Every button, input, and badge resolves to
|
||||
<code style="font-family: var(--font-mono); font-size: 0.95em">--radius-pill</code>
|
||||
(9999px). Cards step from 16 (standard) to 24 (featured) —
|
||||
the four-tier radius scale is the silhouette grammar of
|
||||
the system.
|
||||
</p>
|
||||
<a href="./DESIGN.md" class="body-sm">Read the rule →</a>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<span class="feature-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 7l4-3 4 3 4-3 4 3M4 17l4 3 4-3 4 3 4-3M4 7v10M20 7v10" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>Inter runs tight on display.</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Hero tracks at <code style="font-family: var(--font-mono); font-size: 0.95em">-0.02em</code>
|
||||
(≈ -1.28px at 64px), section heads at -0.02em, body relaxes
|
||||
to 0. Three weights only: 400 reads, 500 interacts, 600
|
||||
announces. Geist Mono is reserved for the terminal voice.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect typography →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════
|
||||
FORM — full-pill input matching the button silhouette,
|
||||
mint focus ring (--focus-ring is 2px var(--accent)), all
|
||||
wrapped in a 24px-radius featured card to demonstrate the
|
||||
large-radius tier. The dark + ghost button pair reuses
|
||||
.btn-primary / .btn-secondary unchanged so the silhouette
|
||||
stays consistent with the hero CTAs above.
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<section data-od-id="form">
|
||||
<p class="eyebrow">Form components</p>
|
||||
<h2 style="margin-block-start: var(--space-3); max-width: 28ch">Inputs inherit the same tokens.</h2>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="body-muted" style="max-width: 48ch">
|
||||
Focus ring, edge, and placeholder colour all derive from
|
||||
<code style="font-family: var(--font-mono); font-size: 0.95em">--accent</code> and
|
||||
<code style="font-family: var(--font-mono); font-size: 0.95em">--border</code>.
|
||||
The submit button reuses
|
||||
<code style="font-family: var(--font-mono); font-size: 0.95em">.btn-primary</code>
|
||||
unchanged — black fill, white label, full-pill silhouette.
|
||||
</p>
|
||||
<p class="body-muted body-sm">
|
||||
No new token is introduced for this section. The form card
|
||||
uses the documented featured-card radius
|
||||
(<code style="font-family: var(--font-mono); font-size: 0.95em">--radius-lg</code>, 24px)
|
||||
and the same 0.03-alpha shadow whisper as everything else.
|
||||
</p>
|
||||
<p class="body-meta">
|
||||
Full reference at <a href="./tokens.css">tokens.css</a> ·
|
||||
spec at <a href="./DESIGN.md">DESIGN.md</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="row-between">
|
||||
<p class="eyebrow">Get the spec</p>
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Open
|
||||
</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="email">Work email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="you@team.dev"
|
||||
autocomplete="email"
|
||||
required
|
||||
/>
|
||||
<p class="field-help">We'll send the spec PDF and nothing else.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Send the spec</button>
|
||||
<button type="button" class="btn btn-secondary">Skip for now</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
256
design-systems/mintlify/tokens.css
Normal file
256
design-systems/mintlify/tokens.css
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/mintlify/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by Mintlify".
|
||||
* Documentation-as-product clarity: white-on-white canvas, near-black
|
||||
* text, signature mint-green accent used sparingly, ultra-subtle 5%-
|
||||
* opacity borders carrying the entire separation system, and a full-
|
||||
* pill (9999px) radius reserved for buttons / inputs / badges as the
|
||||
* brand's signature shape.
|
||||
*
|
||||
* This file pre-compiles the values described in `DESIGN.md` into the
|
||||
* shared schema. Agents generating an artifact for Mintlify should
|
||||
* paste the `:root` block verbatim into the first `<style>` of the
|
||||
* artifact, then reference everything via `var(--*)`.
|
||||
*
|
||||
* Brand-specific schema decisions (each one bends a schema convention
|
||||
* to match Mintlify's voice rather than the cross-brand default):
|
||||
*
|
||||
* 1. `--accent` is Mintlify's mint-green `#18E299`, NOT used as the
|
||||
* primary CTA fill. DESIGN.md §4 documents the primary button as
|
||||
* near-black on white (`#0d0d0d`) with the accent reserved for
|
||||
* links, hover states, focus rings, and the occasional
|
||||
* "promotional" green pill. Treating black as `--fg` and green
|
||||
* as `--accent` keeps the accent slot honest with the lint's
|
||||
* "≤2 visible accent uses per screen" rule, since the heavy CTA
|
||||
* block already lives in `--fg`.
|
||||
*
|
||||
* 2. `--accent-hover` is bound to `#0fa76e` (Brand Green Deep),
|
||||
* NOT a `color-mix(black 8%)` shade. DESIGN.md §2 documents
|
||||
* `#0fa76e` as the explicit hover/dark-on-light variant of the
|
||||
* brand green ("Darker green for text on light-green badges,
|
||||
* hover states on brand elements"). Using the brand-documented
|
||||
* colour preserves voice instead of inventing a math-derived
|
||||
* sibling that does not match Mintlify's own product surfaces.
|
||||
*
|
||||
* 3. `--accent-on` is `#0d0d0d` (Near Black), NOT white. The
|
||||
* brand-accent button (DESIGN.md §4 "Brand Accent Button") sets
|
||||
* `Text: #0d0d0d` over `Background: #18E299` because mint green
|
||||
* is high-luminance — white labels on `#18E299` fall below
|
||||
* WCAG contrast. This is the only brand in the system that
|
||||
* paints dark text on the accent fill.
|
||||
*
|
||||
* 4. `--border` is `rgba(0, 0, 0, 0.05)` — the documented "5%
|
||||
* black opacity" hairline DESIGN.md §1 names as the primary
|
||||
* separation mechanism. Mintlify forbids gray section
|
||||
* backgrounds and instead uses these whisper-thin borders to
|
||||
* slice white-on-white sections apart. Binding `--border` to
|
||||
* the alpha (not a solid hex) lets `--elev-ring` reproduce the
|
||||
* barely-there hairline by default.
|
||||
*
|
||||
* 5. The radius scale climbs HARD: 8 → 16 → 24 → pill. DESIGN.md
|
||||
* §5 names four tiers — 8px (nav buttons / small containers),
|
||||
* 16px (standard cards), 24px (featured cards), 9999px (the
|
||||
* signature pill on every button, input, and badge). The full
|
||||
* pill is the shape that visually identifies a Mintlify
|
||||
* component at a glance, so we reserve `--radius-pill` for
|
||||
* buttons / inputs / badges and let medium / large carry the
|
||||
* card progression.
|
||||
*
|
||||
* 6. `--elev-raised` is the documented Mintlify card whisper —
|
||||
* `0 2px 4px rgba(0, 0, 0, 0.03)` — NOT the schema's slightly
|
||||
* heavier `transparent 92%` blur. DESIGN.md §6 makes the
|
||||
* restraint explicit ("When shadows appear, they're
|
||||
* atmospheric whispers… 0.03 opacity, 2px blur, 4px spread").
|
||||
* The brand's depth system is border-driven, not shadow-driven;
|
||||
* this token barely registers visually and is intentional.
|
||||
*
|
||||
* 7. `--focus-ring` is a sharp 2px ring at `var(--accent)`, NOT
|
||||
* the schema's 3px alpha glow. DESIGN.md §4 specifies focused
|
||||
* inputs use `1px solid var(--color-brand)` plus a matching
|
||||
* outline; the 2px box-shadow form keeps keyboard focus
|
||||
* legible against the white canvas without diffusing into a
|
||||
* halo that would dilute the engineered, paper-like feel.
|
||||
*
|
||||
* 8. The type scale tops out at 64px (`--text-4xl`) with
|
||||
* `--tracking-display: -0.02em` (≈ -1.28px at 64px, the exact
|
||||
* DESIGN.md §3 hero spec). Mintlify's display reads compressed
|
||||
* and deliberate, like a documentation header — not a
|
||||
* billboard. `--leading-tight` sits at 1.15 to match the
|
||||
* documented hero line-height; smaller headings relax toward
|
||||
* 1.30 inline per component.
|
||||
*
|
||||
* 9. Section rhythm is documentation-grade generous: 96px desktop,
|
||||
* 64px tablet, 48px phone (`--section-y-*`). DESIGN.md §5
|
||||
* describes "documentation-grade breathing room" with 48–96px
|
||||
* vertical padding between "chapter-break" sections. We sit at
|
||||
* the top of the documented range on desktop because Mintlify
|
||||
* sells reading comfort and the marketing page must demonstrate
|
||||
* it.
|
||||
*
|
||||
* Source contracts:
|
||||
* - Standard token names: design-systems/_schema/tokens.schema.ts
|
||||
* - A2 fallback parity: design-systems/_schema/defaults.css
|
||||
* - Lint enforcement: apps/daemon/src/lint-artifact.ts
|
||||
*
|
||||
* Keep this file additive: never invent token names not also
|
||||
* documented in DESIGN.md or the schema. The Inter / Geist Mono
|
||||
* faces do not need a CDN reference here — the font stacks list
|
||||
* fallback face names + system fallbacks so artifacts render
|
||||
* acceptably even when Inter is not loaded, and any host that wants
|
||||
* the real Inter face links it externally.
|
||||
* ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* Pure white canvas, white cards, NO color section variation.
|
||||
* DESIGN.md §1: "Clean white canvas — no gray backgrounds, no
|
||||
* color sections, depth through borders and whitespace alone."
|
||||
* `--surface-warm` resolves to a near-white `#fafafa` because
|
||||
* DESIGN.md §4 names "Logo/Trust Card" containers with `#fafafa`
|
||||
* as a surface tint distinct from the pure-white card surface;
|
||||
* components targeting `var(--surface-warm)` therefore reach the
|
||||
* documented Gray 50 instead of collapsing onto plain white. */
|
||||
--bg: #ffffff; /* Pure White — page background */
|
||||
--surface: #ffffff; /* White cards on white background */
|
||||
--surface-warm: #fafafa; /* Gray 50 — trust-card / muted surface tint */
|
||||
|
||||
/* ─── Foreground (4 levels) ───────────────────────────────────────
|
||||
* `#0d0d0d` instead of `#000000` — the micro-softness DESIGN.md §2
|
||||
* calls out as "improves reading comfort". Four independent text
|
||||
* tiers because Mintlify genuinely uses four (heading, body
|
||||
* description, caption, placeholder/disabled), so binding `--fg-2`
|
||||
* and `--meta` independently lets cross-brand components targeting
|
||||
* the richer tiers resolve to Mintlify's actual gray ramp. */
|
||||
--fg: #0d0d0d; /* Gray 900 — primary text, headings */
|
||||
--fg-2: #333333; /* Gray 700 — body description */
|
||||
--muted: #666666; /* Gray 500 — captions, tertiary text */
|
||||
--meta: #888888; /* Gray 400 — placeholder, disabled, code annotations */
|
||||
|
||||
/* ─── Border (2 levels) ──────────────────────────────────────────
|
||||
* 5% opacity hairline is THE signature — DESIGN.md §1 names it as
|
||||
* the primary separation mechanism. `--border-soft` aliases to
|
||||
* `--border` because Mintlify's documented system has only one
|
||||
* "subtle" tier; the slightly stronger `rgba(0,0,0,0.08)` from
|
||||
* DESIGN.md §2 is reserved for INTERACTIVE element edges and is
|
||||
* inlined per-component (button outline, input border) rather than
|
||||
* promoted to a separator-level token. */
|
||||
--border: rgba(0, 0, 0, 0.05); /* signature 5% hairline — section / card edge */
|
||||
--border-soft: var(--border); /* alias — Mintlify has one subtle tier */
|
||||
|
||||
/* ─── Accent ─────────────────────────────────────────────────────
|
||||
* Mint green — used SPARINGLY (DESIGN.md §1: "≤2 visible uses per
|
||||
* screen" enforced by the lint). CTAs, link hover, focus rings,
|
||||
* and the occasional brand-accent pill. Primary CTAs are NOT this
|
||||
* green — they are `--fg`. */
|
||||
--accent: #18E299; /* Brand Green — the signature mint */
|
||||
--accent-on: #0d0d0d; /* dark text on mint — bright accent fails WCAG against white */
|
||||
--accent-hover: #0fa76e; /* Brand Green Deep — DESIGN.md §2 documented hover */
|
||||
--accent-active: color-mix(in oklab, var(--accent-hover), black 12%);
|
||||
|
||||
/* ─── Semantic ───────────────────────────────────────────────────
|
||||
* Warn / Danger sourced from DESIGN.md §2's twoslash colour set
|
||||
* (the technical-doc context where these states most often appear
|
||||
* for Mintlify). `--success` keeps the cross-brand schema default
|
||||
* because using the brand mint (`--accent`) would overload it for
|
||||
* status work and break the "≤2 accent uses per screen" lint. */
|
||||
--success: #16a34a;
|
||||
--warn: #c37d0d; /* Warm Amber — DESIGN.md `--twoslash-warn-bg` */
|
||||
--danger: #d45656; /* Error Red — DESIGN.md `--twoslash-error-bg` */
|
||||
|
||||
/* ─── Typography ─────────────────────────────────────────────────
|
||||
* Inter for everything human-readable; Geist Mono ONLY for code,
|
||||
* tabular metrics, kbd, and uppercase technical labels (DESIGN.md
|
||||
* §3: "The boundary is strict — no mixing"). The `Inter Fallback`
|
||||
* / `Geist Mono Fallback` face names mirror the upstream Mintlify
|
||||
* stylesheet so platforms that ship metric-compatible fallback
|
||||
* fonts under those names can substitute without layout shift. */
|
||||
--font-display: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-body: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale — DESIGN.md §3. Display tops out at 64px; mono code
|
||||
* starts at 12px. The 18px tier (--text-lg) is the documented
|
||||
* "Body Large" for hero descriptions and section introductions. */
|
||||
--text-xs: 12px; /* Mono Code, micro labels */
|
||||
--text-sm: 14px; /* Caption, link, small body */
|
||||
--text-base: 16px; /* Body, button label */
|
||||
--text-lg: 18px; /* Body Large — hero descriptions */
|
||||
--text-xl: 20px; /* Card Title */
|
||||
--text-2xl: 24px; /* Sub-heading */
|
||||
--text-3xl: 40px; /* Section Heading */
|
||||
--text-4xl: 64px; /* Display Hero */
|
||||
|
||||
/* `--leading-body` 1.5 — the documented 16px / 24px reading rhythm.
|
||||
* `--leading-tight` 1.15 matches the 64px display line-height.
|
||||
* `--tracking-display` -0.02em ≈ -1.28px at 64px (exact DESIGN.md
|
||||
* §3 hero spec) and scales proportionally with size. */
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.15;
|
||||
--tracking-display: -0.02em;
|
||||
|
||||
/* ─── Spacing ────────────────────────────────────────────────────
|
||||
* 8px base grid (DESIGN.md §5). The 2/4/5/6/7/10 sub-tier
|
||||
* micro-padding values (button `4.5px 12px`, etc.) are inlined
|
||||
* per-component because they are too fine to belong in the
|
||||
* shared schema. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5: 48–96px chapter-break padding.
|
||||
* Desktop sits at the top of the documented range because the
|
||||
* marketing page itself must demonstrate documentation-grade
|
||||
* breathing room. */
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 48px;
|
||||
|
||||
/* ─── Radius ─────────────────────────────────────────────────────
|
||||
* DESIGN.md §5 four-tier radius scale. The pill (9999px) is the
|
||||
* SIGNATURE shape — every button, every input, every badge.
|
||||
* Cards step from 16 (standard) to 24 (featured). 8 is reserved
|
||||
* for nav-button-style functional rectangles. */
|
||||
--radius-sm: 8px; /* nav buttons, transparent buttons */
|
||||
--radius-md: 16px; /* standard cards */
|
||||
--radius-lg: 24px; /* featured cards, hero containers */
|
||||
--radius-pill: 9999px; /* SIGNATURE — buttons, inputs, badges */
|
||||
|
||||
/* ─── Elevation ──────────────────────────────────────────────────
|
||||
* Shadow as atmospheric whisper. DESIGN.md §6: "Mintlify barely
|
||||
* uses shadows. The depth system is almost entirely border-
|
||||
* driven." `--elev-raised` is the documented card whisper at
|
||||
* 0.03 alpha — barely registering visually, intentional. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 2px 4px rgba(0, 0, 0, 0.03);
|
||||
|
||||
/* ─── Focus ring ─────────────────────────────────────────────────
|
||||
* Sharp 2px box-shadow at the brand mint. DESIGN.md §4 specifies
|
||||
* focused inputs use `1px solid var(--color-brand)` plus a
|
||||
* matching outline; the 2px shadow form keeps keyboard focus
|
||||
* unmistakable on the white canvas without the soft halo that
|
||||
* would dilute the engineered feel. */
|
||||
--focus-ring: 0 0 0 2px var(--accent);
|
||||
|
||||
/* ─── Motion ─────────────────────────────────────────────────────
|
||||
* Standard durations + standard ease — Mintlify's voice is in
|
||||
* type, colour restraint, and whitespace, not in animation. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────────────
|
||||
* 1200px max content width per DESIGN.md §5. Horizontal gutters
|
||||
* climb from 24px on phone/tablet to 32px on desktop — the
|
||||
* documented "24px (mobile) to 32px (desktop)" container padding. */
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 32px;
|
||||
--container-gutter-tablet: 24px;
|
||||
--container-gutter-phone: 24px;
|
||||
}
|
||||
462
design-systems/mongodb/components.html
Normal file
462
design-systems/mongodb/components.html
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>MongoDB — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/mongodb. Forest-dark canvas (#001e2b),
|
||||
neon MongoDB Green (#00ed64) accent, MongoDB Value Serif at hero scale,
|
||||
wide-tracked Source Code Pro labels, teal-tinted shadows."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #001e2b;
|
||||
--surface: #1c2d38;
|
||||
--surface-warm: var(--surface);
|
||||
|
||||
--fg: #ffffff;
|
||||
--fg-2: #e8edeb;
|
||||
--muted: #b8c4c2;
|
||||
--meta: #5c6c75;
|
||||
|
||||
--border: #3d4f58;
|
||||
--border-soft: var(--border);
|
||||
|
||||
--accent: #00ed64;
|
||||
--accent-on: #001e2b;
|
||||
--accent-hover: #00684a;
|
||||
--accent-active: color-mix(in oklab, var(--accent-hover), black 12%);
|
||||
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
--font-display: "MongoDB Value Serif", "Times New Roman", Times, ui-serif, Georgia, serif;
|
||||
--font-body: "Euclid Circular A", "Akzidenz-Grotesk Std", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-mono: "Source Code Pro", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 11px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 20px;
|
||||
--text-xl: 24px;
|
||||
--text-2xl: 36px;
|
||||
--text-3xl: 64px;
|
||||
--text-4xl: 96px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.2;
|
||||
--tracking-display: normal;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
--radius-lg: 16px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised:
|
||||
0 26px 44px rgba(0, 30, 43, 0.12),
|
||||
0 7px 13px rgba(0, 0, 0, 0.13);
|
||||
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg-2);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 300; /* DESIGN.md §3: weight 300 is the body voice */
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — serif authority, geometric workhorse ─── */
|
||||
h1, h2 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 400; /* MongoDB Value Serif at 400 — the editorial move */
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--fg);
|
||||
margin: 0;
|
||||
}
|
||||
h3 {
|
||||
font-family: var(--font-body);
|
||||
font-weight: 500; /* Euclid Circular A medium for sub-headings */
|
||||
line-height: 1.33;
|
||||
color: var(--fg);
|
||||
margin: 0;
|
||||
}
|
||||
h1 { font-size: var(--text-4xl); }
|
||||
h2 { font-size: var(--text-2xl); }
|
||||
h3 { font-size: var(--text-xl); }
|
||||
@media (max-width: 1023px) {
|
||||
h1 { font-size: var(--text-3xl); } /* 96 → 64 on tablet */
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
h1 { font-size: 44px; } /* further collapse on phone */
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 300;
|
||||
line-height: 1.6;
|
||||
color: var(--fg-2);
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
/* Source Code Pro uppercase eyebrow — the database-field label voice */
|
||||
.eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
line-height: 1.14;
|
||||
margin: 0;
|
||||
}
|
||||
/* Neon green accent underline — the signature decorative element */
|
||||
.accent-underline {
|
||||
background-image: linear-gradient(var(--accent), var(--accent));
|
||||
background-size: 100% 2px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 100%;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — pill primary on dark, ghost secondary ────── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 12px 24px;
|
||||
border-radius: var(--radius-pill); /* DESIGN.md §4: pill CTAs */
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard),
|
||||
border-color var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
/* Primary: neon-on-dark — the brand's electric CTA */
|
||||
.btn-primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-hover); /* settles to muted Dark Green on hover */
|
||||
border-color: var(--accent-hover);
|
||||
color: var(--fg);
|
||||
}
|
||||
.btn-primary:active { background: var(--accent-active); border-color: var(--accent-active); }
|
||||
/* Secondary: dark teal pill with cool-gray text — the muted alternative */
|
||||
.btn-secondary {
|
||||
background: var(--surface);
|
||||
color: var(--muted);
|
||||
border-color: var(--border);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: #1eaedb; /* Teal Active — DESIGN.md §4 hover */
|
||||
color: var(--fg);
|
||||
border-color: #1eaedb;
|
||||
}
|
||||
|
||||
/* ─── Inputs — dark surface, light input text ───────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--fg-2);
|
||||
}
|
||||
.field input {
|
||||
padding: 12px 12px 12px 8px; /* DESIGN.md §4 textarea padding */
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg-2);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 300;
|
||||
outline: none;
|
||||
transition:
|
||||
border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field input::placeholder { color: var(--meta); }
|
||||
.field-help { font-size: var(--text-xs); color: var(--muted); }
|
||||
|
||||
/* ─── Cards — dark surface, forest-tinted shadow ────────── */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
box-shadow: var(--elev-raised);
|
||||
}
|
||||
|
||||
/* ─── Badges — pill chips for status ────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 3px 10px;
|
||||
border-radius: var(--radius-pill);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.badge-success {
|
||||
color: var(--accent);
|
||||
background: color-mix(in oklab, var(--accent), transparent 86%);
|
||||
}
|
||||
.badge-muted {
|
||||
color: var(--muted);
|
||||
background: color-mix(in oklab, var(--muted), transparent 88%);
|
||||
}
|
||||
.badge-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
}
|
||||
|
||||
/* ─── Links ─────────────────────────────────────────────── */
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { color: #3860be; text-decoration: underline; text-underline-offset: 3px; }
|
||||
kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Layout helpers ────────────────────────────────────── */
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: end;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.hero-grid { grid-template-columns: 1fr; gap: var(--space-8); }
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.hero-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-5);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--surface);
|
||||
}
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 420px; }
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); }
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Reference fixture · mongodb</p>
|
||||
<h1>The developer data <span class="accent-underline">platform</span>.</h1>
|
||||
<p class="lead" style="max-width: 56ch">
|
||||
Atlas-scale documents, query, and search across every cloud. Built for
|
||||
builders who treat the database as part of the application, not the
|
||||
place applications go to wait.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Start free
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-secondary">Read the docs</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-meta" aria-label="Cluster status">
|
||||
<div class="row-between">
|
||||
<span class="body-sm" style="color: var(--fg-2)">Cluster status</span>
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
Healthy
|
||||
</span>
|
||||
</div>
|
||||
<p class="body-sm body-muted">
|
||||
Last reviewed <time datetime="2026-05-15">2026-05-15</time> · v1.0
|
||||
</p>
|
||||
<p class="body-sm body-muted">
|
||||
Press <kbd>⌘</kbd> <kbd>K</kbd> to open the Atlas command palette.
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 26ch">
|
||||
Forest-dark canvas, <span class="accent-underline">electric green</span> signal.
|
||||
</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card">
|
||||
<p class="eyebrow">Color</p>
|
||||
<h3>Bioluminescent accent</h3>
|
||||
<p class="body-muted body-sm">
|
||||
MongoDB Green (#00ed64) burns through a forest-black (#001e2b)
|
||||
canvas. Used once per section, sparingly, for maximum electric
|
||||
impact — never as a background.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect tokens →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<p class="eyebrow">Type</p>
|
||||
<h3>Serif at database scale</h3>
|
||||
<p class="body-muted body-sm">
|
||||
MongoDB Value Serif at 96px gives the page editorial authority
|
||||
normally reserved for newspapers. Euclid Circular A at weight 300
|
||||
keeps body copy airy against the dense dark surface.
|
||||
</p>
|
||||
<a href="./DESIGN.md" class="body-sm">Read the rule →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<p class="eyebrow">Depth</p>
|
||||
<h3>Teal-tinted elevation</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Card shadows use rgba(0,30,43,0.12) — the forest tone carried
|
||||
into the depth system so even lifted surfaces feel like they
|
||||
belong to the MongoDB color world.
|
||||
</p>
|
||||
<a href="./tokens.css" class="body-sm">Inspect shadow →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Form components</p>
|
||||
<h2>Inputs in the forest-dark context.</h2>
|
||||
<p class="body-muted" style="max-width: 50ch">
|
||||
Borders use teal-gray (#3d4f58), text uses light-input (#e8edeb),
|
||||
focus rings glow neon green. Source Code Pro uppercase labels
|
||||
read as database field names — systematic, structured, classified.
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Work email</label>
|
||||
<input id="email" type="email" placeholder="you@company.com" autocomplete="email" required />
|
||||
<p class="field-help">We'll send Atlas access and nothing else.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Get Atlas access</button>
|
||||
<button type="button" class="btn btn-secondary">Talk to sales</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
176
design-systems/mongodb/tokens.css
Normal file
176
design-systems/mongodb/tokens.css
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/mongodb/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by MongoDB".
|
||||
* Forest-dark database aesthetic: a near-black teal canvas (#001e2b) lit
|
||||
* by a single bioluminescent neon green (#00ed64), serif authority at
|
||||
* hero scale, and shadows that carry the brand color into elevation.
|
||||
*
|
||||
* Key brand decisions encoded here:
|
||||
* - Forest Black (#001e2b) as the primary canvas — never pure black;
|
||||
* the teal undertone is what keeps the dark mode feeling alive
|
||||
* rather than void
|
||||
* - MongoDB Green (#00ed64) as the singular electric accent — used
|
||||
* for highlights, underlines, and one CTA per screen
|
||||
* - MongoDB Value Serif for display sizes — editorial authority at
|
||||
* database-company scale; Euclid Circular A for everything else
|
||||
* - Source Code Pro as the mono voice — wide-tracked uppercase
|
||||
* labels are the "database field" identity
|
||||
* - Teal-tinted shadows (rgba(0,30,43,0.12)) — depth that belongs to
|
||||
* the MongoDB color world, not generic neutral black
|
||||
* - Full 4-tier fg/border ramps — MongoDB genuinely uses #ffffff →
|
||||
* #e8edeb → #b8c4c2 → #5c6c75 for cascading text hierarchies and
|
||||
* #3d4f58 for dark-surface edges
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* Forest-dark canvas: the page is the deepest teal-black; cards lift
|
||||
* on a slightly warmer deep-teal panel. No warm tier — MongoDB's
|
||||
* palette is strictly cool (teal, green, blue) and surface-warm
|
||||
* aliases to the dark surface rather than introducing an amber tint
|
||||
* that would break the forest atmosphere. */
|
||||
--bg: #001e2b; /* Forest Black — the deepest teal-black canvas */
|
||||
--surface: #1c2d38; /* Deep Teal — lifted cards / secondary dark panels */
|
||||
--surface-warm: var(--surface); /* alias — MongoDB has no warm tier */
|
||||
|
||||
/* ─── Foreground ──────────────────────────────────────────────────
|
||||
* Four-tier ramp matches MongoDB's real usage on dark surfaces:
|
||||
* pure white for headings, light-input for body, silver-teal for
|
||||
* captions, cool-gray for metadata. Independently bound (not
|
||||
* aliased) because the brand actually paints each tier somewhere. */
|
||||
--fg: #ffffff; /* Pure White — primary text on dark */
|
||||
--fg-2: #e8edeb; /* Light Input — body text, secondary headings */
|
||||
--muted: #b8c4c2; /* Silver Teal — captions, supporting text */
|
||||
--meta: #5c6c75; /* Cool Gray — metadata, tertiary labels */
|
||||
|
||||
/* ─── Border ──────────────────────────────────────────────────────
|
||||
* Teal Gray edges on dark surfaces — the cool border tone that
|
||||
* belongs to the forest palette. border-soft aliases because
|
||||
* MongoDB does not draw an inner-separator tier distinct from the
|
||||
* card edge on dark mode. */
|
||||
--border: #3d4f58; /* Teal Gray — dark-surface card edge */
|
||||
--border-soft: var(--border); /* alias — no inner separator tier on dark */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* MongoDB Green — neon, electric, bioluminescent. Used sparingly
|
||||
* (≤2 per screen) for headline highlights, accent underlines, and
|
||||
* one CTA per section. accent-on is Forest Black (not white)
|
||||
* because neon green is luminous enough that dark text reads with
|
||||
* far more contrast than white. accent-hover is the functional
|
||||
* muted Dark Green (#00684a) from DESIGN.md §2 — the brand's own
|
||||
* darker green variant, not a synthesized darken. */
|
||||
--accent: #00ed64;
|
||||
--accent-on: #001e2b; /* Forest Black text on neon green CTAs */
|
||||
--accent-hover: #00684a; /* Dark Green — MongoDB's own muted variant */
|
||||
--accent-active: color-mix(in oklab, var(--accent-hover), black 12%);
|
||||
|
||||
/* ─── Semantic ────────────────────────────────────────────────────
|
||||
* Standard semantic palette. MongoDB's brand green is already the
|
||||
* accent; success keeps the schema default so it does not collide
|
||||
* with the neon brand voice. */
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
/* ─── Typography ──────────────────────────────────────────────────
|
||||
* Three voices, three roles:
|
||||
* --font-display: MongoDB Value Serif for editorial hero headlines
|
||||
* --font-body: Euclid Circular A for geometric body / UI
|
||||
* --font-mono: Source Code Pro for code and wide-tracked labels
|
||||
* The serif-at-hero choice is the typographic signature; component
|
||||
* CSS should never substitute the body face for display sizes. */
|
||||
--font-display: "MongoDB Value Serif", "Times New Roman", Times, ui-serif, Georgia, serif;
|
||||
--font-body: "Euclid Circular A", "Akzidenz-Grotesk Std", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
--font-mono: "Source Code Pro", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale — distilled from DESIGN.md §3 hierarchy table.
|
||||
* 96px hero (MongoDB Value Serif) and 64px sub-hero are the
|
||||
* editorial moves; the rest follows Euclid Circular A from 11px
|
||||
* small to 36px section heading. Weight 300 body is encoded in
|
||||
* component CSS (the schema does not carry weight tokens). */
|
||||
--text-xs: 11px; /* Small — tags, annotations */
|
||||
--text-sm: 14px; /* Caption, Code Label */
|
||||
--text-base: 16px; /* Body Light, Nav, Code Body */
|
||||
--text-lg: 20px; /* Body Large — introductions */
|
||||
--text-xl: 24px; /* Sub-heading — feature titles */
|
||||
--text-2xl: 36px; /* Section Heading */
|
||||
--text-3xl: 64px; /* Display Secondary — serif sub-hero */
|
||||
--text-4xl: 96px; /* Display Hero — serif at editorial scale */
|
||||
|
||||
/* Leading + tracking — DESIGN.md §3.
|
||||
* Body Light uses 1.5–2.0; we sit at 1.5 so paragraphs breathe
|
||||
* without losing rhythm. Hero display uses 1.20 (tight). Display
|
||||
* letter-spacing is `normal` — MongoDB Value Serif at 96px does
|
||||
* not compress like Geist or industrial sans; the serif drawing
|
||||
* carries the authority without negative tracking. */
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 1.2;
|
||||
--tracking-display: normal;
|
||||
|
||||
/* ─── Spacing ─────────────────────────────────────────────────────
|
||||
* 8px-rooted scale; MongoDB's documented spacing (1/4/7/8/10/12/
|
||||
* 14/15/16/18/20/24/32) includes odd sub-tiers (7, 14, 15, 18)
|
||||
* for fine-grained type alignment that stay component-internal.
|
||||
* The schema's 4/8/12/16/20/24/32/48 covers the structural rhythm. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5 Whitespace Philosophy: dark hero
|
||||
* sections use extra vertical padding (80px+) to let the forest-
|
||||
* dark background breathe. 96px desktop sits at the generous end
|
||||
* of MongoDB's documented range. */
|
||||
--section-y-desktop: 96px;
|
||||
--section-y-tablet: 64px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
/* ─── Radius ──────────────────────────────────────────────────────
|
||||
* DESIGN.md §5 radius scale: 1/2/4/8/16/20/24/30/32/48/100/9999.
|
||||
* Schema slots bind to: 4 (input subtle), 8 (standard card / link),
|
||||
* 16 (card), 9999 (pill button). The 30–32px image radius and
|
||||
* 48px hero radius live as inline overrides in components.html
|
||||
* where they apply — they are surface-specific, not scale-wide. */
|
||||
--radius-sm: 4px; /* inputs, small buttons */
|
||||
--radius-md: 8px; /* standard cards, links */
|
||||
--radius-lg: 16px; /* feature cards, containers */
|
||||
--radius-pill: 9999px; /* pill buttons, badges */
|
||||
|
||||
/* ─── Elevation ───────────────────────────────────────────────────
|
||||
* Forest-tinted shadow signature. DESIGN.md §6: the primary card
|
||||
* elevation uses rgba(0, 30, 43, 0.12) — a teal-tinted shadow that
|
||||
* carries the forest-dark brand color into the depth system. Even
|
||||
* on light surfaces, shadows feel like they belong to the MongoDB
|
||||
* color world rather than being generic neutral black. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised:
|
||||
0 26px 44px rgba(0, 30, 43, 0.12),
|
||||
0 7px 13px rgba(0, 0, 0, 0.13);
|
||||
|
||||
/* ─── Focus ring ──────────────────────────────────────────────────
|
||||
* Neon-green-tinted halo at 30% alpha — uses the brand accent so
|
||||
* keyboard focus reads as part of the MongoDB color world rather
|
||||
* than a generic blue ring. */
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||||
|
||||
/* ─── Motion ──────────────────────────────────────────────────────
|
||||
* Standard durations — MongoDB's identity lives in color, type,
|
||||
* and shadow; animation is purposeful, not choreographed. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ──────────────────────────────────────────────────────
|
||||
* 1200px max content width — contained editorial layouts within
|
||||
* generous full-bleed dark sections. */
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
537
design-systems/superhuman/components.html
Normal file
537
design-systems/superhuman/components.html
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Superhuman — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/superhuman. The fastest email
|
||||
experience ever made — keyboard-first velocity, warm cream CTAs, lavender
|
||||
as the sole accent, charcoal ink at weight 460."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--surface: #ffffff;
|
||||
--surface-warm: #e9e5dd;
|
||||
|
||||
--fg: #292827;
|
||||
--fg-2: var(--fg);
|
||||
--muted: #6f6c69;
|
||||
--meta: var(--muted);
|
||||
|
||||
--border: #dcd7d3;
|
||||
--border-soft: var(--border);
|
||||
|
||||
--accent: #cbb7fb;
|
||||
--accent-on: #292827;
|
||||
--accent-hover: color-mix(in oklab, var(--accent), black 6%);
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 12%);
|
||||
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
--font-display: "Super Sans VF", system-ui, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
--font-body: "Super Sans VF", system-ui, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 16px;
|
||||
--text-lg: 20px;
|
||||
--text-xl: 22px;
|
||||
--text-2xl: 28px;
|
||||
--text-3xl: 48px;
|
||||
--text-4xl: 64px;
|
||||
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 0.96;
|
||||
--tracking-display: -0.0275em;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 56px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 8px;
|
||||
--radius-lg: 16px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 2px 12px rgba(41, 40, 39, 0.06);
|
||||
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 55%);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ──────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 460;
|
||||
line-height: var(--leading-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container {
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--container-gutter-desktop);
|
||||
}
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — non-standard weight axis (460/540/600/700) ─ */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
line-height: var(--leading-tight);
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: 540; /* Display weight */
|
||||
letter-spacing: var(--tracking-display);
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 460; /* Section heading */
|
||||
letter-spacing: var(--tracking-display);
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 540; /* Feature title */
|
||||
letter-spacing: -0.0225em; /* -0.63px / 28px */
|
||||
}
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--fg);
|
||||
line-height: var(--leading-body);
|
||||
font-weight: 460;
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); line-height: var(--leading-body); }
|
||||
.body-xs { font-size: var(--text-xs); line-height: 1.5; }
|
||||
|
||||
/* Eyebrow — micro label, the only place we go bold (700) per DESIGN.md §3 */
|
||||
.eyebrow {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-5 > * + * { margin-block-start: var(--space-5); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — 8px radius, never pill, warm cream signature ─ */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 12px var(--space-5);
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600; /* Button / UI Semi */
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: background-color var(--motion-fast) var(--ease-standard),
|
||||
color var(--motion-fast) var(--ease-standard);
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
|
||||
/* Warm Cream primary — the signature CTA. Charcoal text on cream. */
|
||||
.btn-primary {
|
||||
background: var(--surface-warm);
|
||||
color: var(--fg);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: color-mix(in oklab, var(--surface-warm), black 5%);
|
||||
}
|
||||
.btn-primary:active {
|
||||
background: color-mix(in oklab, var(--surface-warm), black 10%);
|
||||
}
|
||||
|
||||
/* Dark Primary — charcoal bg on white sections (DESIGN.md §4). */
|
||||
.btn-dark {
|
||||
background: var(--fg);
|
||||
color: var(--bg);
|
||||
}
|
||||
.btn-dark:hover {
|
||||
background: color-mix(in oklab, var(--fg), white 8%);
|
||||
}
|
||||
|
||||
/* Ghost / Text Link — underline only, no fill. */
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
padding-inline: var(--space-3);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
text-decoration-thickness: 1px;
|
||||
}
|
||||
.btn-ghost:hover {
|
||||
background: color-mix(in oklab, var(--fg), transparent 95%);
|
||||
}
|
||||
|
||||
/* ─── Inputs — borders define them, focus deepens to charcoal ─ */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 540;
|
||||
color: var(--fg);
|
||||
}
|
||||
.field input {
|
||||
padding: 12px var(--space-4);
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 460;
|
||||
outline: none;
|
||||
transition: border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input::placeholder { color: var(--muted); }
|
||||
.field input:hover { border-color: color-mix(in oklab, var(--border), var(--fg) 25%); }
|
||||
.field input:focus-visible {
|
||||
border-color: var(--fg);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field-help {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* ─── Cards — 16px radius, parchment border, no shadow by default ─ */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
transition: box-shadow var(--motion-base) var(--ease-standard),
|
||||
border-color var(--motion-base) var(--ease-standard);
|
||||
}
|
||||
.card:hover {
|
||||
box-shadow: var(--elev-raised);
|
||||
border-color: color-mix(in oklab, var(--border), var(--fg) 15%);
|
||||
}
|
||||
.card .card-eyebrow {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ─── Badges ─────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 4px var(--space-3);
|
||||
border-radius: var(--radius-sm); /* 8px — not pill */
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 700; /* Micro Label weight */
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.badge-accent {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
}
|
||||
.badge-success {
|
||||
background: color-mix(in oklab, var(--success), transparent 88%);
|
||||
color: var(--success);
|
||||
}
|
||||
.badge-muted {
|
||||
background: color-mix(in oklab, var(--muted), transparent 88%);
|
||||
color: var(--muted);
|
||||
}
|
||||
.badge-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: var(--radius-pill); /* Only place pill is used */
|
||||
background: currentColor;
|
||||
}
|
||||
|
||||
/* ─── Keyboard chips — Superhuman is keyboard-first ─────── */
|
||||
kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
padding: 3px 8px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
line-height: 1;
|
||||
box-shadow: 0 1px 0 0 var(--border);
|
||||
}
|
||||
|
||||
/* ─── Links — Amethyst-style underline (DESIGN.md §4) ────── */
|
||||
a { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
|
||||
a:hover { text-decoration-thickness: 2px; }
|
||||
|
||||
/* ─── Layout helpers ─────────────────────────────────────── */
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: end;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.hero-grid { grid-template-columns: 1fr; gap: var(--space-8); }
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
.hero-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
padding: var(--space-6);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--surface);
|
||||
}
|
||||
.kbd-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.features-grid { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.features-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
.form-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
max-width: 460px;
|
||||
}
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
margin-block-start: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||||
.row-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.meta-divider {
|
||||
height: 1px;
|
||||
background: var(--border-soft);
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-5">
|
||||
<p class="eyebrow">Reference fixture · superhuman</p>
|
||||
<h1>The fastest email<br />experience ever made.</h1>
|
||||
<p class="lead" style="max-width: 52ch">
|
||||
Fly through your inbox with keyboard shortcuts, instant
|
||||
search, and AI that drafts replies in your voice. Built
|
||||
for high performers who answer hundreds of messages a day.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Get Superhuman
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="1.75"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-ghost">Read the spec</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-meta" aria-label="Keyboard shortcuts">
|
||||
<div class="row-between">
|
||||
<span class="badge badge-accent">Most loved by execs</span>
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
4× faster
|
||||
</span>
|
||||
</div>
|
||||
<hr class="meta-divider" />
|
||||
<p class="body-sm body-muted" style="line-height: 1.55">
|
||||
Press <kbd>K</kbd> to compose. Press <kbd>⌘</kbd> <kbd>K</kbd>
|
||||
to jump anywhere. <kbd>E</kbd> archives. <kbd>⇧</kbd> <kbd>R</kbd>
|
||||
replies all.
|
||||
</p>
|
||||
<p class="body-xs" style="color: var(--muted)">
|
||||
Last reviewed <time datetime="2026-05-18">2026-05-18</time> · v1.0
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3" style="max-width: 30ch">
|
||||
<p class="eyebrow">Your Superhuman suite</p>
|
||||
<h2>Velocity, by design.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-12)">
|
||||
<article class="card">
|
||||
<p class="card-eyebrow">Accent · 01</p>
|
||||
<h3>One color, total restraint.</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Lavender Glow (#cbb7fb) is the only chromatic departure from
|
||||
the warm-neutral palette. Every saturated CTA you've seen on
|
||||
other sites — Superhuman quietly omits it.
|
||||
</p>
|
||||
<p class="body-sm">
|
||||
<a href="./tokens.css">Inspect <code style="font-family: var(--font-mono); font-size: var(--text-xs);">--accent</code></a>
|
||||
</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<p class="card-eyebrow">Type · 02</p>
|
||||
<h3>Weights between weights.</h3>
|
||||
<p class="body-muted body-sm">
|
||||
Super Sans VF runs at 460 / 540 / 600 / 700 — non-standard
|
||||
stops that sit between Regular and Medium, between Medium
|
||||
and Semibold. Body is 460. Display is 540. Bold is rare.
|
||||
</p>
|
||||
<p class="body-sm">
|
||||
<a href="./DESIGN.md">Read the rule</a>
|
||||
</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<p class="card-eyebrow">Geometry · 03</p>
|
||||
<h3>Two radii, total clarity.</h3>
|
||||
<p class="body-muted body-sm">
|
||||
<code style="font-family: var(--font-mono); font-size: var(--text-xs);">--radius-sm: 8px</code> for buttons and inputs.
|
||||
<code style="font-family: var(--font-mono); font-size: var(--text-xs);">--radius-lg: 16px</code> for cards.
|
||||
No micro-rounding. No pill buttons. The binary system is the system.
|
||||
</p>
|
||||
<p class="body-sm">
|
||||
<a href="./tokens.css">Inspect radii</a>
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Get on the list</p>
|
||||
<h2>Built for the highest performers.</h2>
|
||||
<p class="body-muted lead" style="max-width: 44ch">
|
||||
Superhuman is invitation-only. Tell us your work email and
|
||||
we'll let you know when a seat opens up. No marketing, no
|
||||
follow-ups, no noise — that's the whole point.
|
||||
</p>
|
||||
<div class="kbd-row">
|
||||
<span class="body-xs body-muted">Tip:</span>
|
||||
<kbd>Tab</kbd>
|
||||
<span class="body-xs body-muted">to focus,</span>
|
||||
<kbd>Enter</kbd>
|
||||
<span class="body-xs body-muted">to submit.</span>
|
||||
</div>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Work email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="you@company.com"
|
||||
autocomplete="email"
|
||||
required
|
||||
/>
|
||||
<p class="field-help">
|
||||
We'll only email you when a seat opens. Promise.
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Request access
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="1.75"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</button>
|
||||
<button type="button" class="btn btn-ghost">See a demo</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
160
design-systems/superhuman/tokens.css
Normal file
160
design-systems/superhuman/tokens.css
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/superhuman/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by Superhuman".
|
||||
* Premium keyboard-first email client. Predominantly white canvas with a
|
||||
* single dramatic gesture of color (deep purple hero), warm cream CTAs,
|
||||
* lavender as the sole accent, and charcoal ink (warmer than #000) for text.
|
||||
*
|
||||
* Brand identity in three sentences:
|
||||
* 1. Maximum confidence through minimum decoration — white dominates,
|
||||
* borders define containers, shadows are whispered. Lavender Glow
|
||||
* (#cbb7fb) is the only accent that ever leaves the warm-neutral
|
||||
* grayscale.
|
||||
* 2. Super Sans VF with non-standard weight stops (460 / 540 / 600 / 700).
|
||||
* Body weight is 460 — slightly heavier than regular but lighter than
|
||||
* medium — the typographic signature that feels confident, never bold.
|
||||
* 3. Two-radius binary system (8px / 16px) and ultra-tight 0.96 leading
|
||||
* on display sizes — headlines compress into architectural blocks
|
||||
* while body text breathes at 1.50 leading.
|
||||
*
|
||||
* Schema decisions:
|
||||
* - --bg: #ffffff (Pure White) — the dominant content canvas.
|
||||
* - --surface: #ffffff — cards inherit the canvas; --border defines them.
|
||||
* - --surface-warm: #e9e5dd (Warm Cream) — lifted warm tier for CTAs.
|
||||
* - --fg: #292827 (Charcoal Ink) — warm near-black, never pure black.
|
||||
* - --fg-2 → var(--fg) — DESIGN.md uses one ink color on light surfaces.
|
||||
* - --muted: #6f6c69 — warm mid-gray for captions, derived to sit
|
||||
* between Charcoal Ink and Parchment Border on the warm hue family.
|
||||
* - --border: #dcd7d3 (Parchment Border) — warm light gray, slight pink.
|
||||
* - --accent: #cbb7fb (Lavender Glow); --accent-on: #292827 — charcoal
|
||||
* on lavender (DESIGN.md "Don't use bright/saturated CTA text").
|
||||
* - --leading-tight: 0.96 — the signature display compression.
|
||||
* - --tracking-display: -0.0275em ≈ -1.32px / 48px (DESIGN.md §3).
|
||||
* - --radius-md: 8px (no mid-tier — DESIGN.md mandates only 8 / 16).
|
||||
* - --elev-raised: charcoal-tinted whisper, never gray; matches the
|
||||
* warm-neutral palette used everywhere else.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* White canvas dominates. Warm Cream (#e9e5dd) lives in --surface-warm
|
||||
* as the lifted warm tier — reserved for CTAs, never used as a card bg. */
|
||||
--bg: #ffffff; /* Pure White — primary page background */
|
||||
--surface: #ffffff; /* Cards inherit the canvas; --border contains them */
|
||||
--surface-warm: #e9e5dd; /* Warm Cream — primary button background only */
|
||||
|
||||
/* ─── Foreground ──────────────────────────────────────────────────
|
||||
* Charcoal Ink — warm near-black with faint brown undertone. Body
|
||||
* text uses one ink color throughout; --muted is reserved for true
|
||||
* subtext like captions and helper labels. */
|
||||
--fg: #292827; /* Charcoal Ink — primary text */
|
||||
--fg-2: var(--fg); /* alias — DESIGN.md uses one ink for body */
|
||||
--muted: #6f6c69; /* Warm mid-gray — captions, helper text */
|
||||
--meta: var(--muted); /* alias — same warm gray for metadata */
|
||||
|
||||
/* ─── Border ──────────────────────────────────────────────────────
|
||||
* Parchment Border — warm light gray with slight pink undertone.
|
||||
* Cards rely on borders for containment, not box shadows. */
|
||||
--border: #dcd7d3; /* Parchment Border — card edges, dividers */
|
||||
--border-soft: var(--border); /* alias — no separate inner-row tier */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* Lavender Glow — soft, approachable purple. The ONLY chromatic
|
||||
* departure from the warm-neutral palette. Charcoal sits on it for
|
||||
* AA contrast (lavender is too light for white text). */
|
||||
--accent: #cbb7fb;
|
||||
--accent-on: #292827; /* Charcoal on lavender — DESIGN.md §4 */
|
||||
--accent-hover: color-mix(in oklab, var(--accent), black 6%);
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 12%);
|
||||
|
||||
/* ─── Semantic ────────────────────────────────────────────────────
|
||||
* Superhuman's marketing exercises extreme color restraint, but the
|
||||
* schema requires semantic tokens for product-side usage (status pills,
|
||||
* inline validation). Defaults from _schema/defaults.css; legible on white. */
|
||||
--success: #16a34a;
|
||||
--warn: #eab308;
|
||||
--danger: #dc2626;
|
||||
|
||||
/* ─── Typography ──────────────────────────────────────────────────
|
||||
* Super Sans VF — custom variable font with non-standard weight axis
|
||||
* (460, 540, 600, 700). Body weight is 460 — the signature stop that
|
||||
* sits between Regular and Medium. Fallback chain mirrors DESIGN.md §3. */
|
||||
--font-display: "Super Sans VF", system-ui, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
--font-body: "Super Sans VF", system-ui, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale — DESIGN.md §3 hierarchy. 64px hero / 48px section /
|
||||
* 28px feature title / 22px card heading / 20px body heading.
|
||||
* All eight stops appear verbatim in DESIGN.md — no interpolation. */
|
||||
--text-xs: 12px; /* Micro Label */
|
||||
--text-sm: 14px; /* Caption family */
|
||||
--text-base: 16px; /* Body / Button / Nav */
|
||||
--text-lg: 20px; /* Body Heading */
|
||||
--text-xl: 22px; /* Card Heading */
|
||||
--text-2xl: 28px; /* Feature Title */
|
||||
--text-3xl: 48px; /* Section Heading */
|
||||
--text-4xl: 64px; /* Display Hero */
|
||||
|
||||
/* Leading + tracking.
|
||||
* 0.96 — the signature display compression (DESIGN.md §3).
|
||||
* 1.50 — body text breathes generously by contrast.
|
||||
* -0.0275em ≈ -1.32px / 48px from DESIGN.md §3, applied at display sizes only. */
|
||||
--leading-body: 1.5;
|
||||
--leading-tight: 0.96;
|
||||
--tracking-display: -0.0275em;
|
||||
|
||||
/* ─── Spacing ─────────────────────────────────────────────────────
|
||||
* 8px base. Scale per DESIGN.md §5: 4 / 8 / 12 / 16 / 20 / 24 / 32 / 48. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
/* Section rhythm — DESIGN.md §5 says 48–80px between major sections.
|
||||
* Top of the range on desktop, compresses on smaller breakpoints. */
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 56px;
|
||||
--section-y-phone: 40px;
|
||||
|
||||
/* ─── Radius ──────────────────────────────────────────────────────
|
||||
* Binary system — DESIGN.md §5: only 8px and 16px exist on the
|
||||
* marketing site. No micro-rounding (2px), no pill buttons (50px+).
|
||||
* --radius-md collapses to --radius-sm because the brand has no
|
||||
* mid-tier; --radius-pill is reserved for status dots only. */
|
||||
--radius-sm: 8px; /* Buttons, inputs, inline elements */
|
||||
--radius-md: 8px; /* No mid-tier — DESIGN.md mandates only 8/16 */
|
||||
--radius-lg: 16px; /* Cards, links, larger containers */
|
||||
--radius-pill: 9999px; /* Status dots only — never buttons */
|
||||
|
||||
/* ─── Elevation ───────────────────────────────────────────────────
|
||||
* Depth lives in borders and color contrast, not shadow. The raised
|
||||
* tier is a charcoal-tinted whisper for product-screenshot frames
|
||||
* (DESIGN.md §6 "Subtle shadow … product screenshot containers"). */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 2px 12px rgba(41, 40, 39, 0.06);
|
||||
|
||||
/* ─── Focus ring ──────────────────────────────────────────────────
|
||||
* Lavender Glow at 45% — Superhuman is keyboard-first, so the focus
|
||||
* indicator must read clearly without violating the muted palette. */
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 55%);
|
||||
|
||||
/* ─── Motion ──────────────────────────────────────────────────────
|
||||
* Restrained — Superhuman's velocity is in the keyboard, not the page.
|
||||
* Defaults from _schema/defaults.css. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ──────────────────────────────────────────────────────
|
||||
* 1200px container — DESIGN.md §5 "~1200px content container, centered". */
|
||||
--container-max: 1200px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
365
design-systems/wise/components.html
Normal file
365
design-systems/wise/components.html
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Wise — reference components</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reference fixture for design-systems/wise. Spring-green CTAs on warm-neutral
|
||||
canvas, billboard Wise Sans at 0.85 line-height, pill buttons, ring-only shadows."
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--surface: #e8ebe6;
|
||||
--surface-warm: var(--surface);
|
||||
|
||||
--fg: #0e0f0c;
|
||||
--fg-2: var(--fg);
|
||||
--muted: #868685;
|
||||
--meta: var(--muted);
|
||||
|
||||
--border: rgba(14, 15, 12, 0.12);
|
||||
--border-soft: var(--border);
|
||||
|
||||
--accent: #9fe870;
|
||||
--accent-on: #163300;
|
||||
--accent-hover: #cdffad;
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 12%);
|
||||
|
||||
--success: #054d28;
|
||||
--warn: #ffd11a;
|
||||
--danger: #d03238;
|
||||
|
||||
--font-display: "Wise Sans", Inter, ui-sans-serif, system-ui, sans-serif;
|
||||
--font-body: Inter, Helvetica, Arial, ui-sans-serif, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
--text-xs: 12px;
|
||||
--text-sm: 14px;
|
||||
--text-base: 18px;
|
||||
--text-lg: 22px;
|
||||
--text-xl: 26px;
|
||||
--text-2xl: 40px;
|
||||
--text-3xl: 64px;
|
||||
--text-4xl: 96px;
|
||||
|
||||
--leading-body: 1.44;
|
||||
--leading-tight: 0.85;
|
||||
--tracking-display: normal;
|
||||
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 48px;
|
||||
--section-y-phone: 32px;
|
||||
|
||||
--radius-sm: 16px;
|
||||
--radius-md: 30px;
|
||||
--radius-lg: 40px;
|
||||
--radius-pill: 9999px;
|
||||
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 0 0 1px var(--border), 0 2px 8px rgba(14, 15, 12, 0.04);
|
||||
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 60%);
|
||||
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
|
||||
/* ─── Reset ─────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
font-weight: 600; /* Inter 600 as body default — DESIGN.md §3 */
|
||||
font-feature-settings: "calt" 1; /* "calt" on everything */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ─── Layout ─────────────────────────────────────────────── */
|
||||
.container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--container-gutter-desktop); }
|
||||
section { padding-block: var(--section-y-desktop); }
|
||||
section + section { border-top: 1px solid var(--border); }
|
||||
@media (max-width: 1023px) {
|
||||
.container { padding-inline: var(--container-gutter-tablet); }
|
||||
section { padding-block: var(--section-y-tablet); }
|
||||
}
|
||||
@media (max-width: 639px) {
|
||||
.container { padding-inline: var(--container-gutter-phone); }
|
||||
section { padding-block: var(--section-y-phone); }
|
||||
}
|
||||
|
||||
/* ─── Typography — Wise Sans 900 at 0.85, "calt" everywhere ─ */
|
||||
h1, h2, h3 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 900; /* Wise Sans Black — the brand identity */
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
font-feature-settings: "calt" 1;
|
||||
margin: 0;
|
||||
color: var(--fg);
|
||||
}
|
||||
h1 { font-size: var(--text-4xl); }
|
||||
h2 { font-size: var(--text-3xl); }
|
||||
h3 { font-size: var(--text-xl); letter-spacing: -0.015em; line-height: 1.23; }
|
||||
p { margin: 0; }
|
||||
.lead {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--fg);
|
||||
line-height: var(--leading-body);
|
||||
font-weight: 600;
|
||||
}
|
||||
.body-muted { color: var(--muted); }
|
||||
.body-sm { font-size: var(--text-sm); }
|
||||
.eyebrow {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.006em;
|
||||
}
|
||||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||||
|
||||
/* ─── Buttons — pill, green-on-green, scale(1.05) hover ─── */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 12px 22px;
|
||||
border-radius: var(--radius-pill); /* 9999px — all buttons are pills */
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600; /* Inter 600 — confident, not light */
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
font-feature-settings: "calt" 1;
|
||||
letter-spacing: -0.006em;
|
||||
transition: background-color var(--motion-fast) var(--ease-standard),
|
||||
transform var(--motion-fast) var(--ease-standard);
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn:hover { transform: scale(1.05); } /* DESIGN.md §4 — buttons physically grow */
|
||||
.btn:active { transform: scale(0.95); } /* DESIGN.md §4 — compresses on press */
|
||||
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||||
/* Primary: Wise Green pill with Dark Green text — the signature CTA */
|
||||
.btn-primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on);
|
||||
}
|
||||
.btn-primary:hover { background: var(--accent-hover); }
|
||||
.btn-primary:active { background: var(--accent-active); }
|
||||
/* Secondary: subtle dark-green tint pill */
|
||||
.btn-secondary {
|
||||
background: rgba(22, 51, 0, 0.08); /* DESIGN.md §4 — dark green at 8% */
|
||||
color: var(--fg);
|
||||
}
|
||||
.btn-secondary:hover { background: rgba(22, 51, 0, 0.14); }
|
||||
|
||||
/* ─── Inputs — pill borders, ring focus ──────────────────── */
|
||||
.field { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.field label { font-size: var(--text-sm); font-weight: 600; }
|
||||
.field input {
|
||||
padding: 14px 18px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600;
|
||||
outline: none;
|
||||
transition: border-color var(--motion-fast) var(--ease-standard),
|
||||
box-shadow var(--motion-fast) var(--ease-standard);
|
||||
}
|
||||
.field input:focus-visible {
|
||||
border-color: var(--accent-on);
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
.field input::placeholder { color: var(--muted); font-weight: 400; }
|
||||
.field-help { font-size: var(--text-xs); color: var(--muted); }
|
||||
|
||||
/* ─── Cards — 30px radius, ring elevation only ──────────── */
|
||||
.card {
|
||||
background: var(--bg);
|
||||
border-radius: var(--radius-md); /* 30px — Wise's medium feature radius */
|
||||
padding: var(--space-8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
box-shadow: var(--elev-ring); /* Ring shadow only — DESIGN.md §6 */
|
||||
}
|
||||
.card-accent {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
/* ─── Badges ────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex; align-items: center; gap: var(--space-2);
|
||||
padding: 4px var(--space-3);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: var(--text-xs); font-weight: 600; line-height: 1.6;
|
||||
}
|
||||
.badge-success {
|
||||
color: var(--success);
|
||||
background: #e2f6d5; /* Light Mint surface — DESIGN.md §2 */
|
||||
}
|
||||
.badge-muted { color: var(--muted); background: var(--surface); }
|
||||
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
/* ─── Links ─────────────────────────────────────────────── */
|
||||
a { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 2px; }
|
||||
a:hover { color: var(--accent-on); text-decoration-color: var(--accent); }
|
||||
kbd {
|
||||
font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 400;
|
||||
padding: 2px 6px; border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border); background: var(--surface); color: var(--muted);
|
||||
}
|
||||
|
||||
/* ─── Layout helpers ────────────────────────────────────── */
|
||||
.hero-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--space-12); align-items: end; }
|
||||
@media (max-width: 1023px) { .hero-grid { grid-template-columns: 1fr; gap: var(--space-8); } }
|
||||
.hero-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-6); flex-wrap: wrap; }
|
||||
.hero-meta {
|
||||
display: flex; flex-direction: column; gap: var(--space-3);
|
||||
padding: var(--space-6); border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md); background: var(--surface);
|
||||
}
|
||||
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
|
||||
@media (max-width: 1023px) { .features-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 639px) { .features-grid { grid-template-columns: 1fr; } }
|
||||
.form-row { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--space-12); align-items: start; }
|
||||
@media (max-width: 1023px) { .form-row { grid-template-columns: 1fr; } }
|
||||
.form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 460px; }
|
||||
.form-actions { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); }
|
||||
.icon { width: 18px; height: 18px; flex-shrink: 0; }
|
||||
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
|
||||
|
||||
/* Hero headline gets the most extreme Wise treatment */
|
||||
.hero-headline { max-width: 14ch; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<section data-od-id="hero">
|
||||
<div class="hero-grid">
|
||||
<div class="stack-6">
|
||||
<p class="eyebrow">Reference fixture · wise</p>
|
||||
<h1 class="hero-headline">The international account for everyone.</h1>
|
||||
<p class="lead" style="max-width: 50ch">
|
||||
Hold 40+ currencies, send money across borders at the real exchange
|
||||
rate, and get paid like a local — no hidden fees, no fine print.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="./tokens.css" class="btn btn-primary">
|
||||
Open an account
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
<a href="./DESIGN.md" class="btn btn-secondary">Read the spec</a>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="hero-meta" aria-label="Transfer status">
|
||||
<div class="row-between">
|
||||
<span class="body-sm">Transfer status</span>
|
||||
<span class="badge badge-success">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
On its way
|
||||
</span>
|
||||
</div>
|
||||
<p class="body-sm body-muted">Last reviewed <time datetime="2026-05-15">2026-05-15</time> · v1.0</p>
|
||||
<p class="body-sm body-muted">Press <kbd>⌘</kbd> <kbd>K</kbd> to search tokens.</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="features">
|
||||
<div class="stack-3">
|
||||
<p class="eyebrow">What this fixture exercises</p>
|
||||
<h2 style="max-width: 18ch">Money without borders, by design.</h2>
|
||||
</div>
|
||||
<div class="features-grid" style="margin-block-start: var(--space-8)">
|
||||
<article class="card">
|
||||
<h3>Green-on-green CTAs</h3>
|
||||
<p class="body-muted">
|
||||
--accent (#9fe870) paired with --accent-on (#163300) — dark green text
|
||||
on lime green is the Wise signature, not white. Pill radius 9999px.
|
||||
</p>
|
||||
<a href="./tokens.css">Inspect tokens →</a>
|
||||
</article>
|
||||
<article class="card-accent">
|
||||
<h3>Billboard Wise Sans 900</h3>
|
||||
<p class="body-muted">
|
||||
Display headlines run at weight 900 with line-height 0.85 — letters
|
||||
overlap vertically, creating dense text blocks that read like signage.
|
||||
</p>
|
||||
<a href="./DESIGN.md">Read the rule →</a>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Ring-only elevation</h3>
|
||||
<p class="body-muted">
|
||||
--elev-ring (0 0 0 1px rgba(14,15,12,0.12)) is the only depth treatment.
|
||||
No drop shadows; the green accent provides all the visual lift needed.
|
||||
</p>
|
||||
<a href="./tokens.css">Inspect elevation →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-od-id="form">
|
||||
<div class="form-row">
|
||||
<div class="stack-4">
|
||||
<p class="eyebrow">Form components</p>
|
||||
<h2>Sign up in seconds.</h2>
|
||||
<p class="body-muted" style="max-width: 46ch">
|
||||
Inputs sit on the white canvas with hairline ring borders. Focus pulls a
|
||||
green-tinted ring (--focus-ring) and snaps the border to dark green —
|
||||
the same brand family, never a competing color.
|
||||
</p>
|
||||
</div>
|
||||
<form class="form" onsubmit="event.preventDefault();">
|
||||
<div class="field">
|
||||
<label for="email">Email address</label>
|
||||
<input id="email" type="email" placeholder="you@example.com" autocomplete="email" required />
|
||||
<p class="field-help">We'll send your account confirmation here.</p>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Get started</button>
|
||||
<button type="button" class="btn btn-secondary">Learn more</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
141
design-systems/wise/tokens.css
Normal file
141
design-systems/wise/tokens.css
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/* ─────────────────────────────────────────────────────────────────────────
|
||||
* design-systems/wise/tokens.css
|
||||
*
|
||||
* Structured token bindings for "Design System Inspired by Wise".
|
||||
* Money without borders: bright spring-green CTAs on warm-neutral canvas,
|
||||
* billboard Wise Sans at weight 900 with 0.85 line-height, pill buttons,
|
||||
* ring-only shadows, and "calt" everywhere.
|
||||
*
|
||||
* Key brand decisions encoded here:
|
||||
* - Wise Green (#9fe870) as the only accent; Dark Green (#163300) as
|
||||
* --accent-on — green-on-green CTA is THE Wise signature, not white.
|
||||
* - Pastel Green (#cdffad) for hover — lighter, contrast-up, not darker.
|
||||
* - Near-Black with warm green undertone (#0e0f0c), never pure #000.
|
||||
* - Inter weight 600 as body default — confident, not light. Wise Sans
|
||||
* weight 900 for display, line-height 0.85, letter-spacing normal.
|
||||
* - Ring-only elevation: rgba(14,15,12,0.12) 1px ring; no traditional
|
||||
* drop shadows anywhere. Depth comes from green-on-neutral contrast.
|
||||
* - Pill buttons (9999px); cards span 16px → 30px → 40px radius tiers.
|
||||
* - 18px body baseline (not 16px) — Wise reads bigger than typical UI.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
:root {
|
||||
/* ─── Surface ─────────────────────────────────────────────────────
|
||||
* White canvas with a barely-tinted green-gray surface tier. The
|
||||
* background is pure white because the green accent must read as
|
||||
* the only colored element on the page. */
|
||||
--bg: #ffffff; /* Pure white canvas — green pops as the sole accent */
|
||||
--surface: #e8ebe6; /* Light Surface — subtle green-tinted neutral */
|
||||
--surface-warm: var(--surface); /* alias — no warm tier; Wise is cool-green, not warm */
|
||||
|
||||
/* ─── Foreground ──────────────────────────────────────────────────
|
||||
* Near-black with a warm green undertone (#0e0f0c) — never #000.
|
||||
* The faint green in the black ties text to the brand accent. */
|
||||
--fg: #0e0f0c; /* Near Black — primary text, headlines */
|
||||
--fg-2: var(--fg); /* alias — single confident text color */
|
||||
--muted: #868685; /* Gray — captions, tertiary text */
|
||||
--meta: var(--muted); /* alias — same gray for metadata */
|
||||
|
||||
/* ─── Border ──────────────────────────────────────────────────────
|
||||
* Matches the ring-shadow color from DESIGN.md §6 — borders and
|
||||
* ring elevation share the same hairline so cards read as one
|
||||
* unified material. */
|
||||
--border: rgba(14, 15, 12, 0.12); /* Ring hairline — also used by --elev-ring */
|
||||
--border-soft: var(--border); /* alias — no inner separator distinction */
|
||||
|
||||
/* ─── Accent ──────────────────────────────────────────────────────
|
||||
* Wise Green — the brand's most recognizable element. Reserved for
|
||||
* primary CTAs and brand moments; never used as a large surface.
|
||||
* Hover lightens to Pastel Green (Wise's contrast-up convention),
|
||||
* active darkens via color-mix. */
|
||||
--accent: #9fe870; /* Wise Green — primary CTA, brand signal */
|
||||
--accent-on: #163300; /* Dark Green text on Wise Green — THE signature */
|
||||
--accent-hover: #cdffad; /* Pastel Green — lighter on hover, not darker */
|
||||
--accent-active: color-mix(in oklab, var(--accent), black 12%);
|
||||
|
||||
/* ─── Semantic ────────────────────────────────────────────────────
|
||||
* Pulled from Wise's semantic palette in DESIGN.md §2. Positive
|
||||
* is deep green (#054d28) to stay in the brand family rather than
|
||||
* jumping to a generic emerald. */
|
||||
--success: #054d28; /* Positive Green — success state, in-brand */
|
||||
--warn: #ffd11a; /* Warning Yellow — Wise's hover-warn yellow */
|
||||
--danger: #d03238; /* Danger Red — destructive / error */
|
||||
|
||||
/* ─── Typography ──────────────────────────────────────────────────
|
||||
* Wise Sans for display (weight 900 in components), Inter for body
|
||||
* (weight 600 as default). Both stacks enable "calt" at the
|
||||
* component layer. Helvetica/Arial fall back to keep the system
|
||||
* usable when proprietary Wise Sans is unavailable. */
|
||||
--font-display: "Wise Sans", Inter, ui-sans-serif, system-ui, sans-serif;
|
||||
--font-body: Inter, Helvetica, Arial, ui-sans-serif, sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Type scale — DESIGN.md §3. 18px body baseline, 96px hero display.
|
||||
* Wise reads bigger than typical UI; --text-base = 18px is intentional. */
|
||||
--text-xs: 12px; /* Small */
|
||||
--text-sm: 14px; /* Caption */
|
||||
--text-base: 18px; /* Body — confident, larger than typical UI */
|
||||
--text-lg: 22px; /* Feature Title */
|
||||
--text-xl: 26px; /* Card Title */
|
||||
--text-2xl: 40px; /* Sub-heading */
|
||||
--text-3xl: 64px; /* Section Heading */
|
||||
--text-4xl: 96px; /* Display Hero — billboard Wise Sans 900 */
|
||||
|
||||
--leading-body: 1.44; /* Inter body rhythm per DESIGN.md */
|
||||
--leading-tight: 0.85; /* Wise Sans display — letters overlap vertically */
|
||||
--tracking-display: normal; /* DESIGN.md: normal tracking on all Wise Sans display sizes */
|
||||
|
||||
/* ─── Spacing ─────────────────────────────────────────────────────
|
||||
* 8px base unit. Section vertical spacing 80px desktop. */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-12: 48px;
|
||||
|
||||
--section-y-desktop: 80px;
|
||||
--section-y-tablet: 48px;
|
||||
--section-y-phone: 32px;
|
||||
|
||||
/* ─── Radius ──────────────────────────────────────────────────────
|
||||
* Wise's radius vocabulary spans pill buttons to deeply-rounded
|
||||
* cards. Per DESIGN.md §5: 16px (small cards), 30px (medium
|
||||
* features), 40px (large containers/tables), 9999px (all buttons). */
|
||||
--radius-sm: 16px; /* Small cards, inputs — Wise's "card" tier */
|
||||
--radius-md: 30px; /* Medium feature cards */
|
||||
--radius-lg: 40px; /* Large containers, tables — Wise's signature deep round */
|
||||
--radius-pill: 9999px; /* All buttons, badges */
|
||||
|
||||
/* ─── Elevation ───────────────────────────────────────────────────
|
||||
* Ring-only philosophy per DESIGN.md §6. No drop shadows; depth
|
||||
* lives in the green-on-neutral contrast. --elev-raised is kept
|
||||
* extremely subtle (1px ring + whisper of lift) for components
|
||||
* that genuinely need to read as elevated. */
|
||||
--elev-flat: none;
|
||||
--elev-ring: 0 0 0 1px var(--border);
|
||||
--elev-raised: 0 0 0 1px var(--border), 0 2px 8px rgba(14, 15, 12, 0.04);
|
||||
|
||||
/* ─── Focus ring ──────────────────────────────────────────────────
|
||||
* Green-tinted focus ring — keeps the accent visible without
|
||||
* introducing a competing color. */
|
||||
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 60%);
|
||||
|
||||
/* ─── Motion ──────────────────────────────────────────────────────
|
||||
* Standard 150/200ms. Note: the scale(1.05) hover and scale(0.95)
|
||||
* active that DESIGN.md §4 calls out live in component CSS — they
|
||||
* are interaction grammar, not token grammar. */
|
||||
--motion-fast: 150ms;
|
||||
--motion-base: 200ms;
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
|
||||
/* ─── Layout ──────────────────────────────────────────────────────
|
||||
* 1280px container — generous for billboard typography while still
|
||||
* comfortable on standard laptop displays. */
|
||||
--container-max: 1280px;
|
||||
--container-gutter-desktop: 24px;
|
||||
--container-gutter-tablet: 16px;
|
||||
--container-gutter-phone: 12px;
|
||||
}
|
||||
Loading…
Reference in a new issue