Two products, one code path
The demo recreates two products: UK ClaimPilot (the MatterHome screen) and US ClaimPilot (the Claim page). The flags top-right switch between them, and the choice is remembered per browser. They render the same claim document through the same view, and the assistant behaves the same on both.
Everything that differs is declared once
frontend/src/region/regions.ts holds a Region for each product:
| Field | UK | US |
|---|---|---|
locale | en-GB | en-US |
currency (default for lists and random claims) | GBP | USD |
dateFormat | dd/mm/yyyy | mm/dd/yyyy |
nav.menu | Legal, Launch Pad, Toolkit, History, My Claims, … | Home, Search, Actions, Reports, … |
nav.claimsItem | My Claims | Home |
nav.logo | in the top bar | in the left rail |
brand | green disc mark | orange ring mark |
glyph | the assistant's colours | the assistant's colours |
Nothing else in the code knows the region. It is applied three ways.
1. Theme
RegionProvider stamps data-region on <html>. The --color-cp-* tokens in styles.css are swapped under [data-region="us"], so every component recolours without a code path. The provider also sets the page language, except when embedded, where the host owns that.
2. Layout
/claims/:id renders MatterHomePage for UK or us/UsClaimPage for US, and the US shell adds UsSidebar. Both are layouts over the same ClaimView from claimView.ts, and both carry the same data-panel anchors, so highlight_panel works identically.
3. Formats and language
Dates and money come from useRegion():
const { fmtDate, fmtMoney } = useRegion();
fmtDate('2026-07-22'); // 22/07/2026 (UK) · 07/22/2026 (US)
fmtMoney(27800, claim.currency); // £27,800 · in the claim's own currency, the region's locale
Money is formatted in the claim's currency, not the region's. A GBP claim viewed on US ClaimPilot still shows pounds.
Chat and voice send the region's locale, which selects the system.locale_uk or system.locale_us prompt block: spelling, date style, claims terminology, and the accent the assistant speaks in. The accent has to be stated in the prompt, because the Live model otherwise picks its own language.
Brand: Claimpilot or Clonepilot
Separately from region, BrandProvider sets the names the assistant goes by. The demo app runs as Clonepilot (Clonepilot Chat in Clonepilot); an embedded host gets the default, Claimpilot (Claimpilot Chat in ClaimPilot). The brand is sent with each request, and applyBrand fills {{assistant}}, {{product}} and {{pronunciation}} in the prompt text.
Adding a region
See Change the look. In short: a new Region in regions.ts, its token overrides in styles.css, a layout if the screen differs, a locale prompt block if the language does, and a new Locale value in the shared protocol.