---
name: Fixxo
version: 2.0
updated: 2026-09

color:
  primary: "#6D28D9"          # purple — accent, one use per view
  primary-hover: "#5B21B6"
  primary-press: "#4C1D95"
  on-primary: "#FBF9FF"
  ink: "#0D0D0F"              # cool near-black; NEVER #000
  ink-2: "#52525B"
  ink-3: "#A1A1AA"
  paper: "#FFFFFF"            # warm off-white; NEVER #FFF for canvas
  paper-2: "#F7F7F8"
  raised: "#FFFFFF"           # only for raised cards
  rule: "#EAEAEC"
  rule-strong: "#E3E3E6"
  accent-bg: "#F5F3FF"
  accent-rule: "#DDD6FE"
  ok: "#16A34A"
  warn: "#D97706"
  bad: "#DC2626"
  # dark — a warm sibling palette, not an inversion
  dark-canvas: "#0B0B0D"
  dark-ink: "#F5F5F7"
  dark-accent: "#A78BFA"

typography:
  family: "Inter"                       # the only typeface
  weights: { body: 400, control: 500, heading: 600, display: 700 }
  scale: [12, 13, 14, 15, 16, 18, 20, 24, 30, 36, 48]
  body-size: 15
  body-leading: 1.55
  tracking: { display: "-0.03em", title: "-0.02em", body: "-0.011em", label: "0.01em" }
  numerals: "tabular-nums on every price, distance, percentage, rating"
  mono: "JetBrains Mono — documentation and code only, never product UI"
  banned: ["serif", "a second sans", "a display face", "italic headings", "all-caps body"]

spacing:
  base: 4
  scale: [4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 112]
  section-rhythm: "clean 8pt rhythm; vary section gaps so the page has cadence"
  measure: "62–66ch for prose and chat"

rounded:
  small: 8
  control: 12
  card: 16
  sheet: 24
  pill: 999

components:
  - button-primary      # solid purple, 12px radius, all six states
  - button-secondary    # white + 1px border, the non-primary path
  - text-link           # tertiary action — no pill
  - composer            # rounded chat input; attach / send
  - message             # user right in a soft bubble; assistant left, plain text
  - tool-trace          # soft-filled row: label + duration; never hidden
  - thinking            # label + pulsing 6px dot
  - vision-card         # photo + numbered bounding boxes + confidence words
  - question-option     # rounded selectable row with a radio indicator
  - brief               # definition list, not a card grid
  - candidate           # matching row: rank chip, avatar, reasons, score bar
  - status              # 6px dot + label (the Google/Apple pattern)
  - timeline            # 9px dots on a 2px rail
  - meter               # 6px progress bar
  - phone-frame         # 390×844
  - desk-frame          # 1280×800

layout:
  max-width: 1180
  phone: "390×844"
  desktop: "1280×800"
  principle: "clean grids, generous whitespace, chat is the primary surface"
  nav: "sticky header, soft blur, one purple active state"

motion:
  durations: { fast: "120ms", base: "200ms", slow: "300ms" }
  ease: "cubic-bezier(.32,.72,0,1)"
  allowed: ["state change", "streaming caret", "live-state pulse", "layout-matched skeleton"]
  forbidden: ["fade-up on scroll", "parallax", "hover scale+shadow", "ambient loops", "typewriter slower than the real stream"]
---

# Fixxo — DESIGN.md

This is the contract. It exists so that every generation, every screen and every future contributor reaches the same decisions instead of the average. **Tokens explain about a third of the brand; the prose constraints carry the rest.** Where this file and a personal preference disagree, this file wins.

---

## 1 · Brand

Fixxo is **one accountable party for the home repair**. The interface must communicate three facts before anything else: the price is fixed, the professional is verified, and the money is held until the customer approves the work.

The visual posture is *operator, not marketplace*. Marketplaces shout — badges, gradients, urgency timers, "3 pros are viewing this". We do not. The category's biggest lie is that choice is the product; our product is the removal of choice anxiety. So the design is calm, numeric and specific. The most important element on any screen is usually a number, and the second is a name with a face.

The mark is a rounded frame with a single offset point — the home as the AI sees it, and the fault found. Deliberately not a bolt, wrench, house, roof, spark, shield, checkmark or letter monogram — those are the defaults a generator reaches for, and an icon cliché is the absence of a decision.

Voice is plain-spoken and specific: a good tradesperson explaining what they found and what it costs. It never sells, never apologises before offering the remedy, and never uses an emoji.

## 2 · Color

Three active hues, maximum. **Purple `#6D28D9` is the accent and appears once per view** — the primary action, the active state, or the live marker, never all three. Ink `#0D0D0F` carries text; `#FFFFFF` is the canvas. Extend with tints of these, never with a new hue.

The canvas is pure white and the ink is a cool near-black — the Apple/Google/OpenAI convention. Neutrals are true cool grey (`#F7F7F8`, `#EAEAEC`) with **no warm cast**; the earlier warm-paper palette is retired.

Status colours are separate from brand: ok `#16A34A`, warn `#D97706`, bad `#DC2626`. **Status is never colour-only** — it is a 6px dot plus a label, so it survives greyscale and colour-blindness.

**Gradients are banned.** So is glassmorphism, neon-on-dark, purple-to-blue sweeps, and floating gradient orbs. Depth comes from a soft, low-contrast shadow — never a blur, a glow, or a heavy drop. Dark mode is a true dark UI (canvas `#0B0B0D`, accent lifted to `#A78BFA`), not a filter inversion.

Contrast is measured against APCA, not eyeballed: body text clears AAA; white on purple clears AA at every size.

## 3 · Typography

**One typeface: Inter.** It is the neutral grotesque the products we are measured against use, and it makes the brand read as a software product rather than editorial stationery. The previous direction — a serif display face and a warm-paper palette — is explicitly retired: it read as stationery, not as an app.

Four weights, each with a role: **400** body, paragraphs and chat · **500** controls, labels, table headers · **600** headings, card titles, buttons · **700** display headlines only.

**Numbers are tabular** — `font-variant-numeric: tabular-nums` on every price, distance, percentage and rating, so figures align in columns and never jitter.

Scale: 12 · 13 · 14 · **15 body** · 16 · 18 · 20 · 24 · 30 · 36 · 48. Tracking tightens with size: −0.011em body → −0.02em title → −0.03em display. Lead with 1.55. Prose and chat hold 62–66 characters; full width is reserved for tables and figures. Never set body below 15px. Headings use `text-wrap: balance`, body `text-wrap: pretty`.

**Banned:** any serif, a second sans, a display face, italic headings, and all-caps body copy. JetBrains Mono exists for documentation and code samples only — it never appears in a customer or provider screen.

## 4 · Spacing

A clean 4px base on an 8pt rhythm: 4 · 8 · 12 · 16 · 20 · 24 · 32 · 40 · 48 · 64 · 80 · 112.

Proximity carries meaning in three tiers: space inside a component < space between components < space between sections. Never collapse those tiers. Vary section gaps so the page has cadence rather than one repeated value — but keep every value on the grid.

Optical adjustment is expected: a 1–2px nudge to align a figure to its container, or to correct the visual weight of a large heading, is correct even when the maths says otherwise.

Padding: screen 20px on mobile, canvas 24px on desktop, card 20px. Measure 62–66ch.

## 5 · Components

Every interactive element defines **all six states** — default, hover, focus-visible, active, disabled, loading. If one is missing the component is not done. Focus rings are designed (2px purple, 2px offset), never the browser default.

The action hierarchy is text-led. Primary actions are solid purple, 12px radius, 44px tall. Secondary is white with a 1px border. Tertiary is a plain text link — no pill.

**Radii are generous** — 8px small, 12px controls, 16px cards, 24px sheets, pill for tags and switches. Sharp corners and a hard-edged, editorial feel are the previous direction and are retired.

Surfaces are white cards with a 1px `#EAEAEC` hairline and optionally `shadow-1`. Elevation is soft and low-contrast: it communicates *float*, not decoration. A heavy drop shadow is a defect.

The signature components are chat-native:
- **Message** — the user's turn sits right in a soft grey bubble; the assistant's turn sits left in plain text with **no bubble**, so the reading width is preserved.
- **Tool trace** — a soft-filled row reading `Reading image · 1.2s`. The model's work is the user's audit trail; hiding tool calls is the fastest way to lose trust.
- **Thinking** — a label with a pulsing 6px dot, escalating through named phases. Never a bare spinner for more than three seconds.
- **Vision card** — the customer's photo (their own upload, never stock) with numbered bounding boxes and confidence *words* ("high", "medium"), never a fake percentage.
- **Brief** — a definition list of the scoped job, editable line by line. Not a card grid.
- **Candidate** — a matching row: rank chip, initials avatar, two lines of *reason*, and a 4px score bar. This is the component lead-selling marketplaces cannot build.
- **Status** — a 6px dot plus a label, the Google/Apple pattern. No mono uppercase, no checkmark circles.
- **Timeline** — 9px dots on a 2px rail; completed steps go ink, the live step pulses purple, future steps stay faint.

## 6 · Layout

The customer product is **chat-first**. The first screen a homeowner sees is a conversation, not a hero, a category grid, or a hero + three feature cards. Intake, diagnosis, the brief, matching, assignment and tracking all happen inside the same thread, with structured components embedded when a decision is finite (a slot, a payment, an approval). Chat handles open-ended description; controls handle deterministic choices — never force a sentence where a tap will do.

Frames: phone 390×844; desktop 1280×800. Content max-width 1180px.

Compositions are **clean and calm** — closer to Apple and Google than to an editorial site. Generous whitespace, one clear focal point, soft rounded surfaces, a single accent. Banned: a feature-grid of three identical icon cards, a badge floating above an H1, and the canned hero→features→pricing→FAQ order shipped unmodified.

Every screen has exactly one primary action, and the whole composition should lead the eye to it. If a section could be deleted without loss, delete it.

## 7 · Voice

Plain, specific, unhurried. Numbers before adjectives. Say the hard thing plainly. Second person, active voice. Define a term the first time it appears. Never blame the user. Delete 30% of any copy before shipping.

**Banned words:** empower, unlock, seamless, effortlessly, revolutionise, transform, elevate, cutting-edge, next-generation, AI-powered, game-changing, future of, one-stop, hassle-free, curated, bespoke. And every emoji.

Buttons name the action and the consequence: "Assign Marcus · $312 held in escrow", not "Submit". Errors state the cause and the fix: "That card was declined. Nothing was charged." An apology never precedes the remedy.

## 8 · Motion

One authored system. Motion explains state and nothing else.

Durations 120ms (hover, press), 200ms (toggles), 300ms (sheets), on `cubic-bezier(.22,1,.36,1)` — never a browser default. Permitted: a state transition, the streaming caret, a 6px dot pulsing at 1.8s for a live state, and a skeleton that matches the layout it replaces.

**Forbidden:** fade-up-on-scroll, parallax, ambient loops, flat 0.1s stagger across children, and any typewriter effect slower than the real stream (it makes a fast model feel slow). A subtle press-scale on a button is allowed; a hover scale-and-shadow is not.

`prefers-reduced-motion: reduce` collapses everything to 0.01ms, and the design must remain fully legible with motion off.

## 9 · Anti-patterns

The most load-bearing section. These are enforced at build time, not by memory.

**Palette** — no gradients, no purple-to-blue sweeps, no neon-on-dark, no floating gradient orbs, no glassmorphism, no warm-paper or beige cast, no permanent dark mode by reflex, no pure `#000` text.

**Type** — no serif, no display face, no second sans, no italic headings, no all-caps body, no monospace in product UI, no invented font stacks.

**Layout** — no three identical icon cards in a row, no badge floating above the H1, no bento grid reached for by default, no uniform `py-24` on every section, no `max-w-7xl` on everything.

**Surface** — no heavy drop shadows, no coloured left-border strips, no card-inside-card nesting, no design that reads as stationery, print, or editorial layout.

**Imagery** — **no stock photography, no random faces, no generated people, no placeholder art in the product.** Job photos are the customer's own uploads; avatars are initials. Marketing imagery is a commissioned shoot or nothing.

**Motion** — no fade-up on scroll, no hover scale+shadow, no linear 0.1s stagger, no missing `prefers-reduced-motion`.

**Iconography** — no bolt, wrench, house, roof, spark, shield-with-check, handshake or thumbs-up; no oversized icon above a heading; no emoji anywhere.

**Craft** — `::selection`, `:focus-visible`, `prefers-reduced-motion` and print styles are all authored; dark mode is a designed dark UI, not `filter: invert()`. Missing any of these reads as unfinished.

**Copy** — no banned words, no exclamation marks, no "powered by AI" badges, no marketing that over-promises the membership before the pilot proves it.

---

## Appendix · Files

| File | Purpose |
|---|---|
| `DESIGN.md` | This contract |
| `BRAND.md` | Brand narrative, voice, applications, governance |
| `FIXXO_V2_DESIGN_SYSTEM.html` | Visual reference |
| `design/v2/tokens.css` | CSS custom properties (light + dark) |
| `design/tokens.json` | W3C DTCG tokens for Figma / pipelines |
| `design/tailwind.tokens.cjs` | Tailwind theme extension |
| `assets/brand/*.svg` | Mark, lockup, app icon, favicon |
