open-design/design-systems/airbnb/tokens.css
chaoxiaoche e62b87b62c
feat(design-systems): add structured tokens for cursor, apple, stripe, airbnb, vercel brands (#1652)
* 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>
2026-05-15 16:53:51 +08:00

261 lines
14 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ─────────────────────────────────────────────────────────────────────────
* design-systems/airbnb/tokens.css
*
* Structured token bindings for the Airbnb design system — pristine
* Canvas White surfaces, a single Rausch coral-pink accent (#ff385c),
* generous soft-circle radii, and Airbnb Cereal VF as the lone type
* family. The system reads like a travel magazine that happens to be
* an app: the interface disappears so the listings can breathe.
*
* This file pre-compiles the values described in `DESIGN.md` into the
* schema shared with every OD design system. Agents should paste the
* `:root { … }` block verbatim into the first `<style>` of an artifact,
* then resolve every value via `var(--*)` from that point on.
*
* Schema notes (brand-specific bindings worth flagging — section
* references point into `DESIGN.md`):
*
* #Bind 1 — --bg and --surface both resolve to Canvas White
* (#ffffff). Airbnb cards sit directly on the page
* without a tonal step; separation comes from the
* Hairline Gray (--border) edge and from the
* photograph inside the card, never from a surface
* tint (§4 Listing Card).
*
* #Bind 2 — --surface-warm binds to Soft Cloud (#f7f7f7), the
* brand-named subsurface tier used for footers, map
* wrappers, and the calendar's middle-of-range dates.
* A real value rather than `var(--surface)` because
* Airbnb publishes a distinct tier here (§2 Surface).
*
* #Bind 3 — --accent-hover and --accent-active are hand-picked,
* NOT formula-derived. DESIGN.md §2 publishes Deep
* Rausch (#e00b41) as the pressed/active state.
* color-mix would overshoot that saturation and
* under-shoot the brand's gradient terminal stop,
* so we hand-bind both states.
*
* #Bind 4 — Radius scale concentrates on the brand's signature
* soft-circle geometry: 8px for buttons/inputs, 14px
* for listing cards (the workhorse), 20px for the
* booking panel and hero photo frames, 9999px for
* the circular icon buttons and avatars that
* punctuate every surface (§5 Border Radius Scale).
*
* #Bind 5 — --elev-raised encodes Airbnb's signature three-
* layer booking-panel shadow verbatim — a 2% hairline
* ring, a 4% short blur, and a 10% medium blur. The
* brand forbids single drop shadows; this stacked
* triple is what gives the booking panel its premium
* anti-aliased perimeter (§6 Depth & Elevation).
*
* #Bind 6 — --focus-ring is 2px solid Ink Black (#222222), NOT
* the schema's accent-tinted default. DESIGN.md §6
* mandates this specific ring so focus reads cleanly
* against full-bleed colorful photography — a Rausch
* ring would disappear against warm sunset shots or
* sea-blue overlays. Pair with the 4px white
* separator ring at circular buttons floating on
* images.
*
* #Bind 7 — --leading-body is 1.43 (generous). Airbnb pairs
* tight display leading (1.181.25) with notably
* open body leading; that two-mode rhythm is why
* the system reads as a travel magazine rather than
* a utility app (§3 Principles).
*
* Brand-specific extensions: none in this revision. The Plus
* Magenta (#92174d) and Luxe Purple (#460479) product-tier accents
* called out in DESIGN.md §2 stay inline at the tier-specific
* components that need them; promoting them to schema slots would
* encourage non-tier surfaces to reach for them.
* ─────────────────────────────────────────────────────────────────── */
:root {
/* ─── Surface (3 levels) ────────────────────────────────────────
* Canvas White is both the page and the card — Airbnb refuses a
* tonal shift between the two. Cards earn their edges from the
* Hairline Gray border and from full-bleed photography. The
* tertiary tier (--surface-warm) is Soft Cloud, used only for
* footer backgrounds, map-view wrappers, and middle-of-range
* date cells in the date picker. */
--bg: #ffffff;
--surface: #ffffff;
--surface-warm: #f7f7f7;
/* ─── Foreground ramp (4 levels) ────────────────────────────────
* Ink Black (#222222) carries roughly ninety percent of every
* page — every heading, every body paragraph, every nav label,
* every price. The brand's near-black is never true #000000.
* Charcoal (--fg-2) is a one-step-down emphasis tier reserved
* for focused-input text. Ash Gray (--muted) is the secondary
* label — "Cottage rentals" subtitles, muted footer links.
* Mute Gray (--meta) is reserved for disabled buttons and
* low-priority metadata. */
--fg: #222222;
--fg-2: #3f3f3f;
--muted: #6a6a6a;
--meta: #929292;
/* ─── Border (2 levels) ─────────────────────────────────────────
* Hairline Gray (#dddddd) is the workhorse — every card-to-card
* divider, every amenity-row separator, every footer-column
* rule. The soft tier is a lighter hairline used to break up
* dense list interiors without competing with the primary card
* edge. */
--border: #dddddd;
--border-soft: #ebebeb;
/* ─── Accent ────────────────────────────────────────────────────
* Rausch coral-pink — the single signature color. Reserve for
* primary CTAs (Reserve, Search, Add dates), the active-tab
* underline, the wishlist heart fill, and price emphasis. Hard
* cap of two visible uses per viewport; if a third Rausch
* element shows up, neutralize one. Plus Magenta (#92174d) and
* Luxe Purple (#460479) are kept inline at their product-tier
* surfaces, not promoted to shared accent slots. */
--accent: #ff385c;
--accent-on: #ffffff;
--accent-hover: #e31c5f; /* hand-picked, between Rausch and Deep Rausch */
--accent-active: #e00b41; /* Deep Rausch — DESIGN.md §2 pressed-state value */
/* ─── Semantic ──────────────────────────────────────────────────
* Error Red is explicit from DESIGN.md §2; success and warn are
* not specified by the brand and are bound to desaturated values
* that survive the white canvas without competing with Rausch.
* Keep total semantic-color pixels well under five percent of
* any page — the brand almost never renders status. */
--success: #008a05; /* hand-picked warm green — available/in-stock */
--warn: #c47700; /* burnt amber — never tailwind yellow */
--danger: #c13515; /* DESIGN.md §2 Error Red */
/* ─── Typography — fonts ────────────────────────────────────────
* Airbnb Cereal VF is the proprietary face that carries every
* label from 8px superscript to 28px section heading. The
* documented fallback chain renders acceptably on macOS/iOS
* where system-ui resolves to San Francisco. Display and body
* share the same stack — the visual identity comes from the
* family itself, never from typeface mixing. Mono is a generic
* stack for kbd, tabular metrics, and the rare code label. */
--font-display:
"Airbnb Cereal VF", "Airbnb Cereal App", Circular,
-apple-system, system-ui, "Helvetica Neue", Roboto, sans-serif;
--font-body:
"Airbnb Cereal VF", "Airbnb Cereal App", Circular,
-apple-system, system-ui, "Helvetica Neue", Roboto, sans-serif;
--font-mono:
ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Monaco,
Consolas, monospace;
/* ─── Typography — type scale (px) ──────────────────────────────
* Derived from DESIGN.md §3 Hierarchy table. The system clusters
* tightly between 11 and 22px (the conversational range) and
* jumps to 28px for section headings; the higher tiers are used
* sparingly for the Guest Favorite rating lockup (4456px) and
* the rare hero numeral. No 400-regular: Cereal's body weight
* is 500, which any consuming component should set explicitly. */
--text-xs: 12px; /* micro / footer disclaimer */
--text-sm: 14px; /* button default, link, caption */
--text-base: 16px; /* body medium, button large, subtitle bold */
--text-lg: 20px; /* listing title */
--text-xl: 22px; /* subsection heading */
--text-2xl: 28px; /* section heading */
--text-3xl: 44px; /* Guest Favorite rating, hero numeral */
--text-4xl: 56px; /* display ceiling — Guest Favorite max */
/* ─── Typography — leading & tracking ───────────────────────────
* Tight for display (1.20 — chiseled headlines), generous for
* body (1.43 — magazine reading comfort). Display tracking
* compresses negatively at sizes ≥20px; body and caption hold
* at zero. The two-mode rhythm is what gives Airbnb pages
* their travel-magazine feel rather than a utility-app feel. */
--leading-body: 1.43;
--leading-tight: 1.2;
--tracking-display: -0.02em; /* applied at sizes ≥20px only */
/* ─── Spacing — base scale ──────────────────────────────────────
* 8px base unit per DESIGN.md §5. The brand uses fine-grained
* off-grid values (5.5, 10, 11, 18.5, 22) for pixel-perfect
* icon alignment, but the shared scale stays on the standard
* 4px grid — off-grid spacing belongs inline at the component
* level, not in shared tokens. */
--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 ────────────────────────────────────────────
* Section padding ranges 4864px on desktop, 2432px on mobile
* per DESIGN.md §5. We bind the upper bound on desktop because
* Airbnb's content-dense pages benefit from generous breathing
* room between content blocks; the lower phone bound keeps the
* vertical rhythm tight on small screens. */
--section-y-desktop: 64px;
--section-y-tablet: 48px;
--section-y-phone: 32px;
/* ─── Radius ────────────────────────────────────────────────────
* The brand's signature soft-circle geometry. 14px (--radius-md)
* is the workhorse — every listing card photograph, every
* amenity badge, every generic content container lands here.
* 20px (--radius-lg) is reserved for the booking panel and hero
* photo frames; 8px (--radius-sm) is the small radius for
* buttons, dropdowns, and inputs; --radius-pill (9999px) is the
* system's signature round geometry, applied to every circular
* icon button, every avatar, and the wishlist heart. */
--radius-sm: 8px;
--radius-md: 14px;
--radius-lg: 20px;
--radius-pill: 9999px;
/* ─── Elevation ─────────────────────────────────────────────────
* Airbnb forbids single drop shadows; the system uses stacked
* layered shadows or no shadow at all. Listing cards sit flat
* on the canvas. Booking panels, modals, and dropdowns use the
* signature three-layer stack — a 2% hairline ring, a 4% short
* blur, and a 10% medium blur — which reads as one cohesive
* lift while giving the perimeter a premium anti-aliased edge. */
--elev-flat: none;
--elev-ring: 0 0 0 1px var(--border);
--elev-raised:
rgba(0, 0, 0, 0.02) 0 0 0 1px,
rgba(0, 0, 0, 0.04) 0 2px 6px 0,
rgba(0, 0, 0, 0.1) 0 4px 8px 0;
/* ─── Focus ring ────────────────────────────────────────────────
* 2px solid Ink Black, NOT the schema's accent-tinted default.
* DESIGN.md §6 mandates this exact treatment so focus indicators
* read cleanly against full-bleed colorful photography — a
* Rausch-tinted ring would disappear against warm sunset shots
* or sea-blue beach overlays. Pair with a 4px white separator
* ring at circular-icon buttons that float on images. */
--focus-ring: 0 0 0 2px var(--fg);
/* ─── Motion ────────────────────────────────────────────────────
* DESIGN.md did not capture transition timings (static
* extraction scope). We bind defaults consistent with the
* brand's tactile feel: 150ms for micro-states (the famous
* `transform: scale(0.92)` pressed-button rebound) and 200ms
* for general state changes. Standard easing is the schema
* default — short, purposeful, no overshoot. */
--motion-fast: 150ms;
--motion-base: 200ms;
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
/* ─── Layout ────────────────────────────────────────────────────
* Detail pages cap at 1280px per DESIGN.md §5; the homepage
* listing grid lets the canvas breathe to 17601920px on
* ultra-wide. We bind the detail-page width as the shared
* default because that is the geometry agents will most often
* generate (rooms, experiences, host profiles). Gutters
* tighten progressively: 40px desktop, 24px tablet, 16px
* phone per DESIGN.md §8 small-mobile clause. */
--container-max: 1280px;
--container-gutter-desktop: 40px;
--container-gutter-tablet: 24px;
--container-gutter-phone: 16px;
}