# AsqVox Design System — Complete Brand & UI Specification

> **Single-file, portable specification.** Everything needed to reproduce the AsqVox brand on any
> surface, in any tool. Hand this file to a designer, a developer, an AI assistant (Claude, Cursor,
> v0, Lovable, Figma plugins), or paste it into a new repo as the design contract.
>
> **Brand:** AsqVox (formerly AI&Humn) · **Version:** 1.1 · **Updated:** 2026-07-30
> **Token source in code:** `aiw-voice-app/src/design-system/colors_and_type.css`
>
> **v1.1 change —** brand casing is now **always `AsqVox`** (capital `A` + capital `V`). This is a
> brand decision that the codebase has **not** yet been migrated to; see §2.1.1 and §15 item 0.

---

## 0. How to use this file

**For humans:** read §2–§9 for identity and tokens, §10–§13 for applying them.

**For AI tools / code generators:** paste this whole file as context, then instruct:

> Build `<X>` using the AsqVox Design System defined in this document. Use only the CSS custom
> properties in §8. Do not invent new colors, fonts, or scales. Obey the hard rules in §14.

**Core idea in one sentence:** AsqVox is a **monochrome, warm-neutral, typography-led** system —
black text on white and cream, restrained motion, generous whitespace, with a **single yellow**
used only as punctuation (logo, underlines, accents), never as a surface.

**Design lineage:** the palette, type scale, spacing, radii and shadows derive from an
ElevenLabs-style monochrome system, extended with warm cream neutrals and AsqVox's own
voice/call status tokens and "orb" surface.

---

## 1. Design philosophy

Five principles that explain every decision below.

| # | Principle | What it means in practice |
|---|---|---|
| 1 | **Restraint over boldness** | Display headlines are always weight 400 — never 500+. One idea per section. Whitespace is the primary design element. |
| 2 | **Typography does the work** | The system is nearly colourless. Hierarchy comes from size, weight and leading — not colour, borders or boxes. |
| 3 | **Monochrome chrome, warm neutrals** | Pure black + grays for structure; cream tones stop it feeling clinical. Colour is punctuation, not decoration. |
| 4 | **Motion should feel alive, not mechanical** | It's a *voice* product. Organic fades and pulses. Never `spin`, never mechanical easing. |
| 5 | **Accessibility is non-negotiable** | WCAG AA on all body text. Reduced-motion honoured everywhere. One `<h1>` per page. |

---

## 2. Brand identity

### 2.1 Names and constants

| Constant | Value | Usage rules |
|---|---|---|
| **Brand mark** | `AsqVox` | **Capital `A` + capital `V`, always** — see §2.1.1. `SITE_NAME = 'AsqVox'`. One word, never spaced, never hyphenated. |
| **Legal entity** | `AsqVox Technologies Pvt. Ltd.` | Legal docs, JSON-LD `legalName`, invoices, footer copyright. **Never** on a brand-mark surface. ⚠️ Verify registered casing — §2.1.1. |
| **Tagline** | `Voice AI assistants that actually help your customers` | |
| **Short description** (152 chars, SEO) | `Embed a voice AI widget on any website in minutes - visitors click, speak, and get instant answers grounded in your business. 14-day free trial, no card.` | `<meta description>`, OG/Twitter. |
| **Long description** (entity/LLM) | `AsqVox is a voice AI widget for websites - whereby Visitors click, speak, and get answers grounded in your business and in real time.` | Organization + SoftwareApplication JSON-LD. |
| **Primary domain** | `asqvox.com` | |
| **Contact** | `contact@asqvox.com` | The only public contact channel. No phone number. |
| **Social** | `@asqvox` (X/Twitter) | |
| **HQ** | Mumbai, India | |
| **Founded** | 2026 | |

> **Legacy note:** the brand was **AI&Humn** until 2026-06-17. Some internal file names still carry
> the old prefix (e.g. the wordmark asset is `aih-logo.svg`) — filenames were kept to avoid import
> churn. **No visible surface should ever render "AI&Humn" or "AI & Humn".**

#### 2.1.1 ⚠️ Brand casing — ALWAYS `AsqVox`

> **RULE (brand decision, 2026-07-30): the brand is always written `AsqVox`** — capital `A`,
> capital `V`. Never `Asqvox`, never `ASQVOX`, never `asqvox` in prose.

The mid-cap `V` is the brand mark's defining visual signature — it comes from the wordmark's own
letterforms (the SVG `path id` and `aria-label` are `AsqVox`) and must be carried through into
every written surface so text and logo agree.

| Context | Correct | Notes |
|---|---|---|
| Prose, headings, page titles | `AsqVox` | |
| `alt` text, ARIA labels, metadata | `AsqVox` | |
| UI copy, e.g. the widget footer | `Powered by AsqVox` | |
| `SITE_NAME` constant **value** | `'AsqVox'` | It renders to users, so it follows the brand rule |
| Legal entity | `AsqVox Technologies Pvt. Ltd.` | ⚠️ see caveat below |
| SVG `path id` / `aria-label` | `AsqVox` | Already correct |

**Deliberate carve-outs — these stay lowercase** (they are technical identifiers, not the brand
mark, and are case-normalised by the systems that consume them):

| Identifier | Form |
|---|---|
| Domain | `asqvox.com` |
| Email | `contact@asqvox.com` |
| Social handle | `@asqvox` |
| File names, CSS classes, code identifiers, env vars | unchanged (e.g. `aih-logo.svg`, `--aiw-brand`) |

> ⚠️ **Legal-entity caveat.** `AsqVox Technologies Pvt. Ltd.` is a *registered* company name. Its
> casing as filed with the registrar may be fixed and is not ours to restyle unilaterally. Confirm
> the registered form with counsel before changing it on invoices, contracts, or JSON-LD
> `legalName`. If the filing says `Asqvox`, keep the legal string as filed and apply `AsqVox` only
> to the brand mark.

> 📌 **Codebase status: NOT yet migrated.** As of 2026-07-29 the live packages contained
> ~90 occurrences of the old `Asqvox` form (in `SITE_NAME`, page titles, footer, JSON-LD, the
> widget's "Powered by" footer, and both `site.webmanifest` files) against ~15 already-correct
> `AsqVox` (mostly SVG markup). **This document is now the source of truth; the code is the thing
> that is out of date.** See §15 for the migration item.

#### 2.1.2 Punctuation convention

All marketing copy uses a **spaced hyphen `" - "`** as its em-dash substitute — **not** a true
em-dash (`—`) and **not** an en-dash (`–`). Applied consistently across `site.ts`, page content
files and body copy. Match it for typographic consistency.

> *(This specification document itself uses true em-dashes for editorial readability; product and
> marketing copy should follow the spaced-hyphen convention above.)*

### 2.2 Brand voice and tone

**Voice:** confident, plain-spoken, declarative. Short sentences. Statement-first. Never salesy,
never breathless. It sounds like a thoughtful engineer explaining something clearly — not a
marketer selling.

**Authentic examples (verbatim from live copy):**

- "The voice conversion layer for the modern web."
- "Visitors drop off in silence."
- "Chat is fatigued."
- "Phone calls don't scale, and most people won't make one."
- "Three steps. Live in moments."
- "Tell us what you sell."
- "Paste one line."
- "Grounded, never guessing."
- "The web should talk back."

**Observable patterns:**
- Sentences **end in periods**, including headlines and fragments ("Chat is fatigued.").
- Fragments are allowed and encouraged — they create rhythm.
- Second person ("your customers", "tell us what you sell").
- Concrete over abstract ("Paste one line." not "Simple integration").
- Problems stated bluntly before solutions are offered.

**Hard copy rules (apply to ALL UI and marketing text):**

| Rule | ✅ Do | ❌ Don't |
|---|---|---|
| Sentence case | `Saved.` · `Add your content.` | `Successfully Saved!` |
| No exclamation marks | `Saved.` | `Saved!` |
| No emoji in UI chrome | `Listening` | `🎤 Listening` |
| No superlatives | `Fast responses` | `Blazing-fast, world-class` |
| Say what happened | `Saved.` | `Your changes have been successfully persisted` |

### 2.3 Claim discipline (LOCKED — legally and factually binding)

These claims were **removed everywhere**. Do not revive any of them without a measured, defensible
number *and* an explicit brand-wide decision.

| ❌ Forbidden claim | ✅ Approved replacement |
|---|---|
| `HIPAA-ready` | "Enterprise-ready deployments include audit logs and per-tenant isolation" |
| `99.97% uptime` | *(removed — not a measured SLA)* |
| `240+ sites live` | *(removed — no measured number)* |
| `English, Hindi, mixed` / `EN · HI` | "English with strong handling of global accents" |
| `RBI-aligned` | *(removed — reframed as enterprise)* |
| `Avg time-to-first-word: 1.8s` / `under two seconds` | "low latency" |

> **One deliberate exception:** the homepage FAQ answer keeps a concrete `Less than 0.6 sec`,
> because specific Q→A pairs are the retrieval unit for AI/answer-engine optimisation.
>
> **Note:** Hindi is listed as forbidden because it was not live at the time of writing. If/when
> Hindi ships, this row must be revisited as a brand-wide decision.

---

## 3. Logo and brand assets

### 3.1 Wordmark

The primary asset is a **horizontal wordmark** — there is no separate icon-only logotype in the
system.

> The SVG's `aria-label`/`path id` is `AsqVox`, and the drawn letterforms carry that mid-cap
> styling. Written copy — including the `alt` text you pair with the logo — uses the **same**
> `AsqVox` casing, so text and mark always agree (§2.1.1).

| Property | Value |
|---|---|
| File | `aih-logo.svg` *(legacy filename, current AsqVox artwork)* |
| `viewBox` | `0 0 1280 384` |
| Intrinsic size | `500 × 150` |
| Aspect ratio | **3.333 : 1** |
| Fill | Gradient `#g1` (below) + two solid accent shapes |

**Exact gradient definition (copy verbatim):**

```svg
<linearGradient id="g1" x2="1" gradientUnits="userSpaceOnUse"
  gradientTransform="matrix(207.144,-331.5,453.995,283.688,250.678,373.25)">
  <stop offset="0" stop-color="#ffcc00"/>
  <stop offset="1" stop-color="#ff4800"/>
</linearGradient>
```

**Accent shapes inside the wordmark:**

```css
.s0 { fill: url(#g1) }   /* the letterforms — gradient */
.s1 { fill: #ffb900 }    /* chevron under "A" */
.s2 { fill: #ff4800 }    /* caret above "x" */
```

So the logo gradient runs **`#ffcc00` (yellow) → `#ff4800` (orange-red)**, diagonally.

**Two wordmark variants exist — know which you're using:**

| Variant | Files | `viewBox` | Gradient stop order | Accent shapes |
|---|---|---|---|---|
| **Primary (canonical)** | `aih-logo.svg` | `0 0 1280 384` | `#ffcc00` → `#ff4800` | ✅ chevron + caret |
| Plain / secondary | `logo.svg`, `wordmark-dark.svg`, `wordmark-aih-dark.svg`, `favicon.svg` | `0 0 1280 300` | `#ff4800` → `#ffcc00` *(reversed)* | ❌ none |

Both render an orange↔yellow diagonal. **Use `aih-logo.svg` as the canonical primary** — it is the
one wired into the marketing nav, app sidebar and admin topbar, and its filename is imported
everywhere. The reversed stop order in the secondary set is a historical artefact, not a second
brand treatment.

**Usage rules:**
- Always render `width: auto` with a fixed height — never distort the 3.333:1 ratio.
- Standard heights: **32px** (marketing top nav), **24px** (app sidebar, admin topbar).
- Minimum clear space on all sides = the cap-height of the "A".
- Never recolour, outline, rotate, add effects, or place on a busy photographic background.

### 3.2 Favicons and app icons

Complete generated set (identical across marketing, app and admin):

```
favicon.ico                 (multi-size)
favicon-16x16.png
favicon-32x32.png
favicon-48x48.png
favicon-64x64.png
favicon-180x180.png
favicon-192x192.png
favicon-512x512.png
apple-touch-icon.png        (180×180)
android-chrome-192x192.png
android-chrome-512x512.png
```

**Web app manifest:**

```json
{
  "name": "AsqVox",
  "short_name": "AsqVox",
  "icons": [
    { "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
  ],
  "theme_color": "#f5c400",
  "background_color": "#ffffff",
  "display": "standalone"
}
```

### 3.3 Social / OG image

- **File:** `og-default.png` · **Size:** `1200 × 630` · **Alt text:** `AsqVox`
- Used by `og:image` and `twitter:image` (`summary_large_image`) on every route.

### 3.4 Iconography

- **Library:** [`lucide-react`](https://lucide.dev) — the *only* icon library. No Font Awesome,
  no Heroicons, no custom icon fonts.
- Icons inherit `currentColor` and sit on the monochrome scale — never coloured.
- **Brand icons** (LinkedIn / X / YouTube) are **not** in Lucide v1 — hand-rolled SVGs are used
  for those (`SocialIcons.tsx`).
- Decorative icons and illustrations must carry `aria-hidden="true"`.

---

## 4. Colour system

AsqVox runs **two coexisting colour layers**. This is intentional, not drift — understand which
one you're in before picking a value.

### Layer 1 — Core product palette (global `:root`)

Strictly monochrome + warm neutrals. Governs the **app, dashboard, admin panel, widget**, and the
base of the marketing site. **No hue anywhere** except the reserved yellow.

**Base scale**

| Token | Value | Role |
|---|---|---|
| `--color-black` | `#000000` | Primary ink, primary button fill |
| `--color-near-black` | `#101010` | Rare deep surface |
| `--color-white` | `#ffffff` | Primary surface |
| `--color-yellow` | `#feca00` | **Wordmark + reserved accents ONLY** |
| `--color-gray-100` | `#e5e5e5` | Solid visible borders |
| `--color-gray-200` | `#ebe8e4` | Warm gray |
| `--color-gray-300` | `#f2f2f2` | Light fill |
| `--color-gray-500` | `#777169` | Muted text (warm gray, not neutral) |
| `--color-cream-50` | `#fdfcfc` | Faintest cream |
| `--color-cream-100` | `#faf8f8` | Nested surface, idle icon button |
| `--color-cream-200` | `#f5f3f1` | Card / section background |
| `--color-cream-300` | `#f5f2ef` | Deeper cream (orb) |

> The grays are deliberately **warm** (`#777169` has a brown cast, not `#777777`). This is what
> keeps the monochrome system from reading cold or clinical. Do not substitute neutral grays.

**Semantic aliases — use these in components, not the raw scale**

| Token | Resolves to | Role |
|---|---|---|
| `--fg1` | `#000000` | Primary text |
| `--fg2` | `#777169` | Muted / secondary text |
| `--fg3` | `#a8a39c` | Placeholder, very faint |
| `--fg-inverse` | `#ffffff` | Text on dark surfaces |
| `--bg1` | `#ffffff` | Primary surface |
| `--bg2` | `#f5f3f1` | Card / section background |
| `--bg3` | `#faf8f8` | Nested surface |
| `--bg-inverse` | `#000000` | Dark surface |
| `--border1` | `rgba(0,0,0,0.07)` | Default hairline (semi-transparent) |
| `--border2` | `#e5e5e5` | Solid visible border |
| `--border-warm` | `rgb(235,232,228)` | Warm border |

**Voice / call status** — monochrome by design; status is conveyed by weight and fill, not hue.

| Token | Value | Role |
|---|---|---|
| `--status-live` | `#000000` | Active call |
| `--status-idle` | `#777169` | Idle agent |
| `--status-crisis-bg` | `#000000` | Crisis flag background |
| `--status-crisis-fg` | `#ffffff` | Crisis flag foreground |

**The orb** — the one "warm floating surface" in the system.

```css
--orb-bg:     rgba(245, 242, 239, 0.8);
--orb-shadow: rgba(78, 50, 23, 0.04) 0px 6px 16px 0px,
              rgba(0, 0, 0, 0.10) 0px 0px 0px 1px;
```

The `rgba(78,50,23,…)` shadow is a **warm brown**, not black — this is what makes the orb feel
like it's floating on paper rather than glass. Reuse it, don't normalise it to a neutral shadow.

### Layer 2 — Public marketing pages (scoped)

Public marketing pages layer a **warmer ink + a softer yellow family** on top of Layer 1. These
are **scoped to a page container** (e.g. `.landing`, `.about-page`, `.hiw-page`), never global.

```css
.landing {                        /* or .about-page, .hiw-page, … */
  --ink:        #0F0F0E;          /* primary text, dark panel bg, button outlines */
  --ink-2:      #4A4842;          /* secondary text */
  --ink-3:      #8A8676;          /* muted captions, placeholder */
  --bg-cream:   #FBF8F1;          /* warm section / panel background */
  --bg-cream-2: #F4EFE3;          /* deeper cream for gradients */
  --yellow-50:  #FFFBE8;          /* faintest accent */
  --yellow-100: #FFF3C2;          /* faint accent backgrounds */
  --yellow-200: #FFE89A;          /* orb mid-tone */
  --yellow-300: #FFDB6A;          /* PRIMARY ACCENT — the recurring yellow */
  --nline:      rgba(15,15,14,0.08);   /* default hairline */
  --nline-2:    rgba(15,15,14,0.14);   /* visible hairline */
}
```

### 4.1 ⚠️ The yellow question — READ BEFORE PICKING A YELLOW

Five yellows exist in the system. They are **not interchangeable**:

| Yellow | Where it lives | Use it for |
|---|---|---|
| `#ffcc00 → #ff4800` | Logo SVG gradient | **The wordmark only.** Never as a UI colour. |
| `#ffb900` / `#ff4800` | Logo accent shapes | **Inside the wordmark only.** |
| `#feca00` | `--color-yellow`, global token | Wordmark surfaces + reserved accents. |
| `#FFDB6A` | `--yellow-300`, page-scoped | **The recurring UI accent on public pages.** |
| `#f5c400` | `site.webmanifest` `theme_color` | Browser/OS chrome tint. Consistent across app + marketing, but matches no other token. |

**Governing rule (from the design-principles doc):**

> *"Yellow: the landing family (`#FFDB6A` and grades). Don't reintroduce `#feca00` unless we make
> a brand-wide decision."*

**So: for any UI accent, use `#FFDB6A`. Reserve `#feca00` and the logo gradient for the mark itself.**

> **Open item:** the web manifest `theme_color` is `#f5c400` on **both** the app and marketing
> (so it is internally consistent), but it matches no design token. Worth reconciling to `#feca00`
> in a future brand pass.

### 4.2 Where yellow is allowed and forbidden

**✅ Allowed**
- Italic-word underline draw-ins (the `YellowUnderline` signature motif)
- Orb glow (radial-gradient core)
- Accent pill fills
- Primary CTA button fills (climax + closing CTA)
- Stage indicators, progress dots, completion markers
- Hover micro-states (a thin underline drawing under a secondary button)
- Focus rings (`2px solid var(--yellow-300)`)

**❌ Forbidden**
- **Body text at body sizes** — yellow cannot pass WCAG AA on white
- **Large solid backgrounds** — it is a punctuation colour, not a surface colour
- **Two competing yellow elements in one viewport** — pick one

### 4.3 Theming stance

- **There is NO dark mode.** No `prefers-color-scheme` rule exists anywhere in the system. It is a
  deliberate single-theme (light) design. Do not add a dark theme without a brand-wide decision.
- **Per-tenant brand colour** exists only in the embeddable widget (see §11).

---

## 5. Typography

### 5.1 Typefaces

| Role | Font | Weights used | Applied to |
|---|---|---|---|
| **Display** | **Urbanist** | 300, 400, 500, 600 | Hero `h1`, section `h2`/`h3`, statements, pull-quotes, italic accent words |
| **Body** | **DM Sans** | 400, 500, 700 | Sub-headlines, body copy, UI, pills, labels, buttons |
| **Mono** | **Geist Mono** | 400 | Timestamps, micro-labels, code, the occasional caption |
| *Rich content (legacy)* | *Libre Baskerville* | 400–700 | Retained as a fallback face; **not** part of the current active system |

**Google Fonts import (exact):**

```css
@import url('https://fonts.googleapis.com/css2?family=Urbanist:wght@300;400;500;600&family=DM+Sans:wght@400;500;700&family=Geist+Mono:wght@400&display=swap');
```

**Loading strategy by surface**
- **App (Vite):** all three via the `@import` above.
- **Marketing (Next.js):** Urbanist + DM Sans are **self-hosted via `next/font`** so LCP never
  waits on an external request; only Geist Mono uses the `@import`.
- **Widget:** loads **no fonts at all** (see §11).

**Font stacks (declare exactly these):**

```css
--font-display: 'Urbanist', system-ui, sans-serif;
--font-body:    'DM Sans', system-ui, -apple-system, sans-serif;
--font-mono:    'Geist Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
```

> **Historical:** the system previously used **Inter** (body) + **Libre Baskerville** (display).
> It moved to **Urbanist + DM Sans** on 2026-05-14 — Urbanist is geometric with rounded terminals
> that echo the wordmark's letterforms; DM Sans is ~5% wider than Inter and reads better at 14px.

### 5.2 Type scale

Root is `16px`. Sizes are in `rem`.

| Token | rem | px | Typical use |
|---|---|---|---|
| `--text-xs` | `0.63rem` | 10 | Micro-labels |
| `--text-sm` | `0.75rem` | 12 | Badges, chips |
| `--text-sm2` | `0.81rem` | 13 | Code / mono |
| `--text-base` | `0.88rem` | 14 | **Default body size in the app** |
| `--text-md` | `0.94rem` | 15 | Buttons, inputs, labels |
| `--text-lg` | `1.00rem` | 16 | Paragraphs |
| `--text-xl` | `1.13rem` | 18 | Large body |
| `--text-2xl` | `1.25rem` | 20 | `h4`, section leads |
| `--text-3xl` | `2.00rem` | 32 | `h3` |
| `--text-4xl` | `2.25rem` | 36 | `h2` |
| `--text-5xl` | `3.00rem` | 48 | `h1` |
| `--text-6xl` | `4.00rem` | 64 | Marketing only |

**Weights:** `--font-light: 300` · `--font-regular: 400` · `--font-medium: 500` · `--font-bold: 700`

**Line heights:** `--leading-tight: 1.08` · `--leading-snug: 1.13` · `--leading-normal: 1.40` ·
`--leading-relaxed: 1.50` · `--leading-loose: 1.60`

**Letter spacing:** `--tracking-tight: -0.96px` · `--tracking-wide: 0.28px` · `--tracking-wider: 0.70px`

### 5.3 Semantic type styles (app / product UI)

| Element | Family | Size | Weight | Line height | Extra |
|---|---|---|---|---|---|
| `h1`, `.h1` | display | `--text-5xl` (48) | 300 | 1.08 | `letter-spacing: -0.96px` |
| `h2`, `.h2` | display | `--text-4xl` (36) | 300 | 1.17 | |
| `h3`, `.h3` | display | `--text-3xl` (32) | 300 | 1.13 | |
| `h4`, `.h4` | body | `--text-2xl` (20) | 500 | 1.35 | |
| `.section-lead` | body | `--text-2xl` (20) | 400 | 1.35 | `color: --fg2` |
| `p`, `.p` | body | `--text-lg` (16) | 400 | 1.40 | |
| `.body-lg` | body | `--text-xl` (18) | 400 | 1.60 | |
| `.body-base` | body | `--text-lg` (16) | 400 | 1.40 | |
| `.label-sm` | body | `--text-md` (15) | 500 | 1.47 | |
| `.caption` | body | `--text-base` (14) | 400 | 1.43 | `tracking-wide`, `color: --fg2` |
| `.badge-label` | body | `--text-base` (14) | 700 | 1.10 | `tracking-wider`, `UPPERCASE` |
| `code`, `.mono` | mono | `--text-sm2` (13) | 400 | 1.69 | |

**Base body:** `font-family: --font-body; font-size: --text-base (14px); font-weight: 400;
line-height: 1.50; color: --fg1; background: --bg1`.

### 5.4 Display sizing for marketing pages (fluid)

Public marketing pages use **fluid `clamp()`** sizing, larger than the app scale:

| Use | Size | Weight | Letter-spacing | Line-height |
|---|---|---|---|---|
| Hero `h1` | `clamp(40px, 7vw, 92px)` | 400 | `-1.5px` | 1.05 |
| Section `h2` (large) | `clamp(36px, 5vw, 64–72px)` | 400 | `-1.2px` | 1.05 |
| Section `h2` (medium) | `clamp(28px, 4vw, 52px)` | 400 | `-0.8px` | 1.10 |
| Statement (list item) | `clamp(28px, 4vw, 38px)` | 400 | `-0.6px` | 1.30 |
| Lead phrase | `clamp(22px, 2.5vw, 28px)` | 400 | `-0.4px` | 1.20 |
| Sub-headline (italic) | `clamp(22px, 3vw, 30px)` | 300 *italic* | — | 1.35 |

**Marketing body sizing:** lead paragraph 19–20px `--ink` · body 17–18px `--ink-2` ·
body on dark panel 17px `rgba(255,255,255,0.72)` · caption 13–14px `--ink-3` or
`rgba(255,255,255,0.6)` on dark.

**Eyebrow labels:** 12–13px, DM Sans **500**, `UPPERCASE`, `letter-spacing: 0.10em`,
`color: rgba(15,15,14,0.5)`.

### 5.5 Typography hard rules

1. **Display headlines are ALWAYS weight 400** on marketing (300 in the app's semantic styles) —
   **never 500 or higher**. Restraint, not boldness.
2. **Tight leading on display (1.05–1.3), generous on body (1.4–1.7).**
3. **Mono is for labels, never body copy.**
4. **Italic accent words** use the display face's italic cut, and are the anchor for the
   `YellowUnderline` motif. Exactly one per page — like a watermark.
5. **Never introduce a new typeface.**

---

## 6. Spacing, radius, elevation, motion tokens

### 6.1 Spacing (8px grid)

```css
--space-px: 1px;      --space-0-5: 0.125rem;  --space-1: 0.25rem;
--space-2: 0.5rem;    --space-2-5: 0.5625rem; --space-3: 0.75rem;
--space-3-5: 0.875rem;--space-4: 1rem;        --space-4-5: 1.125rem;
--space-5: 1.25rem;   --space-6: 1.5rem;      --space-7: 1.75rem;
--space-8: 2rem;      --space-10: 2.5rem;     --space-12: 3rem;
--space-16: 4rem;     --space-18: 4.5rem;     --space-40: 10rem;
```

### 6.2 Border radius

| Token | Value | Use |
|---|---|---|
| `--radius-sm` | `2px` | Micro elements |
| `--radius-md` | `4px` | **Inputs** |
| `--radius-lg` | `8px` | Small containers |
| `--radius-xl` | `16px` | Panels |
| `--radius-2xl` | `20px` | Large panels |
| `--radius-3xl` | `24px` | Marketing panels (mobile climax shell) |
| `--radius-card` | `20px` | **Cards** |
| `--radius-pill` | `9999px` | **Buttons, badges, chips** |

> Marketing climax panels use **36px desktop / 24px mobile** shared outer silhouettes.

### 6.3 Shadows

```css
--shadow-card:
  rgba(0,0,0,0.06) 0px 0px 0px 1px,
  rgba(0,0,0,0.04) 0px 1px 2px 0px,
  rgba(0,0,0,0.04) 0px 2px 4px 0px;

--shadow-inset-light:
  rgb(255,255,255) 0px 0px 0px 0px inset,
  rgba(0,0,0,0.075) 0px 0px 0px 0.5px inset;

--shadow-inset-medium:
  rgb(255,255,255) 0px 0px 0px 0px inset,
  rgba(0,0,0,0.10) 0px 0px 0px 0.5px inset;

--shadow-elevated:
  rgba(0,0,0,0.06) 0px 0px 0px 1px,
  rgba(0,0,0,0.04) 0px 1px 2px 0px,
  rgba(0,0,0,0.04) 0px 2px 4px 0px;

--shadow-warm:
  rgba(78,50,23,0.04) 0px 6px 16px 0px,
  rgba(0,0,0,0.10) 0px 0px 0px 1px;

--shadow-sm:
  rgba(0,0,0,0.08) 0px 0px 0px 0.5px,
  rgba(0,0,0,0.04) 0px 1.677px 3.354px 0px;
```

Shadows are **layered hairline + soft diffusion**, never a single blurry drop shadow. The first
layer is always a 0.5–1px ring that does the structural work.

### 6.4 Transitions

```css
--transition-fast:   150ms ease;   /* hover, opacity */
--transition-normal: 200ms ease;   /* transforms */
--transition-slow:   300ms ease;   /* larger surfaces */
```

### 6.5 Breakpoints

| Token | Value | Notes |
|---|---|---|
| `--bp-sm` | `480px` | Small mobile |
| `--bp-lg` | `1024px` | Desktop |
| *(convention)* | `880px` | **The real collapse breakpoint** used across landing/marketing layouts |
| *(convention)* | `960px` | Marketing section padding step-down |

**Max content widths (marketing):** full section `1200px` · prose `800px` ·
centred narrative `720px` · climax outer shell `1392px` (deliberately wider, so it feels
"uncontained").

**Section vertical padding (marketing):** desktop `120px 32px` · ≤960px `80px 20px` ·
climax section `60px 24px` (its inner panels add their own 80–96px).

---

## 7. Components

### 7.1 Buttons

All buttons are **pill-shaped** (`--radius-pill`), body font, no border by default.

| Variant | Background | Text | Border | Hover |
|---|---|---|---|---|
| `.btn-primary` | `#000000` | `#ffffff` | none | `opacity: .85` (active `.7`) |
| `.btn-secondary` | `#ffffff` | `#000000` | `1px solid #e5e5e5` | `bg: #f5f3f1` |
| `.btn-ghost` | `transparent` | `#000000` | none | `bg: #faf8f8` |
| `.btn-icon` | `#faf8f8` | `#000000` | none | `bg: #f5f3f1` |
| `.btn-warm` | `--orb-bg` + `blur(8px)` | `#000000` | none | — |

**Sizes:** default `height: 40px; padding: 0 1rem; font-size: 15px` ·
`.btn-sm` `height: 32px; padding: 0 .875rem; font-size: 14px` ·
`.btn-lg` `height: 48px; padding: 0 1.25rem; font-size: 16px` ·
`.btn-icon` `36 × 36px`.

```css
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  white-space: nowrap;
  font-family: var(--font-body);
  border-radius: var(--radius-pill);
  border: none; cursor: pointer;
  transition: opacity var(--transition-fast), background-color var(--transition-fast);
  height: 40px; padding: 0 var(--space-4); gap: var(--space-2);
  font-size: var(--text-md); font-weight: var(--font-regular);
}
```

`.btn-warm` is the distinctive "floating" CTA: the orb surface + warm shadow + `backdrop-filter:
blur(8px)`, `border-radius: 30px`, `font-size: 18px`.

### 7.2 Cards

```css
.card        { background: var(--bg1); border-radius: 20px; box-shadow: var(--shadow-card); padding: 1.5rem; }
.card-subtle { background: var(--bg2); border-radius: 20px; border: 1px solid var(--border1); padding: 1.5rem; }
```

### 7.3 Inputs

```css
.input-text {
  font-family: var(--font-body); font-size: var(--text-md);
  background: #ffffff; color: #000000;
  border: 1px solid var(--color-gray-100);
  border-radius: var(--radius-md);          /* 4px — inputs are the ONE square-ish element */
  padding: var(--space-3) var(--space-4);
  box-shadow: var(--shadow-inset-medium);
  width: 100%; height: 40px;
  transition: box-shadow var(--transition-fast);
}
.input-text:focus       { outline: 2px solid #000000; outline-offset: 0; }
.input-text::placeholder{ color: var(--fg3); }
```

> Inputs are the only component using a small radius (4px) — the inset shadow plus tight radius is
> what makes a field read as "recessed" against the pill-shaped buttons.

### 7.4 Badges / chips

```css
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 var(--space-2-5);
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500;
  border-radius: var(--radius-pill);
  background: var(--bg2); color: var(--fg2);
  letter-spacing: var(--tracking-wide);
}
.badge-live   { background: #000; color: #fff; }
.badge-crisis { background: #000; color: #fff; text-transform: uppercase;
                letter-spacing: var(--tracking-wider); font-weight: 700; font-size: var(--text-sm); }
```

### 7.5 Dividers and links

```css
.divider     { border: none; border-top: 1px solid var(--border1); width: 100%; }
a            { color: inherit; text-decoration: none; }
.link-muted  { color: var(--fg2); text-decoration: underline;
               text-decoration-color: rgb(215, 210, 204); }
```

---

## 8. Complete token stylesheet (copy-paste ready)

Drop this in as the foundation of any new AsqVox surface. It is the canonical superset.

```css
/* ===================================================================
   AsqVox Design System — Tokens
   Monochrome chrome + warm cream neutrals. Single (light) theme.
   =================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Urbanist:wght@300;400;500;600&family=DM+Sans:wght@400;500;700&family=Geist+Mono:wght@400&display=swap');

:root {
  /* ─── COLOR PALETTE ──────────────────────────────────── */
  --color-black:        #000000;
  --color-near-black:   #101010;
  --color-white:        #ffffff;
  --color-yellow:       #feca00;            /* wordmark + reserved accents only */

  --color-gray-100:     #e5e5e5;
  --color-gray-200:     #ebe8e4;
  --color-gray-300:     #f2f2f2;
  --color-gray-500:     #777169;

  --color-cream-50:     #fdfcfc;
  --color-cream-100:    #faf8f8;
  --color-cream-200:    #f5f3f1;
  --color-cream-300:    #f5f2ef;

  /* ─── SEMANTIC ALIASES (use these in components) ─────── */
  --fg1:                var(--color-black);
  --fg2:                var(--color-gray-500);
  --fg3:                #a8a39c;
  --fg-inverse:         var(--color-white);

  --bg1:                var(--color-white);
  --bg2:                var(--color-cream-200);
  --bg3:                var(--color-cream-100);
  --bg-inverse:         var(--color-black);

  --border1:            rgba(0, 0, 0, 0.07);
  --border2:            var(--color-gray-100);
  --border-warm:        rgb(235, 232, 228);

  /* ─── VOICE / CALL STATUS (monochrome) ───────────────── */
  --status-live:        var(--color-black);
  --status-idle:        var(--color-gray-500);
  --status-crisis-bg:   var(--color-black);
  --status-crisis-fg:   var(--color-white);

  /* ─── THE ORB (only warm floating surface) ───────────── */
  --orb-bg:             rgba(245, 242, 239, 0.8);
  --orb-shadow:         rgba(78, 50, 23, 0.04) 0px 6px 16px 0px,
                        rgba(0, 0, 0, 0.10) 0px 0px 0px 1px;

  /* ─── TYPOGRAPHY ─────────────────────────────────────── */
  --font-display:  'Urbanist', system-ui, sans-serif;
  --font-body:     'DM Sans', system-ui, -apple-system, sans-serif;
  --font-mono:     'Geist Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --text-xs:   0.63rem;   /* 10px */
  --text-sm:   0.75rem;   /* 12px */
  --text-sm2:  0.81rem;   /* 13px */
  --text-base: 0.88rem;   /* 14px */
  --text-md:   0.94rem;   /* 15px */
  --text-lg:   1.00rem;   /* 16px */
  --text-xl:   1.13rem;   /* 18px */
  --text-2xl:  1.25rem;   /* 20px */
  --text-3xl:  2.00rem;   /* 32px */
  --text-4xl:  2.25rem;   /* 36px */
  --text-5xl:  3.00rem;   /* 48px */
  --text-6xl:  4.00rem;   /* 64px - marketing only */

  --font-light:   300;
  --font-regular: 400;
  --font-medium:  500;
  --font-bold:    700;

  --leading-tight:   1.08;
  --leading-snug:    1.13;
  --leading-normal:  1.40;
  --leading-relaxed: 1.50;
  --leading-loose:   1.60;

  --tracking-tight: -0.96px;
  --tracking-wide:   0.28px;
  --tracking-wider:  0.70px;

  /* ─── SPACING (8px grid) ─────────────────────────────── */
  --space-px:  1px;
  --space-0-5: 0.125rem;
  --space-1:   0.25rem;
  --space-2:   0.5rem;
  --space-2-5: 0.5625rem;
  --space-3:   0.75rem;
  --space-3-5: 0.875rem;
  --space-4:   1rem;
  --space-4-5: 1.125rem;
  --space-5:   1.25rem;
  --space-6:   1.5rem;
  --space-7:   1.75rem;
  --space-8:   2rem;
  --space-10:  2.5rem;
  --space-12:  3rem;
  --space-16:  4rem;
  --space-18:  4.5rem;
  --space-40:  10rem;

  /* ─── RADIUS ─────────────────────────────────────────── */
  --radius-sm:   2px;
  --radius-md:   4px;
  --radius-lg:   8px;
  --radius-xl:   16px;
  --radius-2xl:  20px;
  --radius-3xl:  24px;
  --radius-card: 20px;
  --radius-pill: 9999px;

  /* ─── SHADOWS ────────────────────────────────────────── */
  --shadow-card:
    rgba(0, 0, 0, 0.06) 0px 0px 0px 1px,
    rgba(0, 0, 0, 0.04) 0px 1px 2px 0px,
    rgba(0, 0, 0, 0.04) 0px 2px 4px 0px;

  --shadow-inset-light:
    rgb(255, 255, 255) 0px 0px 0px 0px inset,
    rgba(0, 0, 0, 0.075) 0px 0px 0px 0.5px inset;

  --shadow-inset-medium:
    rgb(255, 255, 255) 0px 0px 0px 0px inset,
    rgba(0, 0, 0, 0.10) 0px 0px 0px 0.5px inset;

  --shadow-elevated:
    rgba(0, 0, 0, 0.06) 0px 0px 0px 1px,
    rgba(0, 0, 0, 0.04) 0px 1px 2px 0px,
    rgba(0, 0, 0, 0.04) 0px 2px 4px 0px;

  --shadow-warm:
    rgba(78, 50, 23, 0.04) 0px 6px 16px 0px,
    rgba(0, 0, 0, 0.10) 0px 0px 0px 1px;

  --shadow-sm:
    rgba(0, 0, 0, 0.08) 0px 0px 0px 0.5px,
    rgba(0, 0, 0, 0.04) 0px 1.677px 3.354px 0px;

  /* ─── TRANSITIONS ────────────────────────────────────── */
  --transition-fast:   150ms ease;
  --transition-normal: 200ms ease;
  --transition-slow:   300ms ease;

  /* ─── BREAKPOINTS ────────────────────────────────────── */
  --bp-sm:  480px;
  --bp-lg:  1024px;
}

/* ─── PUBLIC MARKETING PAGE LAYER (scope to a page root) ── */
.landing, .about-page, .hiw-page {
  --ink:        #0F0F0E;
  --ink-2:      #4A4842;
  --ink-3:      #8A8676;
  --bg-cream:   #FBF8F1;
  --bg-cream-2: #F4EFE3;
  --yellow-50:  #FFFBE8;
  --yellow-100: #FFF3C2;
  --yellow-200: #FFE89A;
  --yellow-300: #FFDB6A;   /* primary UI accent */
  --nline:      rgba(15,15,14,0.08);
  --nline-2:    rgba(15,15,14,0.14);
}

/* ─── BASE ─────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--font-regular);
  line-height: var(--leading-relaxed);
  color: var(--fg1);
  background: var(--bg1);
}

/* ─── SEMANTIC TYPOGRAPHY ──────────────────────────────── */
h1, .h1 { font-family: var(--font-display); font-size: var(--text-5xl); font-weight: var(--font-light); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); }
h2, .h2 { font-family: var(--font-display); font-size: var(--text-4xl); font-weight: var(--font-light); line-height: 1.17; }
h3, .h3 { font-family: var(--font-display); font-size: var(--text-3xl); font-weight: var(--font-light); line-height: var(--leading-snug); }
h4, .h4 { font-family: var(--font-body);    font-size: var(--text-2xl); font-weight: var(--font-medium); line-height: 1.35; }
.section-lead { font-family: var(--font-body); font-size: var(--text-2xl); font-weight: var(--font-regular); line-height: 1.35; color: var(--fg2); }
p, .p     { font-family: var(--font-body); font-size: var(--text-lg); font-weight: var(--font-regular); line-height: var(--leading-normal); }
.body-lg  { font-family: var(--font-body); font-size: var(--text-xl); font-weight: var(--font-regular); line-height: var(--leading-loose); }
.body-base{ font-family: var(--font-body); font-size: var(--text-lg); font-weight: var(--font-regular); line-height: var(--leading-normal); }
.label-sm { font-family: var(--font-body); font-size: var(--text-md); font-weight: var(--font-medium); line-height: 1.47; }
.caption  { font-family: var(--font-body); font-size: var(--text-base); font-weight: var(--font-regular); line-height: 1.43; letter-spacing: var(--tracking-wide); color: var(--fg2); }
.badge-label { font-family: var(--font-body); font-size: var(--text-base); font-weight: var(--font-bold); line-height: 1.10; letter-spacing: var(--tracking-wider); text-transform: uppercase; }
code, .mono  { font-family: var(--font-mono); font-size: var(--text-sm2); font-weight: var(--font-regular); line-height: 1.69; }

/* ─── BUTTONS ──────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  white-space: nowrap; font-family: var(--font-body);
  border-radius: var(--radius-pill); border: none; cursor: pointer;
  transition: opacity var(--transition-fast), background-color var(--transition-fast);
  height: 40px; padding: 0 var(--space-4); gap: var(--space-2);
  font-size: var(--text-md); font-weight: var(--font-regular); text-decoration: none;
}
.btn-sm { height: 32px; padding: 0 var(--space-3-5); font-size: var(--text-base); }
.btn-lg { height: 48px; padding: 0 var(--space-5);   font-size: var(--text-lg); }

.btn-primary   { background: var(--color-black); color: var(--color-white); }
.btn-primary:hover  { opacity: 0.85; }
.btn-primary:active { opacity: 0.7; }
.btn-secondary { background: var(--color-white); color: var(--color-black); border: 1px solid var(--color-gray-100); }
.btn-secondary:hover { background: var(--color-cream-200); }
.btn-ghost     { background: transparent; color: var(--color-black); }
.btn-ghost:hover { background: var(--color-cream-100); }
.btn-icon      { width: 36px; height: 36px; padding: 0; background: var(--color-cream-100); color: var(--color-black); border-radius: var(--radius-pill); }
.btn-icon:hover{ background: var(--color-cream-200); }
.btn-warm {
  display: inline-flex; align-items: center; gap: var(--space-3);
  font-family: var(--font-body); font-size: var(--text-xl); font-weight: var(--font-regular);
  background: var(--orb-bg); color: var(--color-black);
  padding: var(--space-3) var(--space-5); border-radius: 30px; border: none;
  box-shadow: var(--shadow-warm); backdrop-filter: blur(8px); cursor: pointer;
}

/* ─── CARD / INPUT / BADGE / DIVIDER / LINK ────────────── */
.card        { background: var(--bg1); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: var(--space-6); }
.card-subtle { background: var(--bg2); border-radius: var(--radius-card); border: 1px solid var(--border1); padding: var(--space-6); }

.input-text {
  font-family: var(--font-body); font-size: var(--text-md);
  background: var(--color-white); color: var(--color-black);
  border: 1px solid var(--color-gray-100); border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4); box-shadow: var(--shadow-inset-medium);
  outline: transparent solid 2px; width: 100%; height: 40px;
  transition: box-shadow var(--transition-fast);
}
.input-text:focus        { outline: 2px solid var(--color-black); outline-offset: 0; }
.input-text::placeholder { color: var(--fg3); }

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 var(--space-2-5);
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--font-medium);
  border-radius: var(--radius-pill); background: var(--bg2); color: var(--fg2);
  letter-spacing: var(--tracking-wide);
}
.badge-live   { background: var(--color-black); color: var(--color-white); }
.badge-crisis { background: var(--status-crisis-bg); color: var(--status-crisis-fg); text-transform: uppercase; letter-spacing: var(--tracking-wider); font-weight: var(--font-bold); font-size: var(--text-sm); }

.divider    { border: none; border-top: 1px solid var(--border1); width: 100%; }
a           { color: inherit; text-decoration: none; }
.link-muted { color: var(--fg2); text-decoration: underline; text-decoration-color: rgb(215, 210, 204); }

/* ─── MOTION ───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
```

---

## 9. Page composition — the marketing page formula

Applies to every public marketing page **except the homepage** (which has its own denser rhythm).

### 9.1 Page rhythm

Every page is **8–12 sections** with a deliberate emotional shape:

```
quiet → quiet → LOUD climax → quiet → quiet → personal → quiet → loud-but-restrained → minimal
```

Reference structure (10 sections):

| § | Type | Weight |
|---|---|---|
| 1 | Hero | quiet, declarative |
| 2 | **Visual climax** | **heavy** |
| 3 | Plain-spoken answer | quiet, 2-col |
| 4 | Manifesto block | quiet, centred |
| 5 | Quick scannable | quiet, list-style |
| 6 | Personal / human | medium, framed media |
| 7 | List of principles | quiet, list-style |
| 8 | Trajectory / time | quiet, scroll-linked |
| 9 | Closing CTA | medium, loud-but-restrained |
| 10 | Footer-adjacent | minimal |

**Mandatory:** a quiet hero · one visual climax in the first third · a personal/human moment in the
middle · a closing CTA before the footer-adjacent section.

### 9.2 The visual climax rule

> **Every page must have exactly one section that breaks the rhythm.**
> *"Don't have a climax? You don't have a page yet — you have a list of sections."*

Established climax patterns:
- **Dual-panel** — a black panel + cream panel touching at a straight edge, sharing one rounded
  silhouette (36px desktop / 24px mobile). For problem→resolution arguments.
- **Single dark panel** — one bold dark surface in a rounded shell. Easier, almost as striking.
- **Single cream/warm panel** — softer; good for personal pages.

The climax earns the **biggest motion budget** — the only place with three coordinated motion
moments. Every other section gets one, max.

### 9.3 Layout

- **Grid:** 2-column with media at 50/50 or 45/55 (45/55 when prose carries more weight).
  Dual-panel climax: 60/40 inside the dark half, 55/45 inside the light half.
- **Vertical rhythm:** between text blocks inside a section 32–64px; between statements in a
  centred manifesto block 56px desktop / 32px mobile.

---

## 10. Motion language

**The brand is restraint.** Most sections get exactly one fade-up. Two or three sections per page
(typically hero, climax, closing CTA) earn a "signature" moment.

### Standard fade-up — every section gets this

```ts
initial:     { opacity: 0, y: 24 }
whileInView: { opacity: 1, y: 0 }
viewport:    { once: true, amount: 0.15–0.30 }
transition:  { duration: 0.6–0.7, ease: [0.22, 1, 0.36, 1] }
```

`[0.22, 1, 0.36, 1]` is the **signature easing curve** — use it everywhere.

### Stagger

```ts
container: { transition: { staggerChildren: 0.06–0.14, delayChildren: 0.05–0.10 } }
item:      same fade-up, duration 0.5–0.6
```

Gap by density: sparse (3 manifesto blocks) **140ms** · medium (4–6 cards) **80–100ms** ·
tight (word-stagger in a headline) **60ms**.

### The recurring motif — yellow underline draw

A yellow underline that draws in under one italic accent phrase. **Same speed, easing, colour and
thickness every time** — the consistency is what makes it a signature. Exactly one per page.

### Hard motion rules

1. `<MotionConfig reducedMotion="user">` MUST wrap every public page.
2. Every CSS animation MUST be paired with a `@media (prefers-reduced-motion: reduce)` block that
   zeroes durations.
3. **Never animate `top`/`left`/`width`/`height`.** Use `transform` and `opacity` only.
4. **Never use `animation: spin`** or anything implying mechanical movement — a voice product
   should feel organic, not mechanical.
5. **Only one scroll-linked section per page.** More than one makes the page feel busy.
6. Continuous loops (orb pulse, idle drift, shimmer, blinking cursor) are **CSS `@keyframes` only**
   — never a JS animation library, since they run indefinitely.
7. Motion library is **Framer Motion** only. No Lottie, no Rive, no GSAP.

### ⚠️ Scroll-reveal gotcha

If you implement scroll reveals with `IntersectionObserver`, the visible-state class **must** be
`is-visible` (`.reveal.is-visible`, `.reveal-stagger.is-visible > *`). The pre-reveal default is
`opacity: 0`. Adding any other class name leaves elements **permanently invisible with no console
error** — this shipped as a live bug once.

---

## 11. The embeddable widget (special surface)

The voice widget is a `<script>` drop-in on third-party sites, rendering into a **shadow DOM**. It
has unique constraints.

### Constraints

1. **All CSS is inlined** into the shadow root — no external stylesheet, no `@import`.
2. **No web fonts are loaded at all** (CSP + no network round-trip from the customer's origin).
   Font families are declared as *first-choice-if-already-present*, with system fallbacks.
3. All tokens are **prefixed `--aiw-*`** and declared on `:host` to avoid collision with the host
   page's CSS.

### Widget tokens

```css
:host {
  --aiw-fg1: #000000;
  --aiw-fg2: #777169;
  --aiw-fg-inverse: #ffffff;
  --aiw-bg1: #ffffff;
  --aiw-bg2: #f5f3f1;
  --aiw-bg3: #faf8f8;
  --aiw-border1: rgba(0, 0, 0, 0.07);
  --aiw-border-warm: rgb(235, 232, 228);

  --aiw-orb-bg: radial-gradient(circle at 40% 35%, #fff, #f5f2ef 60%, #ebe8e4 100%);
  --aiw-orb-shadow: rgba(78, 50, 23, 0.04) 0px 6px 16px 0px,
                    rgba(0, 0, 0, 0.10) 0px 0px 0px 1px;
  --aiw-card-shadow: rgba(0, 0, 0, 0.06) 0px 0px 0px 1px,
                     rgba(0, 0, 0, 0.04) 0px 1px 2px 0px,
                     rgba(0, 0, 0, 0.04) 0px 2px 4px 0px,
                     rgba(78, 50, 23, 0.06) 0px 12px 32px 0px;

  --aiw-brand: var(--aiw-fg1);   /* customer brand colour; falls back to black */

  --aiw-font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --aiw-font-mono:    'Geist Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
  --aiw-font-display: 'Libre Baskerville', Georgia, 'Times New Roman', serif;
}
```

> ⚠️ **Known drift:** the widget still names the *pre-2026-05-14* fonts (Inter / Libre Baskerville)
> rather than Urbanist / DM Sans. Because the widget loads no fonts, these only take effect if the
> host page happens to already serve them — otherwise the system fallback renders. Updating these
> names to `'Urbanist'` / `'DM Sans'` would align the widget with the current brand. See §14.

### The per-tenant brand colour rule

Customers pick a brand colour during onboarding. This is the **one place hue enters the system**:

> *"Use the brand colour in exactly one place — the launcher orb's inner pulse dot via `--aiw-brand`
> set on the shadow host. Everything else stays monochrome cream/black."*

This is a load-bearing principle: it lets every customer feel branded without any customer being
able to break the design system.

### Launcher orb spec

| Property | Value |
|---|---|
| Size | `64 × 64px`, `border-radius: 50%` |
| Position | `fixed; bottom: 24px; right: 24px` |
| `z-index` | `2147483647` (max — must sit above all host content) |
| Surface | `--aiw-orb-bg` radial gradient + `--aiw-orb-shadow` |
| Inner dot | `22 × 22px` circle filled `--aiw-brand` |
| Hover | orb `scale(1.04)`, dot `scale(1.08)` |
| Active | `scale(0.98)` |
| Disabled | `opacity: 0.5; cursor: not-allowed` |
| Live-call ring | `2px solid var(--aiw-brand)` expanding/fading halo, `pointer-events: none` |
| Transition | `transform 200ms ease, opacity 150ms ease` |

**Attribution footer:** entry-plan widgets render a "Powered by AsqVox" link below the controls.

---

## 12. Accessibility (non-negotiable)

- Exactly **one `<h1>` per page** — the hero text.
- Every `<section>` has `aria-labelledby` referencing its headline's `id`.
- Decorative SVGs, illustrations and orbs: `aria-hidden="true"`.
- **WCAG AA contrast** for all body text, on both light and dark surfaces.
- **Yellow on white at body sizes is NOT AA-compliant** — yellow may only be a fill, an underline,
  or a display-sized accent.
- **Focus rings:** `2px solid var(--yellow-300)`, visible on every interactive element.
- Visually-hidden screen-reader headings are allowed where the visible label isn't semantic.
- Captions for video; transcripts linked beneath.
- **Lighthouse target: ≥ 95** on all four pillars.
- Honour `prefers-reduced-motion` — pages must be fully readable and complete with zero animation.

---

## 13. Performance discipline

- Illustrations are **inline SVG components**, not external image fetches.
- Lazy-load any below-the-fold video and image (`loading="lazy"`); the LCP/cover image gets
  `priority`.
- Fonts use `display=swap`; the marketing site self-hosts the two critical faces so LCP never waits
  on a third-party request.
- Keep Framer Motion out of the homepage bundle; rely on per-route code splitting.
- No third-party motion libraries beyond Framer Motion + native CSS.

---

## 14. Hard rules — the non-negotiable list

For quick reference, and ideal to paste as constraints for an AI tool:

1. **Never introduce a new typeface.** Urbanist (display), DM Sans (body), Geist Mono (mono).
2. **Never introduce a new colour token.** Everything resolves to §8.
3. **Display headlines are weight 400** on marketing, **300** in the app. Never 500+.
4. **Yellow is punctuation, never a surface.** Use `#FFDB6A` for UI accents; reserve `#feca00` and
   the logo gradient for the wordmark. Never yellow body text.
5. **No dark mode.** Single light theme by design.
6. **Buttons are pills** (`9999px`). Cards are `20px`. Inputs are `4px`. Nothing else.
7. **One visual climax per page**, one italic accent phrase, one yellow underline.
8. **Only one scroll-linked motion section per page.**
9. **Animate only `transform` and `opacity`.** Never `spin`.
10. **Scroll-reveal class is `is-visible`** — never `revealed`.
11. **Copy is sentence case.** No emoji, no exclamation marks, no superlatives.
12. **Never revive a forbidden claim** (§2.3).
13. **Icons are `lucide-react`**, monochrome, `currentColor`.
14. **In the widget, hue appears in exactly one place** — the orb's inner dot.
15. **Never render "AI&Humn"** on any visible surface.
16. **The brand is ALWAYS written `AsqVox`** — capital `A`, capital `V`. Never `Asqvox`/`ASQVOX`.
    Domains, emails and handles stay lowercase (`asqvox.com`, `@asqvox`).
17. **Use a spaced hyphen `" - "`** as the em-dash substitute in product/marketing copy.

---

## 15. Known drift and open decisions

Tracked honestly so a future brand pass can close them.

| # | Issue | Detail | Suggested resolution |
|---|---|---|---|
| **0** | **Brand casing not yet migrated in code** *(highest priority)* | The 2026-07-30 decision fixes the brand as `AsqVox`. The codebase still renders `Asqvox` in ~90 places: `SITE_NAME`, page titles, footer, JSON-LD (`name`/`legalName`/`alternateName`), OG/Twitter titles, the widget's "Powered by" footer, and `site.webmanifest` (`name` + `short_name`) in both the app and marketing packages. | Case-sensitive sweep `Asqvox` → `AsqVox` across `site-v0/`, `beta-v1/`, `aiw-voice-app/src/`, `aiw-voice-widget/src/`, `aiw-voice-backend/` (incl. `admin/`) and both `site.webmanifest` files. **Do not** touch `asqvox.com`, `contact@asqvox.com`, `@asqvox`, or file names. Then rebuild the widget bundle + redeploy `app`, `marketing`, `widget`. Confirm the legal-entity string with counsel first (§2.1.1). |
| 1 | **Five yellows** | `#feca00` (token), `#FFDB6A` (page accent), `#ffcc00→#ff4800` (logo), `#ffb900` (logo accent), `#f5c400` (manifest) | Ratify `#FFDB6A` as the UI accent, `#feca00` as the brand-mark yellow; fix manifest `theme_color` to `#feca00`. |
| 1b | **Wordmark gradient direction differs between variants** | `aih-logo.svg` is `#ffcc00→#ff4800`; the plain `logo.svg` family is reversed | Canonicalise on `aih-logo.svg`; regenerate or retire the reversed set. |
| 2 | **Widget font names stale** | Widget declares Inter / Libre Baskerville, not Urbanist / DM Sans | Rename to `'Urbanist'` / `'DM Sans'` (still no font loading — fallbacks unchanged). |
| 3 | **Token duplication** | App and marketing each keep their own copy of the token file, deliberately (separate build images) | Acceptable today; extract to a shared package only if drift becomes real. |
| 4 | **Legacy asset filenames** | Wordmark is still `aih-logo.svg`; a legacy `--font-sora` alias points at `--font-display` | Cosmetic; rename in a dedicated sweep. |
| 5 | **OG image is a placeholder** | `og-default.png` carries a "PLACEHOLDER · OG" badge | Replace with final branded 1200×630 artwork. |
| 6 | **Two ink scales** | Core `--fg1/2/3` (`#000`/`#777169`/`#a8a39c`) vs marketing `--ink/-2/-3` (`#0F0F0E`/`#4A4842`/`#8A8676`) | Intentional (product vs editorial warmth). Documented, not a bug. |

---

## 16. One-paragraph brand summary

> **AsqVox** is a voice-AI product brand built on restraint. The visual system is monochrome — true
> black text on white and warm cream surfaces, with deliberately warm grays that keep it from
> reading clinical. Typography carries all hierarchy: Urbanist at light weights for display,
> DM Sans for everything functional, generous whitespace, tight leading on headlines and open
> leading on body. A single yellow (`#FFDB6A`) appears only as punctuation — an underline drawing
> beneath one italic phrase per page, a CTA fill, a focus ring — never as a surface and never as
> text. Every page builds to exactly one visual climax that breaks the rhythm. Motion is organic
> and sparing: one fade-up per section on a `[0.22, 1, 0.36, 1]` curve, never mechanical, always
> respecting reduced-motion. The copy is plain-spoken and declarative — short sentences ending in
> periods, sentence case, no exclamation marks, no superlatives, no unmeasured claims. The result
> should feel calm, confident and engineered — a product that talks back, without shouting.

---

*Generated from the AsqVox codebase, 2026-07-29. Canonical token source:
`aiw-voice-app/src/design-system/colors_and_type.css`.*
