# Sooner Design System v2.2 (July 2026)

The complete machine-readable reference for the Sooner brand. Live examples at [brand.joinsooner.com](https://brand.joinsooner.com). This file is self-sufficient: narrative, numbers, copy law, all three visual surfaces, and craft process.

Source-of-truth chain: this site deploys from `brand-site/` in the `rematched/Draper-Growth-Marketer` repo, governed by `DRAPER.md` there. If this file and DRAPER.md disagree, DRAPER.md wins and this file must be updated.

## Narrative canon (locked)

- Flag: "Mortgages with the lowest upfront cost in the UAE." (PLURAL - never "The mortgage with...")
- Kicker: "Same mortgage. Same banks. Just a lot less cash out of your pocket."
- Promise: "Your down payment is all you'll need."
- Guarantee: "Lowest upfront cost in the UAE - or we'll tell you who beats it."
- First-timer wedge (campaign layer only, always additive to the DLD FTHB Programme): "The first-time buyer incentive no one talks about."
- The mortgage leads as the product; closing-fee math is proof, never the headline.
- Safe villains: waiting, the moving goalpost, the hidden fee stack, rent with nothing to show. Never: banks, government, named competitors.

## Numbers canon (compute, never invent)

- Worked example: AED 2,000,000 home -> fee stack AED 165,720 (DLD 4% = 80,000; agency ~2% = 40,000; bank ~1% = 20,000; valuation 3,150; trustee 4,200; mortgage and title registration 18,370). Names and amounts verbatim.
- Repayment at best tier: ~AED 4,143/month over 60 months. Headline coverage: "up to AED 500,000".
- Cost of waiting: ~AED 9,400/month for a typical renter.
- Price framing: 1.5x total over 60 months = about 10% a year, FLAT (always attach "flat"). Comparator: a typical UAE credit card runs ~46% a year - generic, never a named bank.
- Service fee ladder: 15% / 12.5% / 10% by services bundled - anchor on 10%, the fee only moves down.
- Rates are always "assumed X%", never promised.

## Copy law (all surfaces)

- No em dashes (use " - "), no exclamation marks, no ALL CAPS in copy.
- "AED" with commas, never "Dh". Abbreviate in headlines (AED 166K). No period after "Sooner".
- No vanishing fees: comparisons list the SAME fee lines both sides; only who pays changes ("paid by Sooner").
- Same-big-monthly: with/without-Sooner monthlies show the IDENTICAL big number; support rides below as "+ AED X/mo, first 60 months only". Never summed.
- No underwriting machinery (DBR, LTV, scores, gates). Eligibility is an invitation, never a filter.
- CTA reassurance formula: "~ 3 mins - no documents - no credit impact".
- Numbers lead; short sentences; captions state facts and stop.

---

Everything below through "Rules & Usage" specifies the PRODUCT surface (app + funnel) - the default system. The other two surfaces follow at the end.

## For Agents Download

The hero section includes a full-width "For Agents (Markdown)" download button below the tagline/meta area. It links to `/sooner-design-system.md` with a `download` attribute. Style: outline/border on dark background, light text, centered with download icon.

```html
<a href="/sooner-design-system.md" download class="for-agents-btn" style="display:flex; align-items:center; justify-content:center; gap:10px; width:100%; padding:16px 28px; font-size:15px; border-radius:8px;">
  <svg ...download icon...></svg> For Agents (Markdown)
</a>
```

CSS: `border: 1px solid rgba(255,255,255,0.25); color: rgba(255,255,255,0.6); background: transparent;` Hover: `color: white; border-color: rgba(255,255,255,0.5);`

## Core Identity

### Color Palette

| Name | Hex | Usage |
|------|-----|-------|
| Sooner Yellow | `#E9FE0F` | Primary accent, selected states, CTAs |
| Soft Yellow | `#E2F55C` | Hover state for yellow buttons |
| Dark | `#1C1B17` | Text, dark backgrounds (hero only) |
| Cream | `#F5F4F0` | App background, section backgrounds |
| White | `#FFFFFF` | Cards, inputs, clean surfaces |
| Grey Text | `#6B6B6B` | Secondary text, descriptions |
| Subtle Border | `#E5E4E0` | Card borders, input borders, dividers |
| Muted | `#A5A4A0` | Disabled text, timestamps |
| Placeholder | `#9B9B9B` | Input placeholder text |

### Special Tints
- **Yellow Tint 12%:** `rgba(233,254,15,0.12)` - Trust/commitment banners
- **Yellow Tint 30%:** `rgba(233,254,15,0.3)` - Status badges, borders
- **Yellow Highlight:** `rgba(233,254,15,0.55)` - Text highlight effect

### Typography
- **Primary Font:** Manrope (Google Fonts)
- **Weights:** 400 (Regular), 500 (Medium), 600 (Semi-Bold), 700 (Bold), 800 (Extra-Bold)

| Style | Size | Weight | Line Height |
|-------|------|--------|-------------|
| Hero/Display | 59px | 500 | 1.2 |
| Heading 2 | 47px | 500 | 1.15 |
| Heading 3 | 24px | 700 | 1.25 |
| Body | 16px | 400 | 1.5 |
| Section Label | 11px | 600 | uppercase, 0.1em spacing |
| Small/Disclaimer | 13px | 400 | 1.5 |

## UI Components

### Buttons - Marketing (Rectangular)
- **Primary:** `#E9FE0F` background, dark text, 8px radius, 14px 28px padding
- **Secondary:** Transparent, 1px border `#E0E0E0`, dark text
- **Dark:** `#1C1B17` background, white text
- Arrow (-->) on forward-action CTAs
- Sentence case, never ALL CAPS

### Buttons - App (Pill)
- Border-radius: 100px (full pill)
- Font weight: 700
- Padding: 16px 32px
- Full-width in forms
- Disabled state: `#E5E4E0` background, `#A5A4A0` text

### Shimmer Button
- Used on single most important CTA per screen
- `position: relative; overflow: hidden;` on button
- Pseudo-element `::after` with gradient sweep animation
- `background: linear-gradient(90deg, transparent, rgba(255,255,255,0.25), transparent)`
- Animation: `shimmer 3s ease-in-out infinite`
- Replay: clone the button element to reset the `::after` animation cycle

### Bordered Input (Marketing)
- 1px solid `#E0E0E0` border, 4px radius
- Focus: border-color `#1C1B17`
- Font: 18px / 400, placeholder `#9B9B9B`

### Bottom-Border Input (App)
- No visible box - only bottom border
- Default: 2px solid `#E5E4E0`
- Focus: animated line expands from center (`::after` pseudo-element)
- Font: 18px / 600, placeholder `#C5C4C0` weight 400
- Supports prefix (AED, +971)

### OTP Input
- 4 individual boxes: 56x56px, 12px radius
- Default: 2px solid `#E5E4E0`, white background
- Focus: border `#1C1B17`
- Filled: border `#E9FE0F`, background `rgba(233,254,15,0.08)`
- Verified: border `#E9FE0F`, background `#E9FE0F`
- Auto-advance on digit entry

### Choice Cards
- Single-select, vertical stack, 10px gap
- Default: 1.5px solid `#E5E4E0`, white background, 14px radius
- Hover: border `#1C1B17`, translateY(-1px)
- Selected: `#E9FE0F` background + border, 600 weight
- Keyboard hint badges: 26x26px, 6px radius, subtle background

### Area Chips (Multi-Select)
- Pill-shaped: border-radius 100px
- Default: 1.5px solid `#E5E4E0`, white background
- Selected: `#E9FE0F` background + border, 600 weight
- Max selection (e.g., 3): unselected chips fade to 35% opacity
- Selection counter below: "2 of 3 selected"
- Grouped under section labels (PRIME, POPULAR, EMERGING)

### Section Labels
- 11px, weight 600, uppercase, letter-spacing 0.1em
- Color: `#9B9B9B`
- Used to group form sections and detail rows

## Text Highlight

### Static Highlight
- Yellow marker through words (not under)
- CSS: `linear-gradient(transparent 35%, #E9FE0F55 35%, #E9FE0F55 80%, transparent 80%)`
- One highlight per heading max

### Highlight Sweep (Animated)
- Animates from left to right on initial display
- `background-size: 0% 100%` -> `100% 100%`
- Animation: `highlightSweep 0.8s 0.2s ease forwards`
- Used on form hero headings
- Replay: remove `.animate` class, force reflow with `void el.offsetWidth`, re-add `.animate`

## Progress & Status

### Progress Bar (Weighted, Top-fixed)
- Fixed to top of viewport, 3px height
- Track: `#1C1B17` (dark), Fill: `#E9FE0F`
- Glowing dot at leading edge with box-shadow and pulse animation
- Transition: `width 0.5s cubic-bezier(0.4,0,0.2,1)`
- Replay: set width to 0% (no transition), force reflow, then animate to 100% with 1.5s transition

### Progress Timeline (Phase Strip)
- Horizontal 3-phase strip
- Done: yellow circle (`#E9FE0F` bg, dark text)
- Active: dark circle (`#1C1B17` bg, white text)
- Upcoming: grey circle (`#F5F4F0` bg, `#A5A4A0` text, border `#E5E4E0`)
- Connectors: 2px lines, yellow when previous phase done, grey otherwise
- Labels: 11px, weight 600

### Steps-to-Activation Bar
- Card with step count and time estimate
- Track: 6px height, `#E5E4E0` background, 100px radius
- Fill: `#E9FE0F`, transition `width 0.6s cubic-bezier(0.4,0,0.2,1)`

## Trust & Messaging

### Commitment/Trust Banner
- Background: `rgba(233,254,15,0.12)`
- Border: `1px solid rgba(233,254,15,0.3)`, 12px radius
- Yellow checkmark circle icon (20x20 SVG) + bold title + muted detail
- Use for zero-commitment, trust, and reassurance messaging

## Cards & Surfaces

### Balance Card
- White background, 16px radius, 1.5px border `#E5E4E0`
- Contains: label, status badge, large amount (40px/700), subtitle, link
- Optional: progress bar at bottom
- Badge states: Pending (yellow 30%), Verified (yellow 50%), Activated (yellow 100%)

### Document Upload Cards
- White background, 12px radius, 1.5px border
- Text-only - NO emojis
- Uploaded: yellow left border (3px)
- Locked: 50% opacity, disabled button
- Upload button: pill, bordered, inverts on hover

### Payment Breakdown Cards
- White background, 12px radius, 1.5px border
- Ready/unlocked: yellow left border
- Pay button: yellow pill (active) or grey pill (locked)
- Amount: 18px, weight 700

### Calculator Split Cards
- Side-by-side grid (1fr 1fr, 12px gap)
- Sooner card: `rgba(233,254,15,0.15)` background, `rgba(233,254,15,0.3)` border
- Buyer card: white background, standard border
- Label (12px uppercase), amount (20px/700), subtitle (11px muted)

## Floating CTA
- Fixed bottom, centered, full width minus padding
- Pill button with box-shadow: `0 4px 20px rgba(0,0,0,0.15)`
- Optional subtitle: 12px, 70% opacity
- Hover: translateY(-2px), enhanced shadow

## Toast Notifications
- Light theme: white background, dark text
- Border: 1.5px solid `#E5E4E0`, 14px radius
- Shadow: `0 8px 24px rgba(0,0,0,0.15)`
- Slides down from top (top: -80px -> 24px)
- Transition: `top 0.4s cubic-bezier(0.4,0,0.2,1)`
- Auto-dismiss after 3s

## Overlay Patterns

### Modal Overlay (Slides UP)
- Used for: profile completion, focused tasks
- `transform: translateY(100%)` -> `translateY(0)`
- Has: logo header + close button, progress bar, step navigation
- Background: `#F5F4F0`

### Navigation Overlay (Slides RIGHT)
- Used for: account, payments, calculator
- `transform: translateX(100%)` -> `translateX(0)`
- Has: back button, centered title, scrollable body
- Background: `#F5F4F0`

### Shared Overlay Properties
- `position: fixed; inset: 0; z-index: 100`
- Transition: `0.4s cubic-bezier(0.4,0,0.2,1)`

## Animation & Motion

### Replay Button
- Consistent yellow-bordered pill button used across all animation demos
- When to use: alongside any animation that should be replayable on demand
- CSS: `display: inline-flex; padding: 8px 18px; border-radius: 100px; border: 1.5px solid #E9FE0F; background: transparent; font-size: 13px; font-weight: 600; cursor: pointer;`
- Hover: `background: #E9FE0F;`
- Contains a replay/refresh SVG icon + "Replay" text
- HTML: `<button class="replay-btn" onclick="replayFn()"><svg ...></svg> Replay</button>`

### Counter Animation
- Numbers count from 0 to target with exponential ease-out
- `ease(t) = t === 1 ? 1 : 1 - Math.pow(2, -10 * t)`
- Supports prefix (AED) and suffix (/mo)
- Typical duration: 1000-1500ms
- Replay: call `animateCounter(0, target, 1500, element)` to restart

### Welcome Animation Sequence
- Logo: fadeIn 0.5s at 0s
- Name text: fadeIn 0.5s at 0.5s
- Balance card: slideUpFade 0.5s at 1s
- Perks: staggered opacity+translateY at 1.5s+
- Counter animates inside balance card
- Replay: hide all children (opacity 0, translateY 12px), then stagger reveal with 400ms delays per child

### Progressive Disclosure
- Fields reveal with `max-height` + `opacity` transitions
- `max-height: 0; overflow: hidden; opacity: 0`
- Open: `max-height: 800px; opacity: 1`
- Transition: `max-height 0.45s cubic-bezier(0.4,0,0.2,1), opacity 0.35s ease`

### Chip Snap Animation
- `@keyframes chipSnap { 0%{scale(0.95)} 60%{scale(1.02)} 100%{scale(1)} }`
- Duration: 0.2-0.35s ease

## Account Overlay
- Slides from right (navigation pattern)
- Avatar: 64px yellow circle with initial
- Sections: Personal details, Application details (with section labels)
- Actions: Cancel application (bordered button + "Zero fees" sub), Log out (grey)

## Email Template
- **Header:** Dark (`#1C1B17`) background, white Sooner logo, centered
- **Body:** White background, 14-16px text, single yellow CTA button
- **CTA:** `#E9FE0F` background, dark text, 8px radius, 700 weight
- **Footer:** Cream (`#F5F4F0`) background, muted text, 12px
- One CTA per email, sell the outcome

## Rules & Usage

- **Logo:** Capital "S", no trailing period
- **Currency:** Always "AED" - never "Dh" or symbols
- **Dashes:** Regular dashes (-) only - never em dashes
- **Light theme only:** No dark backgrounds on app screens/cards
- **Selection states:** Yellow fill for selected, NEVER dark borders
- **Highlights:** Use sparingly - only on key moments
- **No emojis** in document/upload cards
- **No exclamation marks** - confidence doesn't shout

## Surfaces - one brand, three systems (never mix)

### Product (app + funnel)
Everything above. Cream #F5F4F0 canvas, ink #1C1B17, Manrope, yellow accent only, pill app buttons, light theme, kit at /app-kit/ (sooner-kit.css is the buildable source of truth).

### Marketing & social (ads, organic, website, OOH)
- Ink deepens to #0E0D0D (the website's --dark-900). Cream canvas; yellow as marker sweeps, number blocks, stamps.
- Headlines Manrope 700/800 tight (-0.03em); grey-then-black turn (setup lines #6B6B6B, payoff line in ink). Geist Mono for receipts/tabular devices; tabular-nums.
- Imagery law: numbers ARE the imagery (receipts, meters, blocks, stamps). No stock couples/keys/skylines/handshakes. Billboard posts with photoreal humans are the sanctioned exception - AI-generated (Higgsfield), composited under type, negative space reserved for the headline.
- Social mechanics: 1080x1350 (4:5), HTML-first, rendered headless, never hand-edited PNGs. Wordmark only where the art doesn't already say Sooner. No on-image index numbers. Type-led posts carry a caption hook line ("the full math is in the caption"). Captions hook-first ~55 words; first line sells alone; close with "link in bio" + "No documents, no credit impact".
- Yellow-ground exception: full-yellow reverse posts in SOCIAL CREATIVE ONLY, max ~2 per 9-post grid, never adjacent, never on product surfaces or the website.
- Key numbers go in headers, never footnotes. Bottom halves get air - stamps, terms, footers each in their own lane.

### Internal & investor (decks, data room, internal tools)
- Type: Helvetica Neue (not Manrope). Wordmark stays plain bold "Sooner". Quality bar: Ramp / Klarna / Linear.
- Tokens: ink #1C1B17 on paper #FFFFFF; panels #F5F4F0 > #EBEAE4; grey #6B6A66 (AA 5.39:1), faint #8F8E88; border ladder #EFEEE9 / #E5E4E0 / #C9C8C2. Dark surfaces: ink ground, cards #26251F, borders #38372F, secondary text #A5A4A0. Error #C0392B (per-surface; the app uses #D32F2F - do not unify). Button active #D6E94A.
- Shape: radius 0 on everything (small status pills excepted). No box shadows - depth is borders + background steps; the volt focus ring is the only shadow-like device. Hovers are outline/fill swaps; nothing lifts, scales or bounces.
- The volt law - #E9FE0F allowed ONLY for: focus rings; hover flips (ink -> volt with ink text); the highlighter mark (ONE per screen, on the phrase that matters); one accent link/CTA per band; progress bars; rare live/action status pills. NEVER on app-UI headlines, as large background bands, as decoration or icon tinting.
- Highlighter mark recipe: background linear-gradient(180deg, transparent 9%, #E9FE0F 9%, #E9FE0F 94%, transparent 94%); padding 0 .1em; box-decoration-break: clone (clips so ascenders/descenders poke out).
- Type scale (deck, 1920x1080 stage space): h1 108/700/-0.03em; h2 72/700/-0.025em; kicker 19/700/+0.22em uppercase; sub 27/500-600; fine print 17.5/400. Product-UI scale: h3 22/700; kicker 11/700/+0.22em; button label 15/700; body 14-15; meta 13-13.5.
- Kickers are the only letterspaced element. Ranges take a spaced en dash (7.5 - 10%): typographic ranges only; the no-em-dash prose rule stands everywhere.
- Motion: state swaps 120-180ms; entrances 280-450ms (signature "rise": fade + translateY(14px) -> 0); large crossfades 550-600ms; easing cubic-bezier(.22,1,.36,1); always honor prefers-reduced-motion; nothing bounces.
- Dataviz: horizontal bars (label left | track | value right), volt for the hero series, direct labels over legends, no gridlines/3D/rounded caps. Dark panels: volt bars, white value labels.
- Layout: the left grid line is sacred - kicker, headline, labels, notes share ONE left edge. Fixed-stage decks are 1920x1080 scaled by a single fit transform; stage-space px only inside, never vw/vh. Confidential surfaces carry the diagonal watermark tile (viewer email + date, ~6% opacity, -24deg).

## Craft & process (every surface)

- One line beats two: no orphan words, ever - if it fits on one line it must not wrap.
- tabular-nums on any number that updates or aligns.
- Structure first: lo-fi wireframe with REAL copy (never lorem) before hi-fi; record decisions with the why.
- Screenshot 375px AND desktop before calling a screen done; verify scaled surfaces at 2-3 very different window sizes.
- Self-review every render before presenting it. Settle pixel disputes by measurement, not by eye.
- Never edit rendered PNGs - edit the source and re-render. Never mix surface systems.
