Live mode (impeccable.style/live-mode) never worked here because the skill was never actually installed: postCreate ran `skills add pbakaus/impeccable --global`, which silently no-ops — it's absent from ~/.claude/skills. Vendor it into .claude/skills/impeccable instead, so live mode's scripts/ sit on a stable path and everyone gets the same version (`npx impeccable update` to refresh). Drop the dead postCreate step. Live-mode wiring: - .impeccable/live/config.json for Next.js App Router (src/app/layout.tsx, </body>, jsx). detect-csp.mjs reports no CSP in this project, so no config patch is needed and cspChecked is honestly true. - Forward port 8400 with requireLocalPort. The script injected into the page hard-codes http://localhost:8400, so if VS Code remaps it the element picker silently never loads — the one devcontainer-specific trap here. - Ignore the per-session journal/screenshots; keep the configs tracked. DESIGN.md is required — live.mjs refuses to boot without it (context_missing). Generated via the `document` skill from the actual codebase, so it records what the code really does, including the gaps (dark mode defined but dead, --font-sans referenced but never defined, --radius unused, the broken Tremor colour block). Worth a read rather than a rubber stamp: it's the context live mode generates variants against. Verified: live.mjs boots ok with the helper on 8400 and injects into layout.tsx; live-server.mjs stop strips the tag back out cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
29 KiB
| name | description | colors | typography | rounded | spacing | components | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Ara | Domna's portfolio intelligence platform — housing stock data turned into clear, costed retrofit and investment plans. |
|
|
|
|
|
Design System: Ara
1. Overview
Creative North Star: "The Chartered Surveyor's Desk"
Ara is a working instrument, not a showroom. Its users are analysts, asset managers and approvers with a spreadsheet open on the next monitor; the interface's job is to hand them a number they will stake a retrofit budget on. So the system reads like an institutional document rather than a product tour: white paper, hairline rules, one deep navy that signs the page, and figures set with more care than any decoration on the screen. PRODUCT.md names the register precisely — "calm, expert, institutional — quiet confidence appropriate to housing-sector procurement, with measured warmth from the brand tan/brown accents."
The surface is neutral by construction. Every semantic token in src/app/globals.css is a slate-based shadcn default: pure white background (--background: 0 0% 100%), near-black slate ink (--foreground: 222.2 47.4% 11.2%), a slate hairline (--border: 214.3 31.8% 91.4%). Colour is reserved for meaning: brand navy (#14163d) for identity and the single dark CTA; the seven-step EPC band scale (#117d58 → #e41e3b) for the one dimension the whole product is about; amber/red only for risk. Density is high and deliberate — home-page cards sit at 16px padding (p-4, PortfolioCard.tsx), table cells at 12px/8px, because these screens carry hundreds of properties on large desk displays.
What the system rejects, in PRODUCT.md's own words: generic SaaS admin templates (Bootstrap/AdminLTE dashboards, hero-metric cards, widget walls), the bare centred icon-card grid of the old home page, and over-designed AI mockup output — 2rem-rounded cards, giant soft shadows, decorative gradients, invented data the schema cannot supply. If a surface could be dropped into any other B2B dashboard without changing a word, it is wrong.
Key Characteristics:
- White surface, slate ink, hairline borders — depth comes from rules and tone, not shadow.
- Navy (
#14163d) as signature, not wallpaper: nav bar, one primary CTA, chart series anchor. - Two typefaces, one job each: Inter reads, Manrope counts.
tabular-numson every figure that a user might compare down a column (39 usages acrosssrc/).- Seven-step EPC colour scale is the only decorative-looking colour in the product, and it is load-bearing data.
- Light-mode only in practice — the dark palette exists but is dead (see the honest gaps below).
2. Colors
A near-monochrome institutional surface, signed in navy, warmed sparingly with tan/brown, and cut by a seven-step EPC scale that is the product's only saturated vocabulary.
Primary
- Brand Navy (
#14163d,brandblueintailwind.config.js): the identity colour. It fills the nav bar (src/app/components/Navbar.tsx,bg-brandblue), the footer (src/app/layout.tsx), and the single dominant CTA on a page. 535 usages acrosssrc/— by far the most-used brand token, and the one most at risk of overuse. - Hover Navy (
#3e4073,hoverblue): the only hover partner for brand navy. Nav links and brand buttons lift to it (hover:bg-hoverblue). - Slate Ink (
#0f172a,--primary/--foregroundinsrc/app/globals.css, expressed there as222.2 47.4% 11.2%): the shadcn primary. Every default<Button>and<Badge>is this near-black, not brand navy. Two dark colours therefore coexist in the product — see The One Dark Rule.
Secondary
- Mid Navy (
#2d348f,midblue) and Bright Blue (#3943b7,brandmidblue): the interactive blues.brandmidbluecarries link hover, checkmarks and progress fills (PortfolioCard.tsx:hover:text-brandmidblue, budget barbg-brandmidblue);midblueis the middle stop of the chart ramp. - Pale Blue (
#eff6fc,brandlightblue): the lightest tinted surface, used as a chart wash and card tint. Note the collision documented under gaps:theme.extend.textColor.brandlightblueis#00a9f4, a completely different colour from the background token of the same name.
Tertiary
- Brand Tan (
#d3b488) / Hover Tan (#947750) / Brand Brown (#c4a47c): the "measured warmth" PRODUCT.md asks for. In practice they are almost entirely a chart palette —brandbrownappears 94 times, mostly as a Tremor/Recharts series colour (src/lib/chartUtils.ts), whilebrandtanappears 7 times. The warmth is real but currently lives in the charts, not the chrome. - Brand Gold (
#f1bb06) / Hover Gold (#c79d12): reserved for the starred/pinned state (PortfolioCard.tsx,fill={starred ? "#f1bb06" : "none"}). At 1.77:1 against white it is decorative only, and the critiques flag it: state must never be carried by the gold fill alone.
Neutral
- Surface (
#ffffff,--background): the page. Always. - Muted Surface (
#f1f5f9,--muted/--secondary/--accent, all210 40% 96.1%): row hover, tab track, skeleton fill, secondary button. - Muted Ink (
#64748b,--muted-foreground): table headers, card meta, timestamps. - Hairline (
#e2e8f0,--borderand--input): every divider and every input stroke, at exactly 1px. - Focus Ring (
#94a3b8,--ring): the 2px offset ring on every focusable primitive. - Destructive (
#ff0000,--destructive: 0 100% 50%): pure sRGB red. Honest note: this is a raw, unmodulated red and the only token in the system that is not tuned — it sits oddly against an otherwise slate-derived palette.
The EPC Scale
Seven fixed hues, epc_a through epc_g (tailwind.config.js), rendered as 20px letter bubbles (EpcLetterBubble, propertyTableColumns.tsx) and as chart fills (src/lib/chartUtils.ts). This scale is data, not decoration: A #117d58, B #2da55c, C #8dbd40, D #f7cd14, E #f3a96a, F #ef8026, G #e41e3b.
Named Rules
The One Dark Rule. A screen gets one dark button. PRODUCT.md puts navy "in small, deliberate doses", and the July critique of the property table found two competing navy CTAs side by side ("Add properties" and "Run modelling") and scored it down. Pick the one action the user should take; everything else is outline or ghost.
The Band-Colour Rule. epc_a–epc_g are reserved for EPC bands. They may never be borrowed for status, emphasis, or chart series that are not EPC bands. When a chart needs series colours, it takes them from the navy ramp (#14163d → #2d348f → #3943b7 → #5d6be0 → #8b96e9 → #b8bef4) or brandbrown.
The Tokenised-Hex Rule. Raw hex in a component is prohibited. The critique of the home page caught exactly this drift (#c3ccd8, #e2e7ee, #e4e9f1, #e9edf3, #f8fafc, #eceefb inline in PortfolioCard.tsx and PortfolioHome.tsx) while a full brand palette sat unused in tailwind.config.js. Add the token; don't paste the hex.
3. Typography
Display Font: Manrope (next/font/google, weights 400/500/700/800, exposed as --font-manrope; src/app/layout.tsx)
Body Font: Inter (next/font/google, variable, applied via inter.className on <html>; src/app/layout.tsx)
Label/Mono Font: none. There is no monospace face in the system. Numeric alignment is achieved with Inter/Manrope's tabular-nums feature, not with a mono font.
Character: Inter is the clerk — invisible, legible at 13–14px, carrying every table cell and every paragraph. Manrope is the accountant — it appears only when a number or a label needs to assert itself: the 110px EPC score in CurrentEfficiencyCard.tsx, the plan headline in PlanHeroCard.tsx, the tiny uppercase section labels. 114 font-manrope usages, concentrated almost entirely in the building-passport surfaces.
Hierarchy
- Display (Manrope, 800, up to
text-[110px],leading-none,tracking-tighter): the single hero figure on a building passport — the EPC score. One per screen, never more (CurrentEfficiencyCard.tsx:124). - Headline (Manrope, 800,
text-3xl= 1.875rem,tracking-tight): plan and passport page titles (PlanHeroCard.tsx:173). - Title (Inter, 600,
text-lg= 1.125rem /leading-none/tracking-tight): shadcnCardTitleandDialogTitle. Portfolio names on the home grid sit slightly below attext-[17px], 600,leading-snug(PortfolioCard.tsx:200). - Body (Inter, 400,
text-sm= 0.875rem / 1.25rem line-height): the default everywhere — buttons, inputs, table cells, dialog copy. Card metadata drops totext-[13px]. - Label (Manrope, 700,
text-xs= 0.75rem / 1rem, uppercase,tracking-widest): micro-labels above figures (CurrentEfficiencyCard.tsx:117). Also used unstyled by Inter attext-[11px], 600 for table headers (PortfolioCard.tsx:245). - Numeric (any face,
tabular-nums): mandatory on money, counts, percentages, EPC scores.
Named Rules
The Trustworthy Numbers Rule. Every figure a user could compare down a column carries tabular-nums. PRODUCT.md: "Figures are the product; typography and alignment treat numeric data with more care than any decorative element." Money right-aligns. Counts right-align. A ragged numeric column is a defect, not a style choice.
The Quiet Label Rule. A micro-label must never outweigh the number it introduces. The property-table critique caught RESULTS: set in font-black uppercase — louder than the count beside it. Labels are text-xs/text-[11px], uppercase, tracked, and lighter in visual weight than their value.
The Two Voices Rule. Inter reads, Manrope counts. Manrope on a paragraph of body copy is prohibited; Inter on the 110px hero score is prohibited.
4. Elevation
Ara is a flat, hairline system. Depth is carried by 1px #e2e8f0 borders and by tonal shifts against white — bg-muted/50 on a hovered table row, bg-[#f8fafc] on a hovered list row — not by shadow. The shadow vocabulary that exists is Tailwind's own and is used sparingly: shadow-sm dominates (98 usages) and is reserved for the resting card; shadow-md (34) and shadow-lg (25) appear almost exclusively on floating layers — dropdowns, popovers, dialogs, tooltips. That distribution is the system: shadow means "this element is in front of the page", not "this element is important".
Shadow Vocabulary
- Resting card (
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05), Tailwindshadow-sm; alsotremor-inputintailwind.config.js): the shadcnCarddefault (card.tsx:rounded-lg border bg-card shadow-sm). Barely there — it exists to lift the card off white by a hair, and the 1px border does most of the work. - Overlay (
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1), Tailwindshadow-md;tremor-dropdownintailwind.config.js): select menus, popovers, tooltips, the portalled card menu (PortfolioCard.tsx:96). - Modal (Tailwind
shadow-lg):DialogContentonly (dialog.tsx:57), paired with abg-background/80 backdrop-blur-smscrim. - Tremor card (
0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1),tremor-card): defined intailwind.config.jsfor Tremor chart cards.
Named Rules
The Hairline-First Rule. Reach for a 1px #e2e8f0 border before you reach for a shadow. If both a border and a shadow are present on a resting surface, the shadow is probably wrong.
The Floating-Only Rule. shadow-md and above are reserved for elements that are literally floating above the page — menus, popovers, dialogs, toasts. A card, a table, a panel, a section: never. shadow-xl and shadow-2xl are drift; the codebase has 19 and 11 usages respectively and every one of them should be justified or removed.
The 2014 Test. If a surface looks like a 2014 admin panel, the shadow is too dark and the radius is too big. PRODUCT.md names the failure mode directly: "2rem-rounded cards, giant soft shadows, decorative gradients."
5. Components
The library is shadcn/ui (components.json, style: default, baseColor: slate, cssVariables: true) generated into src/app/shadcn_components/ui/, sitting on Radix primitives, with Tremor (@tremor/react v3) for charts and Headless UI for a handful of menus. Variants are declared with class-variance-authority.
Buttons
src/app/shadcn_components/ui/button.tsx
- Shape: gently rounded (
rounded-md, 0.375rem) at every size. Brand-styled buttons written by hand outside the primitive userounded-xl(0.75rem) — a real inconsistency, not a documented variant. - Sizes: default 40px tall (
h-10 py-2 px-4),sm36px (h-9 px-3),lg44px (h-11 px-8). - Primary (
default): slate ink#0f172aon#f8fafctext, hover to 90% opacity (bg-primary text-primary-foreground hover:bg-primary/90). Note: 104 components bypass this and usebg-brandblue(#14163d) directly against 15 uses ofbg-primary— brand navy is the de facto primary button in feature code even though the primitive says otherwise. - Focus: 2px ring in
#94a3b8, offset 2px, on:focus-visibleonly. Outline is removed and replaced, never removed and left. - Secondary / Outline / Ghost / Link / Destructive: the five other cva variants.
outline= 1px#e2e8f0stroke, transparent fill, hovers to muted surface;ghost= no stroke, hovers to muted surface;link= navy text with a 4px-offset underline on hover.
Chips / Pills
Two distinct pill families exist and they are not interchangeable.
- Badge (
badge.tsx): fully round (rounded-full),px-2.5 py-0.5,text-xs font-semibold, 1px border, four cva variants (default / secondary / destructive / outline). - Status pill (
PortfolioCard.tsx:34-44): same geometry, but an eight-tone map keyed to portfolio status —earlyslate,tenderindigo,underwayblue,ontrackgreen,delayedamber,atriskred,doneemerald,reviewyellow, each as a-100background with a-800/-900foreground. Every pill carries a 1.5px dot and a text label — colour is never the sole carrier of state.
Cards / Containers
- shadcn
Card(card.tsx):rounded-lg(0.5rem), white--cardfill, 1px hairline border,shadow-sm. Internal paddingp-6(24px) on header/content/footer; header stacks withspace-y-1.5. - Portfolio card (
PortfolioCard.tsx:195): the denser home-page variant —rounded-xl(0.75rem), 1px border, no shadow at all,p-4(16px),gap-2.5. Hover changes only the border colour. This is the more honest expression of the system than the shadcn default. - Radius drift is real:
rounded-lg(249),rounded-full(232),rounded-xl(131),rounded-md(125),rounded-2xl(82) acrosssrc/.rounded-2xl(1rem) is the outer edge of acceptable and trends toward the "over-rounded AI mockup" anti-reference.
Inputs / Fields
input.tsx, select.tsx
- Style: 40px tall (
h-10),rounded-md, 1px--input(#e2e8f0) stroke on--backgroundwhite,px-3 py-2,text-sm. Placeholder in muted ink. - Focus: 2px
#94a3b8ring, 2px offset — identical to buttons, so the focus vocabulary is one thing across the app. - Disabled:
cursor-not-allowed+ 50% opacity. - Error: not established in the primitives. There is no error variant on
Input; forms usereact-hook-form+zod(form.tsx) and render messages, but the field has no visual error state token. Flagged as a gap. - Select: Radix
SelectTriggermatchesInputexactly (h-10 rounded-md border border-input px-3 py-2); content panel isrounded-md+shadow-mdwith a chevron and a check-mark indicator.
Navigation
src/app/components/Navbar.tsx
- Style: a solid
bg-brandblue(#14163d) bar, 64px tall (h-16), constrained tomax-w-7xlwith responsive gutters (px-4 sm:px-6 lg:px-8). White Domna wordmark on the left. - Links:
text-gray-300,text-sm font-medium,px-3 py-2,rounded-md. Hover fills tohoverblue(#3e4073) with white text. There is no active/current-page state — a genuine gap. - Mobile: below
md, links collapse into a hamburger panel with a Headless UITransition(100ms ease-out in, 75ms ease-in out, opacity + 95% scale). - Hidden on
/: the nav returnsnullon the root path.
EPC Letter Bubble (signature component)
propertyTableColumns.tsx:68. A 20px (h-5 w-5) circle, rounded-full, text-xs font-bold text-white, filled from the seven-step band scale via getEpcColorClass (src/app/utils.ts:49). Its empty state is deliberate and hard-won: a hollow circle with a 1px slate-200 border, a slate-400 en-dash and an aria-label="No rating yet" — because the critique found that blank bubbles read as breakage. There is a companion EmptyCell (—, text-slate-400, aria-label="No data") so that one absence vocabulary covers the whole table.
Named Rules
The One Overlay Rule. Menus, dialogs and popovers come from one primitive stack (Radix via shadcn, or Headless UI Menu where portalling is needed). window.confirm is banned — the home-page critique found it live in PortfolioHome.tsx and scored Consistency 2/10 for having three overlay vocabularies on one page.
The Portalled-Menu Rule. Any menu inside a scrolling or overflow-x-auto container must portal to the top layer (MenuButton + MenuItems anchor= in PortfolioCard.tsx). A menu clipped by its container can hold focus while invisible — a hard accessibility failure the critiques caught in the list view.
The Visible-Failure Rule. A mutation that fails must be visible to sighted users, not only announced into an sr-only live region. Toasts exist (toaster.tsx, Radix Toast, mounted in layout.tsx); use them.
6. Do's and Don'ts
Do:
- Do put brand navy
#14163don exactly one CTA per screen, and reach foroutline/ghostfor everything else. PRODUCT.md: navy carries identity "in small, deliberate doses." - Do set every comparable figure in
tabular-numsand right-align money and counts. Trustworthy numbers is the product's whole claim. - Do separate surfaces with a 1px
#e2e8f0hairline before considering a shadow. - Do reserve
shadow-md/shadow-lgfor things that literally float: menus, popovers, dialogs, toasts. - Do pair every colour-coded state with a text label — the status pill's dot-plus-label pattern (
PortfolioCard.tsx) is the reference implementation. - Do design the empty state as a first-class surface. The July critique's P0 was that a new portfolio — properties loaded, nothing modelled — falls through to a table of em-dashes and reads as "the import broke."
- Do use one absence vocabulary: the
EmptyCellem-dash attext-slate-400with anaria-label. Not four. - Do add a Tailwind token when you need a colour. The palette is in
tailwind.config.jsfor a reason. - Do keep focus rings visible: 2px
#94a3b8, 2px offset, on:focus-visible. Neverfocus:outline-nonewithout a replacement. - Do meet WCAG 2.1 AA — ≥4.5:1 body text, ≥3:1 large text and non-text state indicators. PRODUCT.md warns that procurement may demand conformance evidence.
Don't:
- Don't build generic SaaS admin templates — no Bootstrap/AdminLTE dashboards, no hero-metric cards, no widget walls (PRODUCT.md anti-reference #1).
- Don't rebuild the current home page — a bare centred grid of identical icon cards with no data, hierarchy, or organisation (PRODUCT.md anti-reference #2).
- Don't ship over-designed AI mockup output: "2rem-rounded cards, giant soft shadows, decorative gradients, invented data the schema can't supply" (PRODUCT.md anti-reference #3). Concretely: no
rounded-2xlon a data card, noshadow-xl/shadow-2xl, nobg-gradient-to-bron a surface, nobg-clip-textgradient headings — all four exist in the codebase today and all four are drift. - Don't put two dark navy CTAs on one screen. Two dark buttons say "both of these are the most important thing."
- Don't paste raw hex into a component.
#c3ccd8,#e2e7ee,#e9edf3,#eceefbare all live insrc/and all should be tokens. - Don't borrow the EPC band colours (
#117d58…#e41e3b) for anything that is not an EPC band. - Don't carry state in the gold star fill alone (
#f1bb06is 1.77:1 on white). Colour plus label, always. - Don't set body copy in Manrope or hero figures in Inter.
- Don't use
window.confirm,alert, or a bare<details>popover. One overlay stack. - Don't render text below AA on white — the property-table critique found
text-slate-300"No cost"/"Unknown" cells failing outright. - Don't let a micro-label outshout its number (
RESULTS:infont-black uppercasewas the offender). - Don't write a
dark:variant in a component. Dark mode is defined but dead (see below); the onlydark:classes insrc/are inherited Tremor helper strings insrc/lib/utils.ts, and adding one variant to one component makes the app half-dark, which is worse than light-only.
Honest gaps: what this codebase does not establish
Every value in this document is copied from source. These are the things the codebase genuinely does not settle, recorded rather than invented — do not treat any of them as a licence to invent a value, and do not "fix" them silently in a feature PR:
- Dark mode is defined but dead.
tailwind.config.jssetsdarkMode: ["class"],globals.csscarries a full.darktoken block,next-themesis a dependency, and adark-tremorcolour scale exists. The onlydark:utilities insrc/are the Tremor-derived focus/error class strings insrc/lib/utils.ts(focusInput,focusRing,hasErrorInput); no component authored for this product writes one, and nothing ever applies thedarkclass, so those variants never activate. The dark palette is aspirational; treat the product as light-only until that changes. --font-sansis referenced but never defined.tailwind.config.js:157mapsfontFamily.sanstovar(--font-sans), but no file defines--font-sans(layout.tsx defines--font-interand--font-manrope).font-sanstherefore silently falls back to Tailwind's default stack. Inter is applied only becauseinter.classNameis on<html>— the token wiring is broken, the outcome happens to be right.- Manrope weight 900 is used but not loaded.
layout.tsxrequests weights400/500/700/800;font-black(900) appears inCurrentEfficiencyCard.tsxandPlanHeroCard.tsx. The browser synthesises or falls back. The frontmatter records 800, the weight that actually exists. --radius: 0.5remis defined and unused.globals.cssdeclares it in both themes, buttailwind.config.jshas noborderRadiusmapping to it (itsborderRadius.extendcontains onlytremor-*keys). Allrounded-*classes resolve to Tailwind defaults. There is no project-defined radius scale — the values in the frontmatter'sroundedblock are Tailwind's, recorded because they are what the code actually renders.- No project spacing scale.
tailwind.config.jsextends nospacing. Thespacingfrontmatter block lists the Tailwind default steps the codebase actually leans on (p-4on dense cards,p-6on shadcn cards,px-3 py-2on dense table cells), not an invented scale. brandlightblueis two different colours.theme.extend.colors.brandlightblueis#eff6fc(a near-white wash);theme.extend.textColor.brandlightblueis#00a9f4(a saturated cyan).bg-brandlightblueandtext-brandlightblueare unrelated colours. This is a bug, not a system.- The Tremor colour block is broken.
theme.extend.colors.tremor.*anddark-tremor.*are set to the string literals"colors.blue[50]","colors.gray[200]", etc. — thecolorsimport at the top oftailwind.config.jsis never interpolated. Those tokens do not resolve to colours. Tremor charts are actually coloured through the safelisted arbitrary-value classes (fill-[#14163d]…) mapped insrc/lib/chartUtils.ts. domna-gradientis defined intailwind.config.js(linear-gradient(135deg, #14163d 0%, #2d348f 45%, #3943b7 70%, #eff6fc 100%)) and used nowhere insrc/. It is not part of the live system.- No motion tokens. No
--ease-*, no--duration-*. What exists:accordion-down/accordion-upat0.2s ease-out(tailwind.config.js), Tailwind's defaulttransition-colors,tailwindcss-animate, and 15 files usingframer-motionad hoc. There is no documented motion vocabulary and noprefers-reduced-motionhandling inglobals.css, despite PRODUCT.md requiring it. - No error state on form fields, no active/current state on nav links, and no defined breakpoint scale beyond Tailwind's defaults plus
container.screens.2xl: 1400pxandmaxWidth.8xl: 90rem. - The North Star is proposed, not confirmed. PRODUCT.md marks the brand personality as a "Hypothesis (user undecided — validate against mockup variants)". "The Chartered Surveyor's Desk" is derived from that hypothesis and from what the code actually does; it has not been ratified by the team.