10 — Experience and Design System
Build anti-AI-slop premium interfaces: dark-first OKLCH color, fluid clamp() type, DTCG tokens, View Transitions on every public-facing surface.
Apple Test — after every design: two elements compete → remove one; crowded → add whitespace; busy type → reduce sizes, increase weight contrast; final feel: effortless, inevitable.
CSS Patterns
- Overlay
rgba(0,0,0,0.81) · Text shadow 1px 1px 1px rgba(255,255,255,0.333) · Box shadow 2px 2px 2px rgba(0,0,0,0.69)
- Border-radius 5px interactive, 10px containers (never 0, never pill)
- Hero padding 40px · Max text 720px · Line-height 1.4
- Letter-spacing: 0.4px labels, 0.5px nav, 1px titles, 1.4px CTAs
- CTA uppercase always · Button 700 always · Reference: Linear, Notion, Stripe
Typography
- Body: Sora 400/500 · Headings: Space Grotesk 600/700 · Mono: JetBrains Mono 400/500 · Display: Clash Display 700 (hero only)
- Variable fonts: WOFF2, subset, self-host (never Google Fonts CDN),
font-display:swap
- Body min 16px (prefer 18) · Line-height 1.6 body, 1.1-1.2 headings · Letter-spacing -0.02em >2rem · Max 65ch
- Never skip levels. Scale: Minor Third 1.2 general, Perfect Fourth 1.333 marketing
text-wrap:balance headings, text-wrap:pretty paragraphs
:root {
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-xl: clamp(1.25rem, 1rem + 1.25vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1.1rem + 2vw, 2rem);
--text-3xl: clamp(2rem, 1.5rem + 2.5vw, 3rem);
--text-4xl: clamp(2.5rem, 1.5rem + 5vw, 4.5rem);
--text-hero: clamp(3rem, 2rem + 5vw, 6rem);
}
Color (Dark Default)
:root {
color-scheme: light dark;
--bg-primary: #060610; --bg-secondary: #0a0a1a; --bg-tertiary: #121225;
--bg-card: #0f0f1f; --bg-elevated: #1a1a35;
--text-primary: #f0f0f5; --text-secondary: #a0a0b5; --text-muted: #606080;
--accent-cyan: #00E5FF; --accent-blue: #50AAE3; --accent-purple: #8B5CF6;
--gradient-primary: linear-gradient(135deg, #00E5FF, #50AAE3);
--gradient-accent: linear-gradient(135deg, #50AAE3, #8B5CF6);
--border-subtle: rgba(255,255,255,0.06); --border-hover: rgba(255,255,255,0.12);
--shadow-sm: 0 1px 2px rgba(0,0,0,0.3); --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
--shadow-lg: 0 8px 32px rgba(0,0,0,0.5); --shadow-glow: 0 0 20px rgba(0,229,255,0.15);
}
- Never
#000 (use #060610) · Never #fff (use #f0f0f5)
- Cyan: primary CTAs · Blue: secondary · Gradients on buttons only · 6% borders · Subtle glow on primary interactive
- Elevation via lightness not shadows: base → surface 1 → surface 2 → surface 3
color-scheme:light dark · data-theme="dark|light" user override · localStorage persistence · prefers-color-scheme system default · Always provide toggle
- OKLCH perceptually uniform ·
color-mix() · Relative oklch(from var(--brand) l c calc(h + 30)) · light-dark() theme-aware
- Contrast 4.5:1 normal, 3:1 large/UI (WCAG 2.2 AA) · Target size min 24×24 px (2.5.8) · Focus 2px thick, 3:1 contrast (2.4.13)
CSS Architecture (2026)
@layer reset, base, tokens, components, utilities, overrides;
- Native nesting · Container queries (
container-type:inline-size, @container) · :has() replaces JS
@scope bounded styling · Anchor positioning replaces Floating UI · Scroll-state queries @container scroll-state(stuck: top) (Baseline 2026)
- CSS
if() · Typed attr() · sibling-index() / sibling-count() stagger: transition-delay: calc((sibling-index() - 1) * 40ms)
appearance:base-select native <select> (Chrome 135+) · @supports for progressive enhancement
- Baseline 2026:
@scope · Anchor positioning · Scroll-state queries · @starting-style · interpolate-size: allow-keywords · field-sizing: content · text-wrap: pretty · @property
W3C DTCG Design Tokens (2025.10 Stable)
- JSON
.tokens / .tokens.json, MIME application/design-tokens+json
- Token:
$value (required), $type, $description, $deprecated, $extensions
- Types: color | dimension | duration | fontFamily | fontWeight | cubicBezier | number + composites (shadow, border, gradient, typography, transition)
- Aliasing:
"$value": "{base.color}" · $ref JSON Pointer · Group $type inheritance · $root for base + variants · $extends for deep merge
- Full Display P3, OKLCH, CSS Color Module 4; naming: no
$ prefix, no {} / . in names
- Tools: Tokens Studio, Style Dictionary, Penpot, Figma
AI-Ready Design Documentation
DESIGN.md: plain-text markdown; sections: Visual Theme, Color Palette, Typography, Spacing + Layout, Components, Elevation
- Atomic docs: context-rich units per component with states, variants, props, constraints, a11y, rationale
- MCP servers (Figma Dev Mode MCP) for programmatic access
Layout
- Container 1140px (wide 1400, narrow 720), padding
clamp(1rem,3vw,3rem)
- Sections
clamp(4rem,8vw,8rem), border between; grid auto-fit minmax(280px,1fr), 1fr at 768px
- Patterns: Hero (full-viewport, centered) · Features (3-col icon+heading+desc) · Alternating (zigzag) · Pricing (3-tier highlighted) · FAQ (accordion) · CTA (full-width dark) · Footer (4-col stack)
- SaaS: Single-CTA 13.5%; Hero / Proof / Features / Demo / Testimonials / Pricing / FAQ / CTA; bento grid for feature showcases
Components
- Cards — bg-card, border-subtle, 12px radius, hover: border-hover + shadow-glow
- Buttons — Primary gradient #060610 text, 600 weight, 8px radius, hover 0.9, active scale(0.98), focus 3px cyan. Secondary: transparent, border, hover cyan
- Nav — sticky,
rgba(6,6,16,0.85), blur(16px)
- Forms — bg-secondary, border-subtle, 8px, focus cyan + glow
- PrimeNG — standalone (not NgModule), OnPush on all, lazy-load heavy (DataTable, Editor, Chart), design tokens for theming
Interaction (every interactive element)
cursor:pointer, hover state, focus-visible (3px cyan, 2px offset), active (scale 0.98), transition (0.2s color, 0.1s transform). WCAG 2.2 — min 24×24px targets, focus not obscured by sticky headers, dragging alternatives required, accessible auth.
4-state distinction (NON-NEGOTIABLE)
Every link/button/card MUST visually differ across :default | :hover | :focus-visible | :active — NEVER let two states look identical.
- Default → neutral · Hover → underline-sweep + color shift +
translateY(-1px) · Focus-visible → 3px cyan ring 2px offset (distinct from hover) · Active → scale(0.98) + immediate color confirm
Audit gate: Playwright cycles each interactive element through 4 states → screenshots → diff ≥3px pixel-difference between adjacent states or fail.
Underline-sweep (text links default)
.underline-hover{position:relative}
.underline-hover::after{content:"";position:absolute;z-index:1;left:51%;right:51%;bottom:0;background:var(--brand-accent);height:1px;transition:left .3s ease-out,right .3s ease-out}
.underline-hover:hover::after,.underline-hover:focus-visible::after{left:0;right:0}
var(--brand-accent) / theme equivalent — never hard-coded #hex.
See submodules: design-tokens.md, build-breaking-rules.md, cinematic-doctrine.md.
1---2name: experience-and-design-system3description: Anti-AI-slop design system for distinctive, premium interfaces. Bold typography, dark-first #060610, fluid clamp() type, cascade layers + native nesting + container queries, OKLCH color, @starting-style, View Transitions API, DTCG tokens.4license: Rutgers5---67# 10 — Experience and Design System89Build anti-AI-slop premium interfaces: dark-first OKLCH color, fluid `clamp()` type, DTCG tokens, View Transitions on every public-facing surface.1011**Apple Test** — after every design: two elements compete → remove one; crowded → add whitespace; busy type → reduce sizes, increase weight contrast; final feel: effortless, inevitable.1213## CSS Patterns1415- Overlay `rgba(0,0,0,0.81)` · Text shadow `1px 1px 1px rgba(255,255,255,0.333)` · Box shadow `2px 2px 2px rgba(0,0,0,0.69)`16- Border-radius 5px interactive, 10px containers (never 0, never pill)17- Hero padding 40px · Max text 720px · Line-height 1.418- Letter-spacing: 0.4px labels, 0.5px nav, 1px titles, 1.4px CTAs19- CTA uppercase always · Button 700 always · Reference: Linear, Notion, Stripe2021## Typography2223- Body: Sora 400/500 · Headings: Space Grotesk 600/700 · Mono: JetBrains Mono 400/500 · Display: Clash Display 700 (hero only)24- Variable fonts: WOFF2, subset, self-host (never Google Fonts CDN), `font-display:swap`25- Body min 16px (prefer 18) · Line-height 1.6 body, 1.1-1.2 headings · Letter-spacing -0.02em >2rem · Max 65ch26- Never skip levels. Scale: Minor Third 1.2 general, Perfect Fourth 1.333 marketing27- `text-wrap:balance` headings, `text-wrap:pretty` paragraphs2829```css30:root {31 --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);32 --text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);33 --text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);34 --text-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);35 --text-xl: clamp(1.25rem, 1rem + 1.25vw, 1.5rem);36 --text-2xl: clamp(1.5rem, 1.1rem + 2vw, 2rem);37 --text-3xl: clamp(2rem, 1.5rem + 2.5vw, 3rem);38 --text-4xl: clamp(2.5rem, 1.5rem + 5vw, 4.5rem);39 --text-hero: clamp(3rem, 2rem + 5vw, 6rem);40}41```4243## Color (Dark Default)4445```css46:root {47 color-scheme: light dark;48 --bg-primary: #060610; --bg-secondary: #0a0a1a; --bg-tertiary: #121225;49 --bg-card: #0f0f1f; --bg-elevated: #1a1a35;50 --text-primary: #f0f0f5; --text-secondary: #a0a0b5; --text-muted: #606080;51 --accent-cyan: #00E5FF; --accent-blue: #50AAE3; --accent-purple: #8B5CF6;52 --gradient-primary: linear-gradient(135deg, #00E5FF, #50AAE3);53 --gradient-accent: linear-gradient(135deg, #50AAE3, #8B5CF6);54 --border-subtle: rgba(255,255,255,0.06); --border-hover: rgba(255,255,255,0.12);55 --shadow-sm: 0 1px 2px rgba(0,0,0,0.3); --shadow-md: 0 4px 12px rgba(0,0,0,0.4);56 --shadow-lg: 0 8px 32px rgba(0,0,0,0.5); --shadow-glow: 0 0 20px rgba(0,229,255,0.15);57}58```5960- Never `#000` (use `#060610`) · Never `#fff` (use `#f0f0f5`)61- Cyan: primary CTAs · Blue: secondary · Gradients on buttons only · 6% borders · Subtle glow on primary interactive62- Elevation via lightness not shadows: base → surface 1 → surface 2 → surface 363- `color-scheme:light dark` · `data-theme="dark|light"` user override · `localStorage` persistence · `prefers-color-scheme` system default · Always provide toggle64- OKLCH perceptually uniform · `color-mix()` · Relative `oklch(from var(--brand) l c calc(h + 30))` · `light-dark()` theme-aware65- Contrast 4.5:1 normal, 3:1 large/UI (WCAG 2.2 AA) · Target size min 24×24 px (2.5.8) · Focus 2px thick, 3:1 contrast (2.4.13)6667## CSS Architecture (2026)6869```css70@layer reset, base, tokens, components, utilities, overrides;71```7273- Native nesting · Container queries (`container-type:inline-size`, `@container`) · `:has()` replaces JS74- `@scope` bounded styling · Anchor positioning replaces Floating UI · Scroll-state queries `@container scroll-state(stuck: top)` (Baseline 2026)75- CSS `if()` · Typed `attr()` · `sibling-index()` / `sibling-count()` stagger: `transition-delay: calc((sibling-index() - 1) * 40ms)`76- `appearance:base-select` native `<select>` (Chrome 135+) · `@supports` for progressive enhancement77- **Baseline 2026**: `@scope` · Anchor positioning · Scroll-state queries · `@starting-style` · `interpolate-size: allow-keywords` · `field-sizing: content` · `text-wrap: pretty` · `@property`7879## W3C DTCG Design Tokens (2025.10 Stable)8081- JSON `.tokens` / `.tokens.json`, MIME `application/design-tokens+json`82- Token: `$value` (required), `$type`, `$description`, `$deprecated`, `$extensions`83- Types: color | dimension | duration | fontFamily | fontWeight | cubicBezier | number + composites (shadow, border, gradient, typography, transition)84- Aliasing: `"$value": "{base.color}"` · `$ref` JSON Pointer · Group `$type` inheritance · `$root` for base + variants · `$extends` for deep merge85- Full Display P3, OKLCH, CSS Color Module 4; naming: no `$` prefix, no `{}` / `.` in names86- Tools: Tokens Studio, Style Dictionary, Penpot, Figma8788## AI-Ready Design Documentation8990- `DESIGN.md`: plain-text markdown; sections: Visual Theme, Color Palette, Typography, Spacing + Layout, Components, Elevation91- Atomic docs: context-rich units per component with states, variants, props, constraints, a11y, rationale92- MCP servers (Figma Dev Mode MCP) for programmatic access9394## Layout9596- Container 1140px (wide 1400, narrow 720), padding `clamp(1rem,3vw,3rem)`97- Sections `clamp(4rem,8vw,8rem)`, border between; grid `auto-fit minmax(280px,1fr)`, 1fr at 768px98- Patterns: Hero (full-viewport, centered) · Features (3-col icon+heading+desc) · Alternating (zigzag) · Pricing (3-tier highlighted) · FAQ (accordion) · CTA (full-width dark) · Footer (4-col stack)99- SaaS: Single-CTA 13.5%; Hero / Proof / Features / Demo / Testimonials / Pricing / FAQ / CTA; bento grid for feature showcases100101## Components102103- **Cards** — bg-card, border-subtle, 12px radius, hover: border-hover + shadow-glow104- **Buttons** — Primary gradient #060610 text, 600 weight, 8px radius, hover 0.9, active scale(0.98), focus 3px cyan. Secondary: transparent, border, hover cyan105- **Nav** — sticky, `rgba(6,6,16,0.85)`, `blur(16px)`106- **Forms** — bg-secondary, border-subtle, 8px, focus cyan + glow107- **PrimeNG** — standalone (not NgModule), OnPush on all, lazy-load heavy (DataTable, Editor, Chart), design tokens for theming108109## Interaction (every interactive element)110111`cursor:pointer`, hover state, focus-visible (3px cyan, 2px offset), active (scale 0.98), transition (0.2s color, 0.1s transform). WCAG 2.2 — min 24×24px targets, focus not obscured by sticky headers, dragging alternatives required, accessible auth.112113### 4-state distinction (NON-NEGOTIABLE)114115Every link/button/card MUST visually differ across `:default | :hover | :focus-visible | :active` — NEVER let two states look identical.116117- Default → neutral · Hover → underline-sweep + color shift + `translateY(-1px)` · Focus-visible → 3px cyan ring 2px offset (distinct from hover) · Active → `scale(0.98)` + immediate color confirm118119Audit gate: Playwright cycles each interactive element through 4 states → screenshots → diff ≥3px pixel-difference between adjacent states or fail.120121### Underline-sweep (text links default)122123```css124.underline-hover{position:relative}125.underline-hover::after{content:"";position:absolute;z-index:1;left:51%;right:51%;bottom:0;background:var(--brand-accent);height:1px;transition:left .3s ease-out,right .3s ease-out}126.underline-hover:hover::after,.underline-hover:focus-visible::after{left:0;right:0}127```128129`var(--brand-accent)` / theme equivalent — never hard-coded #hex.130131## See submodules: design-tokens.md, build-breaking-rules.md, cinematic-doctrine.md.