# 03 — Visual Design System: "Signal on Paper"

**Idea:** a financial-grade growth consultancy that writes like an editor and draws like an engineer. Warm paper, near-black ink, and exactly one electric colour: *signal indigo*. The indigo always means the same thing — the path money takes through the system. It is never decoration.

**Memorable detail:** the first screen is a photograph of people at work, the headline set on the calm wall beside them and the animated signal map docked over the photograph's lower edge: the people and the system in one frame.

---

## Colour

Tokens are CSS custom properties exposed to Tailwind v4 via `@theme`. Ratios below are computed with the WCAG 2 relative-luminance formula.

| Token | Hex | Role | Contrast |
|---|---|---|---|
| `paper` | `#F4F2ED` | Page background (warm off-white) | — |
| `paper-deep` | `#EAE6DE` | Alternate sections, panels | — |
| `surface` | `#FBFAF7` | Raised surfaces on paper | — |
| `ink` | `#101014` | Primary text, primary lines | 17.0:1 on paper |
| `ink-soft` | `#3B3B42` | Secondary text | 9.9:1 on paper |
| `muted` | `#5F5F67` | Tertiary text, metadata | 5.7:1 paper · 5.1:1 paper-deep |
| `line` | `#DCD8CF` | Hairlines (decorative) | — |
| `line-strong` | `#86817A` | Input borders, dividers that carry meaning | 3.4:1 paper · 3.7:1 surface (non-text) |
| `signal` | `#3326FF` | Accent: CTAs, active states, revenue path | 6.6:1 paper · white text 7.3:1 |
| `signal-deep` | `#2419D9` | Hover/pressed accent | 8.5:1 paper |
| `signal-bright` | `#8F8AFF` | Accent on dark | 6.7:1 on night |
| `signal-mist` | `#E7E6FF` | Accent tint, selection, focus halo | — |
| `night` | `#0D0D11` | Dark sections | — |
| `night-raised` | `#16161C` | Panels on dark | — |
| `night-line` | `#2B2B33` | Hairlines on dark | — |
| `night-text` | `#F4F2ED` | Text on dark | 17.3:1 |
| `night-muted` | `#A3A2AC` | Secondary text on dark | 7.7:1 |
| `mist` | `#E6E6F1` | SaaS panel tone (pale, cool) | — |
| `sand` | `#EDE4D6` | E-commerce panel tone (pale, warm) | — |

Rules
- One accent. Indigo marks the path to revenue, the primary CTA, focus, and active state. Nothing else.
- SaaS and e-commerce are distinguished by *tone* (mist vs sand) and by diagram shape (line vs loop), never by a second accent.
- No gradient text, no neon glow, no purple-to-blue gradients. Gradients are only pale veils over imagery.
- Selection colour: `signal-mist` background, `ink` text.

## Typography

| Role | Family | Why |
|---|---|---|
| Display + UI + body | **Schibsted Grotesk** (variable 400–900) | Built for news media: editorial authority with a sharp, contemporary grotesk voice. Not a default SaaS face. |
| Editorial accent | **Newsreader Italic** (opsz) | One word per major headline at most. Adds the magazine note; never used for body. |
| Data labels | **IBM Plex Mono** 400/500 | Only inside diagrams, charts, metric codes, and the "Illustrative data" tag, where tabular alignment matters. |

Scale (fluid for display, fixed for body):

| Token | Size | Line height | Tracking | Weight |
|---|---|---|---|---|
| `display-xl` | `clamp(2.75rem, 1.1rem + 5.4vw, 5.5rem)` → 44–88px | 0.96 | -0.045em | 500 |
| `display-lg` | `clamp(2.35rem, 1.3rem + 3.6vw, 4.25rem)` → 38–68px | 1.0 | -0.04em | 500 |
| `display-md` | `clamp(1.9rem, 1.2rem + 2.2vw, 3.1rem)` → 30–50px | 1.05 | -0.035em | 500 |
| `title` | `clamp(1.35rem, 1.1rem + 0.7vw, 1.75rem)` → 22–28px | 1.15 | -0.02em | 500 |
| `lead` | `clamp(1.125rem, 1.02rem + 0.35vw, 1.3rem)` → 18–21px | 1.5 | -0.005em | 400 |
| `body` | `1rem` / `1.0625rem` ≥ lg | 1.62 | 0 | 400 |
| `small` | `0.875rem` | 1.5 | 0 | 400 |
| `label` | `0.75rem` uppercase | 1.2 | 0.09em | 600 |
| `data` | `0.6875rem` mono | 1.3 | 0.02em | 500 |

Rules
- Headlines are left-aligned, sentence case, and end with a full stop — it reads as a statement, not a slogan.
- Measure: body max `64ch`; lead max `46ch`.
- Numerals in data use `tabular-nums`.
- Italic accent colour stays `ink` (or `night-text`); indigo underline only on the hero accent word.

## Grid, spacing, shape

- 12-column grid, `max-width: 1360px`, inline padding `clamp(1.25rem, 4vw, 3rem)`, gutter `1.5rem` (1rem < 640px).
- Section padding `clamp(5rem, 3rem + 6vw, 9rem)`; tight groups use 8/12/16px, separations 48/64/96px.
- Asymmetry by default: headings span 7 columns, intros sit in columns 8–12 aligned to the heading baseline.
- Radii: `4px` (chips, inputs), `8px` (buttons, small panels), `14px` (media, large panels). Never pill-everything.
- Borders: 1px hairlines. No drop shadows on cards; elevation is expressed by `surface` against `paper`.
- Grain: an SVG noise tile at 3% opacity on paper and 6% on night, fixed to the section, never animated.
- **No section labels.** Section headings stand alone (client direction, 2026-09-18); the numbered `§ 03 — Label` line was removed everywhere. `Eyebrow` survives only for page heroes, the closing CTA, and article headers, without a number.

## Components (styling contract)

| Component | Spec |
|---|---|
| Primary button | `signal` fill, white text, 8px radius, 48px height (44px compact). Hover: an ink disc expands from the pointer position (transform scale, 450ms expo-out); arrow nudges 3px. Magnetic pull ≤ 6px on fine pointers only. |
| Secondary button | 1px `line-strong` border, ink text; hover fills `paper-deep`. |
| On dark | Primary becomes paper fill + ink text (highest contrast); hover fill = `signal`, text white. |
| Text link | Ink text, 1px underline offset 4px at 30% opacity → 100% on hover, arrow translate. |
| Chip | 4px radius, 1px `line`, `small` text; active = `signal-mist` fill + `signal` text. |
| Panel | `surface` on `paper`, 14px radius, 1px `line`. On night: `night-raised`, `night-line`. |
| Focus ring | 2px `signal` outline, 3px offset; on dark `signal-bright`. Always visible for keyboard. |
| Form field | 48px, `surface`, 1px `line-strong`, 4px radius; focus ring as above; errors in text + icon, never colour alone. |

## Data visualisation

- Charts are hand-drawn SVG: 1px strokes, square caps, no gridline clutter, labels in `data` mono.
- Every chart with values is tagged **ILLUSTRATIVE DATA** in the chart frame and captioned "Not client results or benchmarks". Preferred: no axis values at all — relative shapes make the point.
- Indigo = the revenue-relevant series. Ink = comparison series. Dashed = platform-reported or modelled.
- Diagrams must teach one idea each (e.g. "platform ROAS can rise while MER stays flat").

## Imagery

- **Photoreal people at work**, generated with Higgsfield (client direction, 2026-09-17): candid, documentary scenes of SaaS and e-commerce teams in warm ivory and pale oak interiors, with one indigo accent object. See `06-higgsfield-asset-prompts.md`.
- **Never presented as our team.** No names or roles, no people imagery on the About page, and alt text that describes the scene, not an identity.
- **Never:** readable dashboards or invented numbers on screens, device or brand logos, people looking at the camera, handshakes, stock-photo posing, rockets, 3D blobs.
- **Resource covers are photographs** of the work each guide describes: close, detail-led frames (hands, printouts, a tablet) that stay distinct from the wider scenes elsewhere. They run on every card and on the article header, with the format and category as a mono label under the photograph.
- **Living-photo loops** (home "Working together" team review, final CTA) are silent, `muted`, `playsinline`, start after load, pause off-screen, and fall back to the still under `prefers-reduced-motion` or Save-Data.
- **Diagrams explain; photographs carry the human context.** The signal map, Revenue Circuit, and charts stay drawn. On the home page the six service cards and the two growth-model panels use photographs of the work itself (client direction, 2026-09-17). Each service photograph keeps its numbered one-line caption, and a module without a photograph falls back to its drawn schematic.
- **Text over photographs** sits on calm negative space with a paper veil (≤ 62% opacity) behind the text column. Small labels over a photograph use `ink-soft`, not `muted`, to keep 4.5:1.
- **Vary the cast.** Give each prompt an age, hair, and clothing description. Left generic, the model repeats one default person (dark hair in a bun, light knit sweater) across scenes.

## Third-party marks

- **Platforms are shown with their official marks**, in their own colours, about 28px optically, paired with the platform name in Schibsted Grotesk (client direction, 2026-09-18). This is the one place the single-accent rule gives way, because brand guidelines expect official colours.
- **The platform section is a two-row marquee**: full-bleed pills drifting in opposite directions, top row right and bottom row left, masked to fade at both edges. Each row repeats its set five times and shifts by exactly one set, so the loop is seamless and never runs out on wide screens. It pauses on hover or focus, and under `prefers-reduced-motion` the rows stop, drop the repeats, and sit inside the page container as static wrapped pills.
- **Sources.** `public/logos/*.svg`: Iconify's "SVG Logos" set (CC0) for Google Ads, Meta, LinkedIn, Microsoft, GA4, Tag Manager, Search Console, Shopify and Salesforce; Simple Icons (CC0) for the HubSpot sprocket and Stripe mark, filled with each brand's own hex; the Klaviyo flag extracted from Klaviyo's own logo. The marks are trademarks of their owners.
- **The footnote stays.** Listing a platform describes where we work, and does not imply a partnership, certification, or endorsement. LinkedIn, Microsoft and Salesforce restrict logo use, so a client or counsel check before launch is worthwhile.

## Motion

| Token | Value | Use |
|---|---|---|
| `ease-out-expo` | `cubic-bezier(0.16, 1, 0.3, 1)` | Reveals, menus, fills |
| `ease-out-quart` | `cubic-bezier(0.25, 1, 0.5, 1)` | Hover, small state changes |
| `ease-in-out` | `cubic-bezier(0.65, 0, 0.35, 1)` | Toggles, crossfades |
| `dur-micro` | 160ms | Colour, underline |
| `dur-state` | 320ms | Hover, toggles |
| `dur-reveal` | 800ms | Section reveals (16px rise + fade) |
| `dur-headline` | 1000ms | Hero line mask reveal, 90ms stagger |
| `stagger` | 70ms | Cards and list items |

Patterns: hero line reveal (CSS, runs before hydration) · reveal-on-enter (one IntersectionObserver for the whole page) · scroll-linked path drawing (Revenue Circuit, process line) · chart draw-in once · CTA fill expansion · magnetic CTA (≤ 6px) · metric toggle crossfade · platform marquee (two rows, opposite directions, endless, paused on hover).

Not allowed: scroll hijacking, parallax beyond ~40px, cursor followers, loaders, bounce/elastic easing, anything that loops forever outside the two ambient visuals.

`prefers-reduced-motion: reduce`: reveals render instantly, paths render fully drawn, signal particles are hidden, videos show posters, magnetic effect is off.

## Accessibility baseline

WCAG 2.2 AA contrast for all text (table above) · visible focus everywhere · skip link · landmarks (`header`, `nav`, `main`, `footer`) · menus operable by keyboard with Escape · native `details` for FAQ · diagnostic built from `fieldset`/`legend` radio groups with a polite live region · charts have text equivalents · 44px minimum touch targets · no information conveyed by colour alone.
