mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
* feat(design-systems): add structured tokens for cursor brand Introduces design-systems/cursor/tokens.css + components.html, the third structured brand after default and kami. Brings the prose DESIGN.md into the schema-checked form so agents picking the cursor design system get the structured token channel (PR-D #1544) instead of having to re-derive Cursor's warm-cream palette, three-voice typography (CursorGothic / jjannon / berkeleyMono), oklab borders, and depth-based focus from prose every turn. Why now: PR-D made the structured channel default-on, but it only materially helps the 2 brands shipping tokens.css today. To expand batch-design-system-test (#1515) coverage beyond default + kami, we are hand-authoring 5 high-profile brands (cursor first as template, then apple / stripe / airbnb / vercel) before the bulk derive script (PR-B). These five also serve as the byte-identical oracle the future derive script must reproduce. Brand-specific schema decisions, captured in the tokens.css header: - Surface: 3-tier cream ladder (#f2f1ed → #ebeae5 → #e6e5e0). --surface-warm binds to a real intermediate tier, not aliased. - Foreground: 4-tier ramp via rgba(38,37,30,a) at 1.0 / 0.9 / 0.55 / 0.4 — Cursor genuinely has the richer ramp. - Borders: oklab origins shipped as rgba fallbacks per DESIGN.md §Agent Prompt Guide rule 3. - --tracking-display: -0.03em (the 72px hero value normalized to em). Smaller display sizes scale tracking proportionally inline. - --elev-raised: signature 28/70px diffused atmospheric shadow. - --focus-ring: depth-only (0 4px 12px), never the cool-blue halo. - --ease-standard: ease (per DESIGN.md), not the schema cubic-bezier. - --danger: warm crimson #cf2d56, used for the brand-signature hover-text-shift on buttons. components.html demonstrates the full surface (hero with 72px CursorGothic + jjannon serif lead, three-voice typography, warm- surface CTA with crimson hover, accent-orange pill CTA used once, oklab-fallback bordered cards, AI timeline signature element with the warm pastel state colors, jjannon-serif input with 4-12 depth focus). :root paste is byte-identical to tokens.css. Verified: - pnpm guard — 13/13 checks pass, including all 8 design-system sub-checks now reporting "3 brands" (default + kami + cursor): - token-fixture sync: 3 brand pairs aligned - A1/A2/B-slot required tokens: all 3 brands declare 26 A1 + 26 A2 + 4 B-slot - unknown token allowlist: 185 declarations across 3 brands all match shared schema or brand extensions - flag parity: 146 prose-only brands byte-identical, 3 structured diverge as expected Co-authored-by: Cursor <cursoragent@cursor.com> * fix(design-systems): correct h2/h3 line-height in cursor components fixture Per DESIGN.md §Hierarchy, 36px section headings use line-height 1.20 and 26px sub-headings use 1.25. The shared h1/h2/h3 rule was locking all three to --leading-tight (1.10), baking wrong vertical rhythm into the oracle fixture. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(design-systems): add structured tokens for apple, stripe, airbnb, vercel brands Batch follow-up to #1652 (cursor). Adds tokens.css + components.html for the remaining four high-profile brands, using cursor as the format/template oracle. Each brand encodes its specific identity: - apple: SF Pro tight-compressed display (--leading-tight 1.05), system-blue accent, SF Symbols grid, frosted glass surfaces - stripe: sohne-var weight-300 anti-convention signature, --leading-tight 1.10 (matches all heading spec values exactly), indigo accent - airbnb: Cereal weight-700 display with Rausch coral, --leading-tight 1.20 with per-size overrides (h2→1.18, h3→1.25) - vercel: Geist 600 compressed display, --leading-tight 1.10 with per-size overrides (h2→1.20, h3→1.33 per DESIGN.md §Typography) pnpm guard: 13/13 checks pass; flag-parity now shows 6 structured brands and 143 prose-only brands. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local> Co-authored-by: Cursor <cursoragent@cursor.com>
270 lines
16 KiB
CSS
270 lines
16 KiB
CSS
/* ─────────────────────────────────────────────────────────────────────────
|
||
* design-systems/vercel/tokens.css
|
||
*
|
||
* Structured token bindings for "Vercel" — the engineering-as-design
|
||
* thesis of frontend deployment: a near-white canvas, near-black text,
|
||
* one saturated blue accent, and a shadow-as-border philosophy that
|
||
* replaces the box-model edge with a layered box-shadow stack.
|
||
*
|
||
* This file pre-compiles the values described in `DESIGN.md` into the
|
||
* shared schema. Agents generating an artifact for Vercel 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 Vercel's voice rather than the cross-brand default):
|
||
*
|
||
* 1. `--accent` is the Vercel/Console blue (#0070f3), not Vercel Black.
|
||
* Black is already `--fg`; the brand expresses primary CTAs by
|
||
* using `--fg` as the button background, not `--accent`. The
|
||
* `--accent` slot is reserved for the chromatic moments — links,
|
||
* focus rings, badge tints — exactly where Vercel's blue appears
|
||
* in product. Treating black as both `--fg` and `--accent` would
|
||
* collapse two distinct intents into one name and break the
|
||
* lint's "≤2 accent uses per screen" semantic.
|
||
*
|
||
* 2. `--fg` is `#171717` (Vercel Black), not `#000000`. The micro-
|
||
* warmth at the top of the gray ramp is part of the brand — pure
|
||
* black against pure white reads as harsh, and the rest of the
|
||
* neutral scale (gray-600 / 500 / 400 / 100 / 50) is calibrated
|
||
* against `#171717` not `#000000`. Bind the full four-level
|
||
* foreground ramp (#171717 → #4d4d4d → #666666 → #808080) so
|
||
* cross-brand components targeting `--fg-2` and `--meta` resolve
|
||
* to Vercel's actual gray-600 / gray-400 instead of collapsing.
|
||
*
|
||
* 3. `--border` is `rgba(0, 0, 0, 0.08)` — the literal Vercel
|
||
* shadow-as-border alpha, NOT a solid hex. DESIGN.md §1 names
|
||
* this single value as "the signature" that "replaces traditional
|
||
* borders throughout". Binding `--border` to the alpha lets
|
||
* `--elev-ring` (`0 0 0 1px var(--border)`) reproduce the Vercel
|
||
* hairline by default, and lets components reach the same value
|
||
* via `border: 1px solid var(--border)` when a real border is
|
||
* structurally necessary (e.g. image cards). `--border-soft`
|
||
* drops to `0.04` for inner-row separators that must not compete.
|
||
*
|
||
* 4. `--elev-raised` is the full multi-layer Vercel card stack
|
||
* (`0 0 0 1px rgba(0,0,0,0.08), 0 2px 2px rgba(0,0,0,0.04),
|
||
* 0 8px 8px -8px rgba(0,0,0,0.04), 0 0 0 1px #fafafa`), not the
|
||
* schema's single soft blur. The inner `#fafafa` ring at the
|
||
* bottom of the stack is the "subtle inner glow" DESIGN.md §6
|
||
* calls out — without it, Vercel cards lose the built-not-
|
||
* floating quality. The fourth layer's `#fafafa` is the only
|
||
* raw hex inside the `:root` block, justified because the value
|
||
* is structural to the shadow layer, not a recolorable surface.
|
||
*
|
||
* 5. `--focus-ring` is a solid 2px ring at `var(--accent)`, not the
|
||
* schema's 3px alpha glow. Vercel's `--ds-focus-color` focus
|
||
* outline is `2px solid hsla(212, 100%, 48%, 1)` everywhere;
|
||
* reproducing it as a sharp 2px box-shadow keeps keyboard focus
|
||
* legible against the white canvas without the soft halo that
|
||
* would dilute the engineered feel.
|
||
*
|
||
* 6. The type scale tops out at 48px (`--text-4xl`), not 64px+.
|
||
* DESIGN.md §3 caps display at 48px Geist W600 with
|
||
* `letter-spacing: -2.4px` (which expresses as `-0.05em` in
|
||
* `--tracking-display`). Vercel reads HUGE because the tracking
|
||
* compresses, not because the px count climbs. `--leading-tight`
|
||
* drops to `1.1` to match — display lines run shorter than the
|
||
* schema default's 1.2.
|
||
*
|
||
* 7. Section rhythm is generous: `96px` desktop, `64px` tablet,
|
||
* `48px` phone (`--section-y-*`). DESIGN.md §5 describes the
|
||
* "gallery emptiness" of 80–120px+ vertical padding between
|
||
* sections — the whitespace is the design. Container caps at
|
||
* `1200px` (Vercel's documented 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 Geist family does not
|
||
* need a CDN reference here — the font stack lists OS fallbacks so
|
||
* that artifacts render acceptably even when Geist is not loaded,
|
||
* and any host that wants the real Geist face links it externally.
|
||
* ─────────────────────────────────────────────────────────────────── */
|
||
|
||
:root {
|
||
/* ─── Surface (3 levels — schema slot) ─────────────────────────────
|
||
* Vercel's canvas is famously achromatic: pure white page, pure
|
||
* white cards, no warm tier. `--surface-warm` aliases to surface
|
||
* because the brand explicitly forbids background-color variation
|
||
* between sections — depth comes from shadow layering, not from
|
||
* tinting one surface warmer than another. (DESIGN.md §5: "White
|
||
* sections alternate with white sections — there's no color
|
||
* variation between sections.") */
|
||
--bg: #ffffff;
|
||
--surface: #ffffff;
|
||
--surface-warm: var(--surface); /* alias — Vercel has no warm tier */
|
||
|
||
/* ─── Foreground ramp (4 levels) ──────────────────────────────────
|
||
* Gray 900 → 600 → 500 → 400, the documented neutral scale from
|
||
* DESIGN.md §2. `#171717` instead of `#000000` matters — the
|
||
* yellow-undertone warmth is what keeps the page from reading as
|
||
* harsh. `--fg-2` and `--meta` are independently bound (not aliased)
|
||
* because Vercel genuinely uses four distinct text tiers: heading
|
||
* black, body description gray, tertiary caption gray, and
|
||
* placeholder/disabled gray. */
|
||
--fg: #171717; /* Gray 900 — headings, primary text */
|
||
--fg-2: #4d4d4d; /* Gray 600 — body description */
|
||
--muted: #666666; /* Gray 500 — captions, tertiary text */
|
||
--meta: #808080; /* Gray 400 — placeholder, disabled */
|
||
|
||
/* ─── Border (2 levels) ──────────────────────────────────────────
|
||
* Shadow-as-border is THE signature: `rgba(0, 0, 0, 0.08)` at 1px
|
||
* spread replaces traditional borders throughout. Binding `--border`
|
||
* to the alpha (not a solid hex) lets `--elev-ring` reproduce the
|
||
* Vercel hairline by default, and lets `border: 1px solid var(--border)`
|
||
* paint the same value when a real border is structurally required
|
||
* (e.g. image-card top edge per DESIGN.md §4). `--border-soft`
|
||
* drops to 0.04 alpha for inner row separators that should not
|
||
* visually compete with the card edge. */
|
||
--border: rgba(0, 0, 0, 0.08); /* signature shadow-as-border alpha */
|
||
--border-soft: rgba(0, 0, 0, 0.04); /* inner row separator */
|
||
|
||
/* ─── Accent ─────────────────────────────────────────────────────
|
||
* The single chromatic move: Vercel/Console Blue. Used in links,
|
||
* focus rings, pill-badge tints, and console syntax highlighting.
|
||
* Hard cap of ≤2 visible uses per screen — DESIGN.md §7 forbids
|
||
* decorative use ("Color is functional, never decorative — workflow
|
||
* colors (Red/Pink/Blue) mark pipeline stages only").
|
||
*
|
||
* Primary CTAs in Vercel are BLACK, not blue. components.html
|
||
* encodes that pattern via `background: var(--fg)` on the primary
|
||
* button, so `--accent` stays reserved for the chromatic moments
|
||
* where blue actually appears. */
|
||
--accent: #0070f3; /* Vercel Blue / Console Blue */
|
||
--accent-on: #ffffff; /* white label on saturated blue */
|
||
--accent-hover: color-mix(in oklab, var(--accent), black 8%);
|
||
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||
|
||
/* ─── Semantic ───────────────────────────────────────────────────
|
||
* Vercel's marketing surface rarely renders state. We inherit the
|
||
* schema defaults (no warm-shift) because the brand has no defined
|
||
* success/warn/danger palette of its own; the workflow accents
|
||
* (Ship Red, Preview Pink, Develop Blue from DESIGN.md §2) are
|
||
* pipeline labels, not status colors, and intentionally do NOT
|
||
* bind here. */
|
||
--success: #16a34a;
|
||
--warn: #eab308;
|
||
--danger: #dc2626;
|
||
|
||
/* ─── Typography ─────────────────────────────────────────────────
|
||
* Geist Sans is Vercel's open-source typeface — `--font-display`
|
||
* and `--font-body` share the stack; size, weight, and tracking
|
||
* carry hierarchy, not face. The Arial/system fallbacks come from
|
||
* DESIGN.md §3 and ensure artifacts render legibly even when Geist
|
||
* is not loaded. Geist Mono for code and technical labels
|
||
* preserves the "developer console voice" that connects the
|
||
* marketing site to the product. */
|
||
--font-display: "Geist", "Geist Sans", -apple-system, "Segoe UI", Arial, sans-serif;
|
||
--font-body: "Geist", "Geist Sans", -apple-system, "Segoe UI", Arial, sans-serif;
|
||
--font-mono: "Geist Mono", ui-monospace, "SF Mono", "Roboto Mono", Menlo, Monaco, "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace;
|
||
|
||
/* Type scale (px) — derived from DESIGN.md §3 hierarchy table.
|
||
* The scale tops out at 48px (display hero); Vercel reads BIG
|
||
* because of -0.05em compression on display, not because of a
|
||
* larger px ceiling. */
|
||
--text-xs: 12px; /* caption, metadata, tags */
|
||
--text-sm: 14px; /* button, link, small UI */
|
||
--text-base: 16px; /* body small, navigation */
|
||
--text-lg: 20px; /* body large, introductions */
|
||
--text-xl: 24px; /* card title */
|
||
--text-2xl: 32px; /* sub-heading, large card */
|
||
--text-3xl: 40px; /* section heading */
|
||
--text-4xl: 48px; /* display hero */
|
||
|
||
/* `--leading-tight` is 1.1 (DESIGN.md says 1.00–1.17 at display),
|
||
* `--leading-body` is 1.5 (the documented 16px / 24px ratio).
|
||
* `--tracking-display` is `-0.05em`, the em-relative form of
|
||
* Vercel's `-2.4px at 48px` — letter-spacing in em scales
|
||
* proportionally with size, matching DESIGN.md §3's principle
|
||
* that "tracking scales with font size". */
|
||
--leading-body: 1.5;
|
||
--leading-tight: 1.1;
|
||
--tracking-display: -0.05em;
|
||
|
||
/* ─── Spacing ────────────────────────────────────────────────────
|
||
* 4px-grid base scale. Vercel's documented spacing (DESIGN.md §5)
|
||
* uses 1–6px sub-tier increments for micro-padding (button
|
||
* `0px 6px`, etc.); those are inlined per-component because they
|
||
* are too fine to belong in the shared schema. The 4/8/12/16/20/
|
||
* 24/32/48 tier 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: 80–120px+ vertical padding between
|
||
* sections desktop, collapsing to 48px on mobile. We sit in the
|
||
* middle at 96px desktop, drop to 64px on tablet (still generous),
|
||
* and 48px on phone (the documented mobile floor). */
|
||
--section-y-desktop: 96px;
|
||
--section-y-tablet: 64px;
|
||
--section-y-phone: 48px;
|
||
|
||
/* ─── Radius ─────────────────────────────────────────────────────
|
||
* DESIGN.md §5 radius scale: 2/4/6/8/12/64/100/9999. We bind the
|
||
* four schema tiers to: 6 (button/input/functional), 8 (card),
|
||
* 12 (image/featured card), 9999 (badge/pill). The 64px and
|
||
* 100px "navigation pill" radii from DESIGN.md are component-
|
||
* specific and not part of the shared schema. */
|
||
--radius-sm: 6px; /* buttons, inputs, functional */
|
||
--radius-md: 8px; /* cards, modals */
|
||
--radius-lg: 12px; /* image cards, featured */
|
||
--radius-pill: 9999px; /* badges, status pills */
|
||
|
||
/* ─── Elevation (3 levels) ───────────────────────────────────────
|
||
* Vercel's depth system is shadow-LED, not blur-led. Three levels:
|
||
*
|
||
* --elev-flat no shadow (page background, text blocks)
|
||
* --elev-ring the signature 1px shadow-as-border (most surfaces)
|
||
* --elev-raised the multi-layer Vercel card stack (featured cards)
|
||
*
|
||
* `--elev-raised` is reproduced VERBATIM from DESIGN.md §6 Level 3,
|
||
* including the inner `#fafafa` 1px ring that DESIGN.md calls out
|
||
* as "the glow that makes the system work" — never drop the last
|
||
* layer when overriding this token. The four layers compose:
|
||
* ring (1px shadow-as-border, sits on top)
|
||
* close (2px 2px soft elevation, just below the surface)
|
||
* far (8px blur -8px spread, ambient depth at distance)
|
||
* inner (1px #fafafa ring, the subtle highlight) */
|
||
--elev-flat: none;
|
||
--elev-ring: 0 0 0 1px var(--border);
|
||
--elev-raised:
|
||
0 0 0 1px rgba(0, 0, 0, 0.08),
|
||
0 2px 2px rgba(0, 0, 0, 0.04),
|
||
0 8px 8px -8px rgba(0, 0, 0, 0.04),
|
||
0 0 0 1px #fafafa;
|
||
|
||
/* ─── Focus ring ─────────────────────────────────────────────────
|
||
* Vercel's `--ds-focus-color` is `hsla(212, 100%, 48%, 1)`; the
|
||
* outline is `2px solid` on every interactive element. We
|
||
* reproduce that as a sharp 2px box-shadow at `var(--accent)`,
|
||
* NOT the schema's 3px alpha glow — Vercel's focus is engineered,
|
||
* not atmospheric. */
|
||
--focus-ring: 0 0 0 2px var(--accent);
|
||
|
||
/* ─── Motion ─────────────────────────────────────────────────────
|
||
* Two durations + one easing curve, per anti-ai-slop's "short,
|
||
* purposeful transitions (150–250ms) with stable easing". Vercel
|
||
* transitions are quick and unobtrusive — never a long-form
|
||
* choreographed entrance. */
|
||
--motion-fast: 150ms;
|
||
--motion-base: 200ms;
|
||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||
|
||
/* ─── Layout ─────────────────────────────────────────────────────
|
||
* 1200px max content width per DESIGN.md §5. Gutters narrow on
|
||
* mobile to preserve the line-length-as-craft feel — Vercel does
|
||
* NOT edge-bleed body copy on phones, only screenshots. */
|
||
--container-max: 1200px;
|
||
--container-gutter-desktop: 24px;
|
||
--container-gutter-tablet: 16px;
|
||
--container-gutter-phone: 12px;
|
||
}
|