The canonical written spec for rebuilding the Unlock intelligence platform in Lovable (React + Vite + TypeScript + Tailwind + shadcn/ui). This page is the record of the design system and architecture. The live working demo is access-controlled (not reachable from this public site); the Asset Register module is viewable at the dedicated link below. ← Back to the site
Unlock is a portfolio-intelligence platform for UK investors. It aggregates a household's entire portfolio into one Asset Register (the single source of truth) and runs an intelligence suite on top of it: tax/IHT, decumulation planning, portfolio safety lights, concentration, simulation, and an annual review.
The public site is a marketing landing; behind a "Try a demo" flow sits the working app on synthetic data. The whole app reads from the Asset Register — every other module is a lens over those holdings.
| Concern | Choice |
|---|---|
| Framework | React 18 + TypeScript, built with Vite |
| Routing | wouter (lightweight). App shell mounts a nested router with base /demo/app. |
| Styling | Tailwind + shadcn/ui, driven by CSS custom properties. Two parallel token systems: shadcn HSL tokens and an --unlock-* hex layer (see §5). |
| Charts | recharts (PieChart, donut, area, etc.) |
| Icons | lucide-react |
| State | React context (PlannerContext holds assets/inputs; DemoContext holds persona) |
Two surfaces: a public marketing site at /, and the gated app under /demo.
/ Marketing landing ("See everything. Protect everything.")
nav: Platform · Pricing · EIS & SEIS · The Advice Gap · About · Try a demo · Log in
/demo Investor questionnaire (8 Qs) → computes a persona
/demo/app/* The authenticated app shell (left nav + content)
├─ /asset-register ◀ single source of truth (list + allocation)
├─ /tensions Financial Health
├─ /portfolio-intelligence Hub
│ ├─ /safety-lights red/amber/green guardrails
│ ├─ /concentration-risk
│ ├─ /simulator scenario weights → range of outcomes
│ ├─ /liquidity-runway
│ └─ /risk-check
├─ /tax-intelligence/iht · /timeline · /gifting · /beneficiaries · /hmrc
├─ /decumulation · /annual-review
├─ /property · /compare · /deals · /pitch-deck
└─ /reports · /chat (AI assistant)
Deep links into the app accept ?persona=legacy_builder|preserver|growth_seeker to skip the questionnaire.
A fixed left sidebar (≈248px) + scrolling content. Content is centred, max-width: 960px.
The authenticated app is dark by default. A light theme exists (applied via a demo-light class on <html>) and overrides the same variables. Brand green is constant across both. Use these exact values.
--unlock-bg: #1e1e1e — page background--unlock-surface: #2b2b2b — cards / panels--unlock-surface-raised: #333333 — raised surfaces--unlock-border: #444444 — borders / dividers--unlock-text: #ffffff — primary text--unlock-muted: #b0b0b0 — secondary text--unlock-disabled: #555555.demo-light)--unlock-bg: #ffffff--unlock-surface: #f5f6f8--unlock-border: #e3e6ea--unlock-text: ≈#212022 (hsl 270 3% 13%)--unlock-muted: #5b6470--unlock-accent: #01BC77 — brand green (buttons, active, highlights)--unlock-accent-hover: #008655--unlock-danger: #ef4444--unlock-warning: #f59e0b| Token | Value |
|---|---|
| Body font | 'Inter', 'Aeonik', sans-serif (--font-body) |
| Display font | 'Noto Serif', serif (--font-display, used sparingly for editorial headings) |
| Condensed | 'Barlow Condensed' (loaded; used for some marketing display) |
| Radius | --radius: 0.5rem (cards/buttons ~6–8px) |
| H1 (page) | 24px / 700 |
| Body | 14px base; 13px secondary; 11–12px captions |
background: var(--unlock-surface); border: 1px solid var(--unlock-border); border-radius: 8px; padding: 16–24px.background: var(--unlock-accent); color: #fff; border-radius: 6px; padding: 8–10px 16–20px; font-weight: 600.1px solid var(--unlock-border), muted text.4px solid var(--unlock-accent) left border, dismissible (×).All charts use recharts. Pies/donuts share one palette so colours are consistent across Beneficiaries, Concentration and the Asset Register allocation view.
PIE_COLORS = ['#01BC77','#3b82f6','#f59e0b','#ef4444','#8b5cf6',
'#ec4899','#14b8a6','#f97316','#6366f1','#84cc16']
Donut convention: innerRadius 50–70, outerRadius 80–100, paddingAngle 2, tooltip on a --unlock-surface card. See the dedicated Asset Register spec for the allocation donut.
15 web modules surfaced as the nav above. Priority order for a rebuild:
Three personas drive synthetic households: preserver, growth_seeker, legacy_builder. The canonical demo story is legacy_builder ("David & Sharon") — a post-business-sale household with a £2,950,000 portfolio, a concentrated single stock (Acme plc, 30.5%) and ~£4.3m projected IHT exposure. Persona is set by the questionnaire or a ?persona= URL param.
recharts + lucide-react + wouter.:root default; light via .demo-light). Use the exact hex in §5.