# Restyle notes — what was wrong, and what was repaired

Companion to `README.md`. This is the honest record of the transformation: how it was done,
what the v1 prototype actually got wrong (as opposed to merely got old), and where v2 still
falls short of the benchmark.

---

## How the transformation was run

1. **Tokens were measured, not estimated.** The HubSpot palette, type scale, control
   geometry and table anatomy were pulled from the *computed styles* of the live captures in
   `packages/data-sync/docs/hubspot-benchmark/brand-reference/`, driven through headless
   Chrome — not read off screenshots.
2. **The frame was unified first.** v1 carried three different page frames. `assets/shell.js`
   replaces all three with one dark top bar + 236px left navigation, built once and injected
   into every page.
3. **The shared class vocabulary was re-expressed, not replaced.** `assets/foxie-hs.css` keeps
   v1's class names (`.card`, `.kpi`, `.clients`, `.pill`, `.btn`, `.tab`, `.status-pill-tbl`, …)
   so page markup survived; only their values changed.
4. **Codemods did the mechanical work.** Palette mapping, grey-snapping onto the neutral ramp,
   font normalisation, weight and radius snapping, uppercase removal — applied across the set
   so that 57 pages could not drift apart by hand.
5. **Every page was verified by rendering it and looking at it.** No page was signed off on the
   basis of reading its code. Pages were screenshotted in real Chrome at 1680×1050 and reviewed
   as images, then iterated on.
6. **An independent reviewer scored the result against the benchmark** and its findings were
   applied centrally (`foxie-hs.css` §31).

---

## Defects in the v1 prototype

These are places where v1 was **broken or unfinished**, not merely dated. They were repaired
rather than faithfully reproduced.

### Structural

- **11 pages were headless HTML fragments** — no `<html>`, `<head>` or `<body>`
  (`experts.html`, all six `customers/*`, `owners/owner`, all three `experts/*`). They loaded
  no fonts and no shared stylesheet, so they rendered in the browser's default face.
  → wrapped in real documents.
- **Three incompatible page frames** — a 56px icon rail, a 220px light sidebar, and a bare
  centred `.page`. Pages in different families could not share a navigation.
- **`review.html` was a `position:fixed; inset:14px` overlay** over a `#45433e` body. As a
  navigation destination it covered the entire viewport, top bar and left nav included.
- **`quick-launch.html` was a fixed dark scrim and a floating panel over a fake skeleton
  "Automations" screen** — which carried its own duplicate 160px sidebar and brand block.
- **`launch-redesign.html` painted a fake host page** (top bar + grey skeleton blocks) behind
  its dialog — double chrome once a real shell exists.
- **`crm.html` had a nested scroll trap** (`.app { height:100vh; overflow:hidden }` with an
  inner `overflow-y:auto`), so the page could not scroll inside the shell.
- **`my-clients.html` redeclared the entire legacy `:root` token set**, silently overriding the
  shared stylesheet for that page alone.
- **`emails-*.html` set their own body background and padding**, double-padding inside the
  content plate.
- **All 8 wireframes put their `<style>` before the stylesheet link**, so their page CSS was
  dead on arrival.

### Rendering bugs

- **`experts.html` shipped a permanently visible debug toast** — `#open-notif` declared
  `display:none` *and* `display:flex` in the same inline style.
- **`index.html` rendered a literal `\n`** as visible text before `</body>`.
- **`automation-overview.html` rendered the literal string `n 10`** where a trend glyph had
  failed to substitute.
- **`activity-progress-explorations-2`: the response-rate meter never drew** — `.rfill` was
  `display:inline`, so `height:100%` collapsed to zero and every row showed an empty pill.
- **`activity-progress-explorations-10`: a class-name collision** — the segmented control and
  the 7px progress track both used `.seg`, leaving the control as an unreachable black bar.
- **`portfolio-v7`: the donut captions sat on top of their own card titles** — `.donut-center`
  was centre-pinned with a translate that survived the shared `inset:0`.
- **`portfolio-v7`: `.signals-row` declared three columns for two cards** that were ever
  rendered, and `.sig-click-hint` was pinned on top of the breakdown counts.

### Unfinished or misleading design

- **`activity.html` used grey skeleton placeholder rows as filler** in the middle of a table of
  real data — with no other loading affordance on the page, they read as an unfinished layout.
  Replaced with real rows, which also gave the table its missing non-Complete states.
- **`activity.html`'s "Complete" status used the interaction hue**, making statuses and links
  indistinguishable. The same fault appeared in the progress explorations, where the Customer
  stage colour *was* the primary teal.
- **The "All feedback" card was clipped** on `customers/customer.html` and
  `experts/feedback.html` — it was the only card in the sparkline strip missing its month-axis
  row, so the polylines ran into the card edge.
- **Inactive sparkline cards were open-bottomed** — a `border-bottom:none` intended for the one
  active tab-to-panel card was applied to all four.
- **`portfolio-v8`'s legends showed a dot, a count and a euro figure but no category name**, so
  nothing said which colour meant Risk, Watch, Stable or Unmeasured. Its trend charts had
  `y: { display:false }` — stacked charts with no value scale at all.
- **`portfolio-v4`…`v6b`'s five-series portfolio trend had no legend of any kind.**
- **`experts/analysis.html`'s "Coming soon" was a bare inline-styled `div`** with no affordance.
- **`left-panel-variants.html`'s comparison grid** used three fixed 340px columns with a dead
  gutter, so the variants being compared did not line up.
- **`account-view-v1.html` carried a 56px "Left nav" placeholder column**, duplicating the real
  navigation, with its label clipped.
- **`customer-table-v1.html` and `event-card-survey-v1.html` were narrow centred columns**
  (`max-width: 760px`/`1200px` on `body`) that clipped their own content.
- **`activity-progress-explorations-10` had a 500px dead gap** between its fixed 236px track and
  the next column.

### Systematic style faults

- Warm cream canvases (`#FAFAF7`, `#f7f6f2`, `#F0EDE8`) mixed with cool greys page by page.
- Colour doing two jobs: green as both "good" and "clickable"; blue and teal both as
  interaction; status hues used for chrome.
- Black buttons (`Review now`, `Continue automation`, `Ask AI`, `⚡ Launch`) and blue buttons
  (`#2563EB` Quick launch) side by side as primary actions.
- Uppercase letter-spaced micro-labels throughout — a pattern HubSpot's 2026 UI does not use.
  Some were `text-transform`, some were literal capitals typed into the markup.
- Monospace figures (DM Mono, JetBrains Mono) for percentages, dates and counts.
- ~380 text glyphs (`⚑ ✦ ✎ ⚙ ⇅ 🔍 ⏰ ▷ ⏸ …`) used as icons.
- Per-row inline avatar tints, which no stylesheet can override.
- Radii at 4, 5, 7, 8 and 12px in the same view; card shadows on non-cards.

---

## Where v2 still differs from the benchmark

Judged by an independent review against the capture, and recorded so nobody has to
re-derive it.

**Closed after the review:** the content plate is now `#f0f0f0` (was `#f5f5f5`); cards carry
HubSpot's `0 1px 8px rgba(20,20,20,.08)` in addition to the 1px border; table rows are 40px with
`2px 24px` padding rather than 44–62px with `11px 16px`; saved-view tabs are 48px with a filled
idle state; navigation rows are 52px; the page title is 20px; inputs are 16px/40px with a `#333`
border; value pickers are 6px rectangles rather than pills; progress meters are 6px tracks with
a status fill rather than teal pills.

**Deliberately different, and correct as they are:** the record pages are two-column where
HubSpot's are three — the prototype has no third association rail to show; chart series use the
status hue set rather than HubSpot's categorical palette, because here the series *are*
statuses; avatar rings carry status colour, which HubSpot does not do but which this product
needs; the automation canvas is centred rather than full-bleed.

---

## Two conventions the set uses that are easy to misread

**Blue and periwinkle are a channel axis, not a status.** On the ten progress explorations,
`activity-action`, `activity-kpi` and `automation-overview`, `--info` `#016de1` means the
*customer* stage of a feedback round and `--purple` `#6a78d1` means the *internal* stage. They
encode which audience a send is aimed at, which is orthogonal to how healthy the account is.
Status keeps its own hue set (`good` / `watch` / `risk`), and teal stays interaction-only. If
you add a page that shows round stages, use this axis; if it shows account health, do not.

**The status wording drifts across the exploration sets, deliberately.** `Poor / Fair / Good` on
the record pages, `Risk / Watch / Stable / Unmeasured` on the home and `portfolio-v8`,
`Poor / Watch / Good / Unknown / Churned` on `portfolio-v2`–`v3b`,
`At risk / Investigate / Grow / Unknown / Churned` on `v4`–`v6b`, and
`At risk / Watch / Grow / Unknown` on `my-clients`. The *colours* are consistent throughout;
only the labels differ, because each portfolio variant was testing a different vocabulary. That
is the point of an exploration set — but a shipped product must pick one, and the guideline does
not pick it for you.

---

## Conventions to keep if you extend this

- **Change `assets/foxie-hs.css`, not the pages.** Almost everything is expressible in tokens.
- **Put any page-level `<style>` after the stylesheet link**, so it can actually override the
  system. Every `dashboard/` page and every wireframe now does. The ten
  `activity-progress-explorations*` pages are the one deliberate exception: they layer a shared
  `assets/progress-explorations.css` between the system and the page, because that sheet is what
  replaces their legacy vocabulary and has to outrank it.
- **Teal is interaction only.** Links, primary buttons, focus rings. Never status, never
  progress, never a chart series.
- **Icons are inline SVG**: `viewBox="0 0 24 24"`, `fill:none`, `stroke:currentColor`,
  `stroke-width:1.6`, round caps and joins, 14px in controls and 16px in headers. Never a glyph.
- **Sentence case everywhere.** No `text-transform: uppercase`, and no labels typed in capitals.
- **Weight 500 is the working maximum**; 600 for the rare emphatic figure. Never 700.

---

## Final QA

All 57 pages plus the cover were screenshotted and reviewed one last time against the
benchmark. Result: no page scrolls horizontally, no page throws a console error, every page
carries the shared shell and the design system, and no page has clipped, overlapping or
collapsed content. Every defect listed above was verified closed.

Five issues the final pass turned up, all now fixed:

1. **The card had two elevations.** The shadow added in §31.2 reached `.card` / `.hs-card` /
   `.kpi` only, and 31 page-local `box-shadow: none` declarations — which won the cascade after
   the page `<style>` blocks were reordered — kept the rest flat. Six pages showed both
   treatments in one viewport. The page-level card classes now compose the same elevation, and
   the local opt-outs were removed.
2. **A literal `n1` rendered in the UI** on four pages, where a sample size of one printed the
   raw token instead of a range — the same class of bug as the `n 10` already fixed on
   `automation-overview.html`. Now an em dash.
3. **`review.html` opened scrolled 638px past its own header**, hiding the top bar, the page
   title and the pager. It auto-scrolled to the flagged item on load; it now highlights the item
   in place and opens at the top like every other page.
4. **Two native `<select>` controls** (`quick-launch`, `launch-redesign`) were the only
   browser-default controls in the set. Given the system's select geometry and an inline caret.
5. **The cover page's palette grid was missing `--info`, the accent, and the tag fill** —
   tokens in real use on 21 pages. A guideline that does not show its own palette is a gap.

Two things were left deliberately:

- **`activity-action.html`'s Progress column is compressed** — the same component needs roughly
  650px and has about 200px there. Widening it means re-cutting that page's column model, which
  is an information-architecture decision rather than a restyle.
- **The ten `activity-progress-explorations*` pages read as an appendix rather than as product**
  — no page header, and a blue stage palette used nowhere else. That is what they are: ten
  side-by-side studies of one component, kept for comparison. The blue encodes pipeline stage,
  not status, which is why it sits outside the status hue set.

---

## Appendix — the full working log

Every entry recorded during the transformation. A line beginning with a bracketed bang marks a
real defect in the v1 prototype that was repaired; a bracketed x marks a page that needed only
the restyle.


### Design tokens (extracted from HubSpot 2026 capture, computed styles — ground truth)

- font: "HubSpot Sans" unavailable publicly -> HubSpot's own fallback is **Lexend Deca** (Google Fonts). Use it.
- text: #141414 primary / #333 secondary / #666 muted / #8a8a8a hint
- border: #cccccc default, #e6e6e6 subtle
- surfaces: #fff card, #f5f5f5 subtle fill, #f0f0f0 canvas, #e6e6e6 hover
- shell/nav: #333333, nav text #fff
- interactive: link #006162, primary btn bg #00494B / white text
- radius: card 16px, pill 999px, control 6px, tag 6px
- type: body 14/400, small 13, micro 12, h2 22/500
- table: th 12/500 #666, td 14/400 #141414, row-h 40px, 1px #ccc separators
- buttons: h32, pad 8px 16px, fs 12px, pill radius; secondary = 1px #8a8a8a on white; toggled = #e6e6e6 fill


### Status legend

[ ] todo  [~] in progress  [x] done  [!] design-defect found (needs layout repair, not just restyle)


### System foundation

[x] assets/foxie-hs.css — design system built from computed styles of the HubSpot capture
[x] assets/shell.js — unified dark top bar + 236px left nav, replaces the three legacy frames
[x] all 57 pages — head patched: Lexend Deca, design system, shell, viewport 1600
[!] 11 pages were headless HTML fragments (no <html>/<head>/<body>): experts.html,
    customers/*.html (6), owners/owner.html, experts/*.html (3) → wrapped in real documents
    so they load fonts, tokens and shell like every other page
[x] palette codemod across 34 pages — legacy warm/blue/green palette mapped to HubSpot tokens
[x] font codemod — -apple-system / system-mono declarations mapped to --font-sans / --font-mono
[x] prototype-v2/index.html — gallery of all 57 pages, HubSpot-styled
[x] prototype-v2/README.md — what changed and why


### System foundation — observed

[!] dashboard/activity.html — grey skeleton placeholder rows used as filler; mono percentages
    and mono "Last 3 months" label; emoji glyphs used as icons; "Complete" status uses the
    interaction hue rather than a status hue
[!] dashboard/index.html — a position:fixed notification button floats over the shell corner
[!] dashboard/review.html — built as a full-screen .overlay, fights the new shell


### Account, owner and expert records

- [x] customers/customer.html — restyled: warm `#f7f6f2` canvas + `#F0EDE8`/`#e0ddd6` border family → neutral HubSpot greys; 0.5px hairlines → 1px `#ccc`; card radii 10px → 16px; all uppercase+letter-spaced micro-labels → sentence-case 12px/500 `#666`; `-apple-system` stack → `var(--font-sans)`; weight 700 → 600/500.
- [!] customers/customer.html — "Review now" CTA was a **black** `#1a1a1a` 7px-radius block → teal `var(--teal-primary)` 32px pill; "Quick launch" was a **blue** `#2563eb` button → teal pill; `.tl-cta` popover CTA and all hover states (`#1a1a1a` fills, black inset rings on selected cards) → teal.
- [!] customers/customer.html — "All feedback" sparkline card was visually clipped: it was the only card in the 4-up strip with no `.trend-months` axis row, so its polylines ran to the card's bottom edge with no baseline → added the matching month-label row. Also `.scard:not(.active)` had `border-bottom:none` + top-only radius, leaving the three inactive cards open-bottomed against the canvas → gave inactive cards a full border and 16px radius; active card keeps the tab-to-panel connection.
- [!] customers/customer.html — `.page` had `padding:20px;min-width:980px` and `.page-header` had `margin:-20px -20px 14px` calibrated to the old frame; inside `.hs-content` this double-padded and pulled the sticky header off-canvas → `.page` padding 0 / `min-width:0`, header re-anchored to `margin:0 -24px 16px;padding:6px 24px 0` so the sticky strip bleeds to the plate edges. Sticky `top:0` verified working (checked at scroll 1400).
- [!] customers/customer.html + experts/feedback.html — record left rail was a 200px column forcing 2-line wraps in every card → 296px, matching HubSpot's record left column.
- [x] customers/overview.html — restyled; KPI strip, AI-analysis boxes, risk/opportunity lists and contact tables moved onto the neutral palette + status tokens.
- [x] customers/analysis.html — restyled; signal tables, severity dots and the SWOT(E) grid on tokens.
- [x] customers/risks.html — restyled.
- [x] customers/opportunities.html — restyled.
- [!] customers/overview-rail.html — `.source-row .label` was `width:54px`, narrower than the word "Customer" at the new 13px size, so label and status dot collided with zero gap → 76px. Status trajectory bar was a fully saturated green→red gradient → same hues at ~30% alpha so it reads as a track, not a chart. Left rail 210px → 296px.
- [x] owners/owner.html — restyled; left rail 210px → 296px (ratings list and analysis bullets were wrapping to 3 lines).
- [x] experts/expert.html — restyled; KPI strip, dev-area/strength bars and account/feedback lists on tokens.
- [!] experts/analysis.html — the "Coming soon" tab was a bare centred `<div>` with inline styles and no affordance → rebuilt as a proper `.hs-empty` state (icon, sentence-case heading, explanation, teal primary + secondary pill actions).
- [x] experts/feedback.html — restyled; same "All feedback" clipping and open-bottomed-card defects as customer.html, repaired identically.
- [x] all 10 — near-duplicate copies of the same page CSS converged: identical `.page` / `.page-header` / `.layout` / `.scard` / `.lcard` rules now carry identical token-based values across customers, owners and experts records.


### Core workspace pages

- [!] index.html — "Quick launch" CTA was a hard-coded blue (#2563EB) 7px-radius inline button → replaced with `.hs-btn.hs-btn--primary` teal pill.
- [!] index.html — stray literal `\n` text node rendered as visible text between `</script>` and `</body>` → removed.
- [!] index.html — table `<th>` labels were literal UPPERCASE strings (NAME, ACCOUNT OWNER, …) so no CSS could normalise them → rewritten to sentence case in markup.
- [x] index.html — restyled: KPI clusters to 16px cards / 12px sentence-case labels / 28px values, `.kc-label` uppercase eyebrows killed, ov-cards to 16px radius + 16px titles, chips/tags to `#e6e6e6` 6px, list names to teal, popovers (`.pd-pop`, `.tlpop`) to 16px + `--shadow-float`, task-flag button to pill.
- [x] index.html — Chart.js retuned to the new status palette (`#009a71`/`#d39913`/`#d9002b`), axis ticks to 12px `#666` Lexend Deca, gridlines `#e6e6e6`.
- [!] my-clients.html — page redeclared the whole legacy token set in `:root` (warm `#FAFAF7` canvas, `#ECECE6` borders, 12px radius, old green/amber/red) which overrode `foxie-hs.css` globally → deleted the entire duplicated token + table + pill block, kept only genuinely page-specific rules.
- [!] my-clients.html — client avatars were 7px rounded rects with per-row inline tint colours → neutral `.avatar.avatar-lg` circles.
- [x] my-clients.html — page header rebuilt as `.hs-page-head` (title + sub + right-hand action slot), legacy divider-ruled `.summary-bar` reworked to a HubSpot metric strip (subtle `--n-200` separators, 12px sentence-case labels, 28px values), action chips to pills.
- [!] risk.html / growth.html — hero banner was a diagonal `linear-gradient` with a saturated border → flat status-tint banner on a 16px card.
- [!] risk.html / growth.html — the active source filter was a solid **black** pill → HubSpot toggled state (`#e6e6e6` fill, `--n-500` border); inactive pills to h32/pill/12px.
- [x] risk.html / growth.html — signal source chips de-blued/de-purpled to `#e6e6e6` tags, signal icon squares to circles, account-block headers to 16px cards with teal company names, per-signal rows to 44px with `#ccc` separators, detail panel quote/AI blocks retokenised.
- [x] owners.html — restyled: KPI row from an auto-width flex strip to a 5-up 16px-card grid, filter tabs to saved-view tabs, `0.5px` hairlines to `1px #ccc`, thead to 12px `#666` sentence case, rows to 44px, owner name from `#1a6ac4` blue to `--teal-link`, avatars/company logos to neutral circles (inline tints stripped), black "A" strategic badge to a grey tag.
- [!] experts.html — `#open-notif` toast declared `display:none` *and* `display:flex` in the same inline style, so the "— opening expert view…" debug bar was permanently visible at the bottom of the page → dead element removed.
- [x] experts.html — document wrap is correct; whole stylesheet rewritten onto tokens (page canvas removed so `.hs-content` owns padding, KPI grid, saved-view tabs, teal person names, neutral circular avatars, status/risk flags to `--*-bg`/`--*-text`, uppercase `<th>` literals sentence-cased).
- [!] expert-portal.html — page loaded `'DM Sans'` and an indigo brand palette (`#4F46E5` pills/notes, `#D9F25B` logo tile) plus a 780px centred column fighting `.hs-content` → refonted to `var(--font-sans)`, indigo replaced by `--teal`/`--info` tokens, `.pbar` turned into an in-flow 16px record-header card, column left-aligned at 900px.
- [x] expert-portal.html — round pills to saved-view tabs, answer/annotation blocks and option buttons retokenised (pill controls, 6px tags, `--good-bg`/`--watch-bg` chips).
- [!] crm.html — `.app{height:100vh;overflow:hidden}` + `.main{overflow:hidden}` + `.content{overflow-y:auto}` created a nested scroll trap inside the new shell (page could not scroll with the shell) → switched to normal document flow.
- [!] crm.html — primary CTA blue `#2563EB` and an "Ask AI" **black** button with `#E8FF6B` text → teal-primary pill and a standard secondary pill. Contact-role chips were blue/purple bordered → grey `#e6e6e6` tags. Emails were `#2563EB` → `--teal-link`.
- [x] crm.html — leftover 160px `nav.sidebar` (shell.js strips it) left no dangling grid: `.app` is now `display:block`; `.topbar` demoted to a borderless page-head strip; table to HubSpot anatomy (12px `#666` th, 44px rows, `#ccc` separators, teal company names); `ACTIVE`/`COMPLETED` badges from bold uppercase micro-pills to sentence-case status tags; monospace "Last 12 months ↓" replaced with a `.period` control.
- [!] review.html — built as `position:fixed; inset:14px` `.overlay` with a `box-shadow` floating over a `#45433e` body: it covered the whole viewport including the new top bar and left nav, and `#headerB` was `position:sticky;top:0` inside it → made the overlay a normal in-flow in-shell page (`position:static`, transparent, no shadow), header a static page-head strip, `.main` grid unpinned from its 1240px centred max-width, and the JS `$('overlay').scrollTo(...)` retargeted to `window.scrollTo(...)` so the jump-to-flagged behaviour still works.
- [!] review.html — `#devstrip` was `position:fixed; left:22px; bottom:22px`, landing on top of the shell's left nav → re-anchored to `right:22px`.
- [x] review.html — full retokenisation: warm cream flag/round cards to `--watch-bg`, black "Continue automation" button to teal pill, `0.5px` hairlines to `1px #ccc`, `● UNDECIDED` badge sentence-cased, radios to `accent-color: var(--teal-primary)`, modal to 16px + `--shadow-float`.
- [!] quick-launch.html — the whole page was a `position:fixed` `.ql-scrim` dark scrim + a 1040px floating panel over a fake skeleton "Automations" screen (complete with its own 160px `nav.sidebar` and brand block). As a left-nav destination it dimmed the real shell and duplicated the navigation → scrim de-fixed to a static container, panel turned into a full-width in-shell 16px card with no shadow, and the fake background app screen deleted.
- [x] quick-launch.html — blue `#2563EB` selection/link/CTA colour replaced with `--teal-primary`/`--teal-link`, `#E8FF6B` spark tile to a neutral circle, step rail and footer buttons to pill controls, focus rings to teal.


### Activity, automation and email

[!] activity.html — grey "reduced-fidelity skeleton" filler rows sat in the middle of a table of real data, reading as an unfinished layout rather than a loading state (no other loading affordance on the page) → replaced with two real rows (Nordkalk / Vaisala) that also give the table its missing non-Complete states
[!] activity.html — every row's "Complete" status used the interaction hue (#4a56a8 blue-violet); statuses and links were indistinguishable → moved to `.status-pill-tbl` with `sp-grow`/`sp-watch`/`sp-unknown` status hues
[!] activity.html — percentages and the "Last 3 months" control were set in 'DM Mono' → `var(--font-sans)` tabular, and the bare `0% / 50% / 100%` cell became a `.hs-progress` meter + tabular figure
[!] activity.html — emoji glyphs (⏰ ▷ ⏸ ✎ ✓ ＋ ↻ ⧉ ✦ ‹) used as icons → inline 1.6-stroke SVGs matching the shell icon set
[x] activity.html — action toolbar → `.hs-toolbar` / `.hs-toolbar-btn`; Contacts|Companies → `.hs-segmented`; Editor/Activity/Admin → `.ftab`; search input had no `type` so the shared input rules never matched it (rendered as a browser default) → styled locally; added `.hs-pagination`
[!] activity.html — the page's `.app` was `display:flex; height:100vh; overflow:hidden` with the AI panel as a viewport-height flex sibling; renamed to `.act-shell` so it stops fighting the shell, and the AI panel is now a sticky in-content column
[x] activity-kpi.html — chart/KPI exploration restyled onto tokens: 28/500 tabular figures in `--text` (chart hue moved to the swatch, teal reserved for interaction), 8px pill meters, 16px cards, `.etab` tab strip; "OPTION A/B/C-min…" eyebrows → sentence case
[!] automation-overview.html — the Account-owner delta rendered as the literal string `n 10` (a broken glyph substitution) → replaced with a flat-trend icon + "no change"
[!] automation-overview.html — 52% / 43% / 10% answer rates were monospace → sans tabular; added a `.hs-progress` answer-rate meter per stage (per `_verify/11`) and labelled the per-send bars "Answers per send" so the two bar rows are no longer ambiguous
[x] automation-overview.html — black-on-mint "⚡ Launch" → `.hs-btn--primary`; crumb/tabs rebuilt on tokens
[!] automation-editor.html — form controls were ad-hoc (`.fakesel` 8px-radius 12px chips, uppercase 10px "MESSAGE" eyebrow, unstyled pickers) → HubSpot form system: 36px min-height, 6px radius, 1px #8a8a8a border, teal focus ring, `.hs-label`-weight labels
[x] automation-editor.html — black step-number bullets, black segmented toggles and the black ⚡ Launch button → teal/neutral; ⋮ 🕘 📄 🗒 ✉ ⚡ ⚑ ▾ › emoji → inline SVG; teal-tinted "Customer" role pill → neutral tag; running-count banner moved from green to the info banner treatment
[!] emails-reviews.html / emails-late-arrivals.html — `body` carried `background:#EDEBE6` plus `padding:24px 12px 60px`, double-padding inside `.hs-content` → removed; cream `#FBF3E2`/`#FCE3C4` callouts → `--watch-bg`; black active preview tab → HubSpot saved-view tab; ⚑ ▲ ⚠ glyphs → SVG
[!] emails-*.html — the shared `.tab:first-child{font-size:22px}` rule (saved-view "page title" tab) hit these pages' generic `.tab` preview switcher, rendering the first tab at 22px while the rest were 14px → worked around with `.tabbar .tab…` specificity (system request raised)
[!] launch-redesign.html — the page painted a fake host page (topbar + grey skeleton blocks) behind the launch dialog; the real application shell is that backdrop now, so the stand-in was double chrome → hidden
[x] launch-redesign.html — teal-tinted company chips → neutral tags, black step marks/segmented controls → teal/white, 7px-radius buttons → system pills, `#1d4fd0` blue hover on the primary button → teal; ✎ ✓ ＋ ▾ ▸ ✦ ⚑ in the JS-rendered markup → inline SVG. `launch-redesign-embed.js` only iframes this page, so the embedded markup is covered by the same restyle (verified via automation-editor's ⚡ Launch)
[!] activity-action.html — 145KB page: black "Companies|Contacts" segmented control and black-on-mint "Ask AI" → `.hs-segmented`/system pills; `#141414` completion markers inside the JS-drawn progress tracks → teal; donut labels in 'DM Mono' → sans; `.anum.warn` #b8860b → `--watch-text`; company column now the teal primary scan-line; 7 action-tile emoji icons (↻ ⏸ ⏰ ✉ ✶ ☷ ✎) → inline SVG
[!] activity.html / activity-action.html / automation-editor.html / launch-redesign.html — foxie-hs.css §24 forces `.hs-content .overlay, .hs-content .ql-scrim` to `position:static`, which broke four *real* modal dialogs (they rendered inline in the page flow instead of overlaying) → restored locally with one extra level of specificity (system request raised)


### Portfolio explorations

[x] portfolio-v8.html — restyled (the canonical "Account portfolios" page). Page style put on tokens: 12px→16px card radius, .pv8-label eyebrow (11px uppercase) → 16px/500 sentence-case card title, .mockup-section-label captions → quiet 13px #666, footers → 13px with teal links, warm greys (#C8C4BC/#B5B1A8/#FAF9F5) → n-400/n-300/n-50, weight 600/700 figures → 500.
[!] portfolio-v8.html — Revenue/Accounts toggle was a bespoke 11px grey box-shadowed segment → rebuilt on `.hs-segmented` (pill track, white active chip, 13px).
[!] portfolio-v8.html — sections A and B: the breakdown rows are the chart legend, but rendered only a dot + count + revenue with NO category name, so nothing said which colour was Risk/Watch/Stable/Unmeasured → added the label column (dot · count · label · value) and widened the column 130px→184px.
[!] portfolio-v8.html — every trend chart had `y: { display: false }`, so stacked area/bar charts carried no value scale at all → y axis enabled with #e6e6e6 gridlines, 12px #666 ticks, money formatting on the revenue charts and plain counts on the people charts; x ticks 10px→12px, tick colour #9A958F→#666.
[!] portfolio-v8.html — `fmtRev(0)` returned "€0k"; fixed to "€0" now that the axis renders a zero tick.
[x] portfolio-v2.html — restyled; literal uppercase micro-labels in markup (NPS/AVG SATISFACTION/STATUS BREAKDOWN/TOP AT-RISK ACCOUNTS/TOP CONCERNS/6-MONTH REVENUE TREND/table headers) rewritten to sentence case — shell.js only strips `text-transform`, it cannot fix text that is typed uppercase.
[x] portfolio-v3a.html — restyled (same shared block as v2).
[!] portfolio-v3b.html — the status-tab strip (`.pf3-stab.is-active`) was a solid black pill with white text; retoned to the HubSpot toggled state (#e6e6e6 fill, #141414 text, #8a8a8a border, 999px). Its uppercase section labels are generated in JS (`accountsLabel: 'TOP AT-RISK ACCOUNTS'` etc.) so the runtime normaliser never touched them → sentence-cased at source.
[!] portfolio-v4.html — the "Churned · last 6mo" breakdown row rendered as a solid #2A2A28 band with white text, the only black surface on the page → neutral #e6e6e6 tint with #333 text and an n-700 dot.
[!] portfolio-v4/v5/v5-1/v5-2/v6a/v6b — the 5-series stacked "Portfolio trend" chart had `legend: { display: false }` and no HTML legend anywhere, so Churned/Unknown/Good/Watch/Risk were unlabelled → Chart.js legend enabled top-start as dot + 13px #333 label rows; gridlines #F0F0EA→#e6e6e6, ticks #8a8a8a/11px→#666/12px.
[!] portfolio-v4/v5/v5-1/v5-2/v6a/v6b — chart series used warm #D4D4CE for "Unknown" and pure #141414 for "Churned" → #cccccc / #4d4d4d.
[x] portfolio-v5.html — restyled.
[!] portfolio-v5-1.html — the left segment was 0.75fr and its inner two-up (Top at-risk accounts / Top concerns) collapsed: the column labels and every concern name broke over two lines → left column widened to minmax(360px, .92fr), inner grid to 1fr 1fr.
[!] portfolio-v5-2.html — "Strengths & weaknesses" meters used warm pastels (#E8A09A / #A8CE99 on #EFEDE7) → status palette (--risk / --good on --n-200); churned bar-fill #5A5A55 → #4d4d4d.
[x] portfolio-v6a.html — restyled.
[x] portfolio-v6b.html — restyled.
[!] portfolio-v7.html — the three donut cards overlapped their own titles: `.donut-center` was pinned with `top/left:50% + translate(-50%,-50%)`, but shared `.donut-wrap`/`.donut-center` (foxie-hs.css §12) resets it to `inset:0`, so the translate dragged "35 clients" / "6 owners" / "12 experts" up onto the card headings → re-anchored with `inset:0; transform:none` and the wrap sized to 86px.
[!] portfolio-v7.html — `.signals-row` declared `repeat(3, 1fr)` but only two signal cards were ever written (the `.sig-nurture` card is styled and never rendered), leaving a dead third column → grid set to two columns.
[!] portfolio-v7.html — `.sig-click-hint` was `position:absolute; bottom:10px; right:14px` and landed on top of the source-breakdown counts ("13" / "7") → moved into flow as a right-aligned teal link row.
[!] portfolio-v7.html — revenue blocks used warm tints with a 2px amber accent border, ARR/arrow figures were set in 'DM Mono', and `.filter-pill.active` was a black pill → status-token tints at 16px radius, var(--font-sans) figures, #e6e6e6 toggled fill.


### Wireframes

[!] all 8 wireframes — page `<style>` was emitted BEFORE the `foxie-hs.css` link, so the design system silently overrode every page-level rule (e.g. outlined `.pill` rendered as a filled grey chip) → moved each page's `<style>` block after the stylesheet + shell.js tags.
[!] customer-table-v1.html — `body{padding:32px;max-width:1200px;margin:0 auto}` fought `.hs-content`, leaving the page as a narrow column on the dark shell → removed; tables were full black cell-grids (`border:1px solid #000` on every th/td) → wrapped each `<table>` in a `.tbl-card` (white, 1px `--n-300`, radius 16, overflow hidden) with horizontal separators only, 44px rows, 12/500 grey th, teal name column; swatch grid rebuilt as a 1px-gap token grid (the old `margin:-1px` overlap trick broke the rounded container); added a page title/subtitle header.
[!] event-card-survey-v1.html — `body{padding:32px;max-width:760px;background:#fafafa}` clipped the whole page to a 760px strip inside the shell → removed, reading column moved onto `.stack{max-width:900px}`; `.icon-stub`/`.menu-stub` rendered as 16px black-outlined squares that read as unstyled checkboxes → icon becomes an `--n-200` rounded chip, menu becomes a ghost `⋯` icon button; theme highlight machinery re-tinted from saturated orange/blue (`#e85d2c/#fde2d4`, `#2c6ce8/#d6e3fb`) to `--risk`/`--risk-bg` and `--watch`/`--watch-bg` (critical/amber), toggles rebuilt as h32 pill buttons; behaviour verified working after restyle.
[!] account-view-v1.html — the frame carried a 56px "Left nav" placeholder column that duplicated the real shell nav and clipped/wrapped its own label → column removed, frame is now `340px / 1fr` with the header spanning both; black 1px wireframe boxes with `margin:-1px` overlap → single rounded token frame, cards on `--n-300`/radius 16, uppercase micro-labels sentence-cased.
[x] account-view-source.html — restyled onto tokens (card radius 8→16, `#e6e6e6`→`--n-300`, navy `#18193f` KPI value → `--text`, bullet dots `#f87171`/`#7fd6bd` → `--risk`/`--good`); header bar de-boxed to a border-bottom strip, tabs to teal-underline, date range to a pill control; `max-width:1400px;margin:0 auto` on `.account-body` removed so it fills the plate.
[x] account-view-topic.html — same restyle; topic meters now `--n-200` track with `--risk`/`--good` fills at pill radius, `.topic-section-label` sentence-cased.
[x] account-view-hybrid.html — same restyle; top rail cards on the card token set, `.person` status rings mapped to `--good`/`--watch`/`--risk`; click-to-highlight (topic row → feed) re-verified with a scripted click, highlight now `--risk-bg` tint + 2px inset marker.
[x] account-view-hybrid-kpi-panel.html — same restyle; KPI strip re-typed (22/500 value, 12/500 grey label, `--n-200` column rules).
[!] left-panel-variants.html — comparison grid was three fixed 340px columns leaving a dead gutter and no shared column edge → `grid-template-columns: repeat(3, minmax(300px,1fr))` so the three variants line up and fill the plate; V2's hollow ring `.reason-dot` (which read as an unstyled radio) filled to `--n-400`; health-rail + KPI replica cards moved onto card tokens, variant/preview labels sentence-cased.


### System foundation — second round

[x] applied every system request raised by the page agents into assets/foxie-hs.css §23–28
[!] §24 (.overlay/.ql-scrim neutralisation) was too broad and flattened four real modal
    dialogs → narrowed to direct children of .hs-content only
[!] §6 (.tab:first-child = 22px page title) leaked onto generic tab strips → scoped to .topbar .tabs
[!] §12 .donut-center kept legacy translate(-50%,-50%) on top of inset:0, dragging captions
    out of the donut → transform:none added
[x] assets/chart-defaults.js — HubSpot chart treatment as Chart.js defaults + FOXIE_SERIES
[x] grey-snapping codemod — 466 near-neutral hexes across 39 pages snapped onto the token ramp
[x] typography codemod — 57 weights >600 → 600, 22 radii 4/5px → 6px, 49 CSS uppercase rules removed


### System foundation — resolved late

[ ] CASCADE ORDER. Page <style> blocks sit BEFORE the foxie-hs.css link in 49 of 57 pages, so
    the design system wins every equal-specificity contest. The wireframes agent flipped its 8
    files to the conventional order (system first, page CSS after). Both sets are visually
    verified as they stand, but the repo now carries two conventions. Flip the remaining 49 and
    re-verify once the last page agents are out of those files.


### Round-progress explorations

[x] shared — the ten `activity-progress-explorations*` pages duplicated one page-level `<style>` vocabulary (`.treat`, `.tbl`, `.track/.seg`, `.stpill`, `.anum`, `.controls`); translated it once into `assets/progress-explorations.css`, linked after `foxie-hs.css` in all ten, rather than ten local rewrites
[x] all 10 — DM Sans / DM Mono `@import` removed; body + every figure class moved to `var(--font-sans)` with `font-variant-numeric: tabular-nums` (`.anum .tknum .cbadge .range .aggnum .resp .cap.pct` and the donut `<text>` inline style)
[x] all 10 — 40 warm/cream prototype hexes (#c3bfb6 #e7e4dd #a7a399 #f2f0ec #ece7de #f4f2ed #edebe4 #9a978f …) codemodded onto the neutral ramp; olive/brick accents (#3f5a1a #2f4610 #cfe3b3 #a4553f #b8860b) onto the good / risk / watch tokens
[!] all 10 — progress fills used the interaction hue: the Customer stage colour was `#00494b` (teal-primary) in `STAGE_COLOR`/`palette`, so every bar, donut, icon and legend dot read as "link" → remapped the Customer series to `--info` #016de1 and the current-step tint from `--teal-tint` to `--info-bg`; teal now only survives on `accent-color` for checkboxes
[!] all 10 — 84 emoji glyphs used as icons (✉ ↻ ⚑ ⚐ ✔ ✓ ◇ ★ ▸ ▾ Σ) inside 19–21px step boxes → replaced with inline stroke SVGs (`.gi`, 1.5px currentColor) matching the shell's icon style
[!] all 10 — "done" states were painted pure black (#141414 bars, step chips, connectors, tag/`.bsig`/`.segb.on` chips) → progress ink moved to `--n-700`, black chips to the neutral tag box
[x] all 10 — uppercase letter-spaced micro-labels (`h2`, `.hrow th`, `.controls .lbl`, `.treat-tag`) set to sentence case, 12px/500, `--n-600`; page `h1` 21/700 → 22/500; every `font-weight:700` in the style blocks dropped to 500
[x] all 10 — cards (`.treat`, `.wrap`) re-boxed to `#fff / 1px --n-300 / 16px / no shadow`; 5/8/9/10/12px radii retired; tables put on the list-view convention (th 12/500 --n-600, td 14/400, --n-300 separators, `--n-50` row hover)
[!] all 10 — `.stpill` status was bare coloured text with a dot, no pill → given the `status-pill-tbl` box (good / watch / neutral bg + text tokens)
[!] -10 — class-name collision: the "Close marker" segmented control used `.seg`, the same class as the 7px progress-track segment, so the control rendered as a black 7px bar with unreachable buttons → scoped a `.controls .seg/.segb` segmented control (pill, `--n-200` trough, white active) that wins over the track rule; also killed its `position:sticky` bar and black active fill
[!] -10 — the Progress column was a fixed 236px track inside a full-width table, leaving a ~500px dead gap before "Next" → track/trackc given `min-width:360px` and the cell width released
[!] -2 — the response-rate mini meter (R2/R3) never drew: `.resp .rfill` was a `display:inline` span, so `height:100%` + `width:<pct>%` collapsed to a 0×0 box and every row showed an empty grey pill → fill set to `display:block`
[!] -2 — `.hoverwrap` (an inline tooltip anchor around a track) was being caught by the card rule and boxed the bars into a 64px pill with the fills clipped → excluded from the card selector and restored as an inline-flex anchor
[!] -1 — the "F · Timeline" treatment positions every node `position:absolute`, so its cell had no intrinsic width and collapsed to ~180px jammed against the right edge of each row → `.c-viz .t-time` given an explicit 520px/min 420px width
[!] -1 — the "pick" recommendation badge was a black chip with an inline style; density tags (`minimal / medium / detailed`) were uppercase, letter-spaced, 10.5px, in three saturated hues → badge moved to the good-status tag, density tags to the neutral 12px chip
[x] -3 -4 -5 -6 -7 -8 -9 — inherited the shared transform; verified individually (top + lower region) with no page-specific defects left


### Icon and consistency pass

Consistency pass: every text-glyph icon across the 39 assigned pages replaced with inline
SVG in the shell's icon language (24-viewBox, stroke `currentColor`, stroke-width 1.6, round
caps/joins, never filled, 14px in controls / 15–16px in headers / 18–30px in hero tiles).
259 markup glyphs + ~60 glyphs living inside JS template strings + 75 `›` disclosure
chevrons converted; `→ ← ↑ ↓ • − ≈` left alone where they read as running text.

- [x] crm.html — 49 glyph icons → SVG; `[!]` "Import / Export" button was a blue outline (`#bfdbfe`) with teal label → plain secondary pill
- [x] portfolio-v7.html — 18 glyphs; `[!]` `€` character used as the growth signal icon in 12 places (hero tile + signal rows) → trending-up SVG; `[!]` icon tile radius 12px → 50%; `[!]` 57 non-token hexes (pastel avatar chips `#fce4ec/#e3f2fd/#fff3e0`, `#a32d2d`, `#854f0b`, `#faeeda`) → tokens
- [x] activity-action.html — 14 markup + 12 in-JS glyphs; `[!]` `.tree-check` checkbox drew its tick with `content:'✓'` and its indeterminate state with `content:'–'` → CSS-drawn tick/bar; `[!]` `<option>Inside Reschedule (＋ add reminder)</option>` — plus glyph inside a `<select>` option (would have rendered raw markup) → plain `+`; `[!]` uppercase literals `SENT` / `SENT TO ALL` / `PARTLY SENT` / `NEW` → sentence case; `[!]` blue `#b6d9fb` borders and a blue `rgba(37,99,235,…)` tile shadow → neutral tokens
- [x] automation-editor.html — 24 glyphs; `[!]` two `textContent` assignments ('Set up launch ▸', '✦ Launch') switched to `innerHTML` so the SVG renders
- [x] review.html — 13 glyphs; `[!]` decision badge wrote `'■ ROUND WILL STOP'` and `'✓ ' + pillText().toUpperCase()` — literal shouty caps → sentence case, `.toUpperCase()` dropped; 6 `textContent` writes → `innerHTML`
- [x] index.html — 12 glyphs incl. the `◍ Overall status` toggle and the `▲` risk marker (inline `#a1001f` → `var(--risk-text)`)
- [x] my-clients.html — 15 glyphs, all inside the JS data model / row renderers
- [x] quick-launch.html — 14 glyphs (stepper marks, sender checks, `▾/▴` expanders, `✉/✎` message head)
- [x] activity-kpi.html — 15 glyphs + `[!]` tool strip mixed text arrows with icons (`→ Continue`, `❚❚ Pause`) → play/pause SVG, and `▷ Confirm` used a play icon for a confirm action → check
- [x] customers/customer.html — 11 glyphs + 8 in-JS (`textContent` → `innerHTML`), `▲` watch marker re-tokenised
- [x] customers/overview-rail.html — `[!]` `€` glyph in the Opportunities card icon → trending-up SVG; `[!]` three `NEW` badges typed in caps → `New`
- [x] customers/overview.html, customers/analysis.html (17), customers/risks.html, customers/opportunities.html — glyphs + `⤢` SWOT expanders → SVG
- [x] experts.html, experts/expert.html, experts/feedback.html, experts/analysis.html — sort/chevron glyphs → SVG
- [x] owners.html, owners/owner.html — `↕ Sort`, `⊕`, expander `›` → SVG
- [x] growth.html, risk.html — hero glyph → 28px sparkle / flag SVG (the old `font-size:32px` sizing removed)
- [x] emails-reviews.html, emails-late-arrivals.html — `✉ ⚑ ⚠` → SVG; `[!]` `NEW` badge → `New`
- [x] activity.html, expert-portal.html, launch-redesign.html — glyphs → SVG; expert-portal `›` disclosure caret (rotated 90° on open) → chevron SVG
- [x] portfolio-v2/-v3a/-v3b/-v4/-v5/-v5-1/-v5-2/-v6a/-v6b — card-title + toolbar glyphs → SVG; `[!]` ~13 non-token tag/avatar hexes per page → status/neutral tokens
- [x] portfolio-v8.html, automation-overview.html — verified clean, no glyph icons, no changes needed


### List-view anatomy

- [x] dashboard/my-clients.html — HubSpot list chrome: in-card full-width search, `.hs-toolbar` control row, 44px checkbox column + 28px caret column, centred `.hs-pagination` footer ("Showing 8 of 8"). Pattern copied from `activity.html`.
- [x] dashboard/index.html — same chrome on the "Recent customer updates" card; the detached `.table-actions` button row (Risk first / Filter / Search / Overall status) was **moved inside the card** as a quiet `.hs-toolbar`; the old `.table-footer` "Load more" line replaced by a real pagination footer (Prev 1 2 3 4 Next · Showing 9 of 35 accounts). Status-toggle button kept live.
- [x] dashboard/owners.html — `.table-controls` row was floating **above** the card; moved inside `.portfolio-table` as search + toolbar. Added a `c-check` column to every `<colgroup>` (owner tables and expanded sub-tables) plus per-row checkboxes; the existing `c-expand` caret column now reads as HubSpot's row-expand column. Footer count corrected to the **real** row count (4 owner rows, not the 6 the tabs claim).
- [x] dashboard/experts.html — `.table-controls` moved inside `.table-wrap`; checkbox + caret columns added; pagination footer ("Showing 7 of 7 experts"), count taken from the actual rows rather than the "12 experts" label.
- [!] dashboard/experts.html — the table's `<th>` widths sum to 100%, so the new 44px/28px columns collapsed to ~15px → gave `.col-check`/`.col-caret` an explicit `min-width` (applied to every page's chrome block).
- [x] dashboard/crm.html — the toolbar (search + Show excluded / Filter / Sort / Review / Import-Export / + New) sat **outside** the card; moved inside as `.hs-searchbar` + `.hs-toolbar`, "+ New" kept as a primary pill at the right. Checkbox column added to company rows and contact rows, caret on the expandable company rows, `colspan` adjusted. Pagination footer added with the real counts (7 companies · 16 contacts) rather than the banner's 11/26 claim.
- [!] dashboard/crm.html — fidelity deviation #6 fixed: the hand-rolled "Quick launch" button (inline `border-radius:7px; font-size:12.5px; font-weight:600; padding:7px 13px`, the only 7px-radius and only 600-weight button in the nine-page set) → replaced with `class="btn hs-btn--primary"`, matching `index.html` / `activity.html`.
- [!] dashboard/risk.html, dashboard/growth.html — these are grouped signal feeds, not tables: N free-floating `.account-block` cards with a detached `.filter-bar` above them, so there was no list anatomy at all. Wrapped the whole feed in a single `.lc-listcard` (card border + shadow, groups become internal sections with hairline separators), moved the filter bar inside as search + `.hs-toolbar` (All / Customer / Internal kept live, JS selector rewired from `.filter-pill` to `.src-filter`), added a leading checkbox to each group header and each signal row, and closed with a centred pagination footer stating the real rendered counts (risk: 10 of 16 signals · 3 of 7 accounts; growth: 9 of 23 · 4 of 19).
- No shared-system changes needed — `.hs-searchbar`, `.hs-toolbar`, `.hs-toolbar-btn`, `.hs-pagination`, `.hs-page-btn` already existed in `foxie-hs.css`; all page-level additions are a single identical `HubSpot list-view chrome` block per page.


### Full-set regression sweep

Post-section-31 regression sweep + final pass over 50 pages (dashboard leaf pages,
`customers/`, `owners/`, `experts/`, all 8 wireframes). Every page screenshotted at
1680×1050 and read; `shots/J1-*.png`.

Section-31 damage found and repaired:
- [!] `dashboard/activity-action.html` — the stage-close marker `.ffico` is a 16×8px box that
  carried a 12px `&#9873;` glyph, so the flag was sliced in half at the new row density
  (and was a glyph used as an icon) → swapped for the house 7px flag SVG and dropped the
  font-size override.
- [!] `dashboard/portfolio-v7.html` — the page's own `<style>` block loads *after* the earlier
  `#d1-v7` override block, so none of the d1 repairs applied: an 86px donut canvas sat in a
  58px `.donut-wrap` and spilled across the neighbouring KPI card ("6 owners" / "12 experts"
  hung outside their cards), `.sig-click-hint` stayed `position:absolute` and printed on top
  of the signal-source numbers, and `.signals-row` still declared 3 columns for 2 cards
  → added a trailing `<style id="j1-v7">` block that re-lands all of it (donut 64px,
  `.donut-card{overflow:hidden}`, static hint, 2-column signals row).
- [!] ten `dashboard/activity-progress-explorations*.html` — `assets/progress-explorations.css`
  (shared, not editable here) pins `.page h1` at 22px and wins over section 31.8's 20px page
  title → local `<style id="j1-ape">` override on each page; request logged in
  SYSTEM-REQUESTS.md to fix the shared file and delete the ten blocks.

House-rule violations cleaned up (secondary pass):
- [x] off-scale radii — 4/5/7/9/10/11/12/13/14px `border-radius` → 6px, 18/20px → 999px on the
  pill-shaped elements, across 25 pages (`.msg`, `.rail-row`, `.etab`, `.fork-opt`, `.filter-pill`,
  `.ab-status`, `.kpi-cell`, `.modal`, `.seg`/`.fill` bars, `.ansgroup`, …). 8px left alone —
  it is `--radius-sm`, a system token.
- [x] weight 700 — `<b>`/`<strong>` at 700 on `activity-kpi`, `automation-editor`, `quick-launch`,
  explorations 2/3/5, `customers/{customer,overview,overview-rail,analysis}`,
  `experts/{expert,feedback}` → page-local `b,strong{font-weight:500}` on all 50 pages.
- [x] page titles — `.customer-name` was 22px/600 with `letter-spacing:-0.3px` on all six
  `customers/` + three `experts/` pages, and the four wireframe `h1`s were 22px → all 20px/500,
  letter-spacing dropped (section 31.8).
- [x] monospace figures — `'DM Mono'` on `quick-launch` (`.rr-mark`, `.sch-num`, `.chip`, schedule
  inputs) and `portfolio-v7` (`.ab-arr`, `.arr-val`, `.rcr-arr` currency figures) → removed.
- [x] fractional type — 9.5 / 10.5 / 11.5 / 12.5px snapped to the 10/12/14 scale on 31 pages.
- [x] glyph used as an icon — 📅 emoji in the date-range control on the four
  `wireframes/account-view-*.html` → the house calendar SVG.
- [x] `dashboard/automation-editor.html` — `.dr-title` 17px → 16px (H1 fidelity item #10).
- [x] `dashboard/customers/customer.html` — `.ctab.active` faked its border with
  `box-shadow: inset 0 0 0 1px` → real `border-color` (H1 fidelity item #13).
- [x] `dashboard/quick-launch.html` — `.sch-num` step badge was filled `#141414` (black) →
  `var(--teal-primary)`, matching the active step badge on `launch-redesign`.

Verified clean, no changes needed: `activity`, `activity-kpi`, `automation-overview`,
`emails-reviews`, `emails-late-arrivals`, `launch-redesign`, `review`, `expert-portal`,
`portfolio-v2/v3a/v3b/v4/v5/v5-1/v5-2/v6a/v6b/v8`, all ten explorations bodies,
`customers/{overview,overview-rail,analysis,risks,opportunities}`, `owners/owner`,
`experts/{expert,analysis,feedback}`, all 8 wireframes. Progress meters on these pages
already carry the right status variant (green where "good", `--info` blue for the
"where we are" stage in the explorations set) — no green-by-default regressions found.

Not fixed, deliberately: KPI *values* tinted red/green (`€220k`, `6`, `€542k`) on
`portfolio-v2`…`v6b` and `owners/owner` — same class of deviation H1 flagged on `owners.html`;
left alone here because on these pages the tint sits inside an explicitly status-tinted tile,
and changing it would be a design decision rather than a repair.


### Final list-page pass

[!] all 7 — control-row "column settings" button carried a **sun/starburst** pictogram where HubSpot has a gear → replaced with a gear path + aria-label/title.
[!] my-clients, owners, experts, risk, growth — "Export" used an **upload** arrow (arrow leaving the tray) → replaced with a download arrow.
[!] crm — "Show excluded" used a plus-in-circle (an *add* action) for a visibility toggle → eye icon; "Review" had a bare hamburger trailing the label → clipboard-check icon, moved to lead the label like every other control.
[!] experts, crm — table density never picked up §31.3 (their td rules are `.table td` / `.crm-table tbody td`, not `.clients`/`.hs-table`): `11px 16px` / 44px rows → `2px 24px` / 40px. experts rows measured **79px**, crm 47px.
[!] owners — same: bare `thead th` / `.owner-tr td` / `.sub-table-wrap` at `10-11px 14px`, rows 61px → `2px 24px` / 40px.
[!] all 7 — `th.col-check`/`th.col-caret` lost their padding+alignment to higher-specificity td rules, so on index/my-clients/crm the **header checkbox sat 14px left of the body checkboxes**. Added `!important` to width/padding/text-align; checkbox now at x=275 and caret at x=305 on 6 of 7 pages (owners 279.8 — auto table-layout, header and body still aligned).
[!] experts — 3-line name cell (name / title / accounts) blew rows to 79px; title+accounts merged onto one nowrap ellipsised line → 48px. Also removed a hardcoded `style="background:#f5f5f5"` stuck on the Victor Bernard row that read as a frozen hover.
[!] owners — "Clients" cell wrapped to 3 lines once the gutter went to 24px; widened `col.c-clients` 100→130px and set `.clients-a{white-space:nowrap}`.
[!] owners — footer claimed "Showing 4 of 4 account owners" while the tab and the KPI both say 6 → "Showing 4 of 6".
[!] experts — footer claimed "Showing 7 of 7 experts" while the tab says 12 → "Showing 7 of 12".
[!] crm — footer claimed "Showing 7 companies · 16 contacts" but 6 companies render and the banner says 11/26 → "Showing 6 of 11 companies · 16 of 26 contacts".
[!] owners — KPI figures were tinted with raw hex `#a1001f` / `#7a5605` / **`#3B6D11`** (a green that is in no palette) → decoloured; HubSpot colours the delta, never the figure. Same for the five tinted `.kpi-val-*` figures on experts.
[!] my-clients — warm/cream leftovers the restyle missed: `.act-review:hover` at `#f9e9c9`/`#e0c47a` → watch tokens; the Neste avatar at `#F0E6D2`/`#7A5A1F` → `#e6e6e6`/`#141414`.
[!] risk, growth — signal-severity bars used off-palette `#EFB429` / `#E8822E` / `#cbd9b6` → `var(--watch)` / `var(--risk)` / `var(--good)` / `var(--n-200)`.
[!] risk, growth — `.tab-badge` was a 10px radius at **10px** font (below the type scale) → `var(--radius-pill)` / 12px.
[!] owners, experts, crm — saved-view tabs carried a local `border-radius:8px 8px 0 0` overriding §31.5c's 6px → 6px.
[!] risk, growth — list rows sat 13px right of the table pages' checkbox column (`padding: 12px/14px 20px`) → left padding 14px so the checkbox lands at x=275 like the other five.
[x] all 7 — swept 30 page-level `font-weight:600/700` declarations down to 500.
[x] index, crm — control labels normalised ("Filter" → "Filters", "Risk first" → "Sort: Risk first") so the seven read as one component.
[x] judged fine as-is: index's paired risk(red)/growth(green) KPI figures — the hue *is* the axis there and each carries a matching status icon, same logic as the risk/growth banner headlines; risk/growth putting the drill-in chevron on the right rather than a left caret column (their left slot is the account-group toggle — changing it is an IA change, not a restyle); owners' two-line column headers (the sub-questions are content, not decoration); `#f5b8c1` / `#a8ded0` tint borders (same pattern as the system's own `.hs-alert` `#b6d9fb`).


### Record-family consistency

Scope: the 10 record pages (`customers/{customer,overview,overview-rail,analysis,risks,opportunities}.html`,
`owners/owner.html`, `experts/{expert,analysis,feedback}.html`). No file outside that set touched;
`assets/` untouched.

### 1. Weight 600 removed from the record family (FINAL-QA cosmetic gap #5)
- Mechanical pass: every page-local `font-weight:600` (CSS block **and** inline style) rewritten to
  `500` in all ten files. That covers the named offenders — `.resp-av`, `.detail-av`, `.av`,
  `.q-label`, `.resp-score`, `.sev-pill`, `.stag`, `.score-badge` — plus ~30 more per page
  (`.ah-logo`, `.card-title`, `.kpi-val`, `.ro-*`, `.p-status`, `.timeline-*`, `.rbadge`, `.afb-*`,
  `.tl-*`, `.an-*`, `.detail-*`, `.summary-stat .num`, …).
- `.sig-val` (26px hero figure) is the one declaration left at 600, as the "single figure carrying a
  card" exception. Measured: it renders on no page in the set, so the effective count is unchanged.
- Measured after (leaf elements with computed weight >= 600, Playwright, 1680x1050):
  all ten pages = **2** (`.hs-logo`, `.hs-top-badge`, both shell) — identical to every other page in
  the prototype. Before: 110 / 81 / 79 / 63 / 35 / 35 / 33 / 31 / 24.
- Weight 700: none. Each of the ten already carries a page-local `b,strong{font-weight:500}`.

### 2. Underline tabs -> boxed saved-view tabs (FINAL-QA cosmetic gap #3)
- Deleted the page-local underline rules (`.nav-tabs`, `.ntab`, `.ntab.active`, and the
  `.tabs-row` height/padding parts) from all ten files.
- Markup converged onto the system classes: `nav-tabs` -> `tabs`, `ntab` -> `tab`,
  `ntab active` -> `tab is-active`. §6 + §31.5/31.5b/31.5c now style them, unmodified.
- Kept a 3-line page-local shim per file: `.tabs-row` (the flex row + the 1px bottom rule the
  active tab merges into), `.tabs-row .tabs{gap:0}`, `.tabs-row .tab{text-decoration:none}`
  (the record tabs are `<a>`s).
- `owners/owner.html` needed a structural change: its tabs sat inside a page-local `.topbar`,
  where the system rule `.topbar .tabs .tab:first-child` would have promoted "Overview" into a
  20px page title. The tab strip was moved out into its own `.tabs-row` below the back-link row
  (mirroring the other nine record pages) and the local class renamed `.topbar` -> `.rec-topbar`
  so it no longer inherits the system `.topbar` border/min-height.
- Measured parity against the list pages (`my-clients.html`), computed styles:
  idle `48px | rgb(245,245,245) | radius 0 | 400 | 12px 18px | border-top 0`
  active `48px | rgb(255,255,255) | radius 6px | 500 | 12px 18px | border-top 1px #cccccc`
  — byte-identical on all ten record pages. (`experts.html`, not mine, is still 40px/16px.)

### 3. Below-the-fold emptiness on risks / opportunities (gap #11)
Judged unfinished: a 5-row and a 3-row table just stopped, with no bottom edge, above ~550px of
bare plate. Added the list pages' closing chrome — an in-card `.sig-foot` footer (tinted #fafafa,
1px top rule, bled to the card edges, 16px bottom radius) carrying the honest count and a link:
- `risks.html` — "Showing all 5 risk signals for DNA Oyj · 2 high severity · last activity
  2026-05-10" + "Open in Analysis →" (`analysis.html#risks-section`).
- `opportunities.html` — "Showing all 3 opportunity signals for DNA Oyj · 1 high value · last
  activity 2026-05-08" + "Open in Analysis →" (`analysis.html#opportunities-section`).
Both anchors verified to exist. The plate below is still empty — that is honest for a 5-signal and
a 3-signal account; what was missing was an ending, not content.

### Verification
`node shot.js` at 1680x1050 in real Chrome, all ten pages, every PNG read:
`shots/M1-{customer,overview,overview-rail,c-analysis,risks,opportunities,owner,expert,e-analysis,feedback}.png`
(risks/opportunities re-shot after the footer). No horizontal scroll on any of the ten
(`scrollWidth > clientWidth` false), no clipping, no layout regression.
Backups of all ten originals: `scratchpad/m1backup/`.

### Left / notes
- `.sig-val{font-weight:600}` survives as a declaration on `customers/overview.html`,
  `experts/expert.html`, `experts/analysis.html` but matches nothing rendered — safe to drop if
  a later pass wants the set to be literally 500-max.
- No system change needed for either job; nothing added to SYSTEM-REQUESTS.md.


### Set-wide consistency

Cosmetic gaps #3, #6, #7, #8, #9, #10, #12 from `FINAL-QA.md`, plus blocking #5 (job 8).
Verified in real Chrome at 1680×1050 — before/after PNGs in `shots/N1-*.png`, all read.

[x] **#6 weight 700 (job 1)** — `dashboard/crm.html` (3 `<strong>` + 1 `<b>`) and cover
  `index.html` (1 `<strong>`): added `strong, b { font-weight: 600 }` to each page's own style
  block rather than touching `assets/`. Re-measured every leaf element on all 58 pages with a
  Playwright computed-style sweep (`scratchpad/n1w.js`): **0 elements now compute > 600**
  anywhere in the set. At `>= 600` the sweep still finds the expected shell pair
  (`.hs-logo`, `.hs-top-badge`) plus the portfolio pages' own 600s, which are in policy.

[x] **#8 owners eNPS wrap (job 2)** — `dashboard/owners.html`: `col.c-enps` 70px → 88px and
  `.enps-trend { white-space: nowrap }`. "→ stable" no longer wraps in the James Renard row;
  all four rows are single-line and the same height again.

[x] **#7 portfolio-v7 accent stroke (job 3)** — `dashboard/portfolio-v7.html`: dropped the
  2px coloured top stroke from `.sig-growth` / `.sig-nurture` / `.sig-risk` — both cards now
  carry the same `1px var(--n-300)` border as every other card in the set. Status is already
  in the card's own content (tinted icon disc + tinted figure), so nothing was lost.

[x] **#9 customer-table stray rules (job 4)** — `wireframes/customer-table-v1.html`: removed
  the four `<hr class="divider">` full-width hairlines and their rule; the four version
  sections already carry real `h2` headings + a description line, so section spacing went
  32px → 40px and the headings do the separating.

[x] **#12 launch mark (job 5)** — `dashboard/launch-redesign.html` converged onto
  `quick-launch.html`'s mark: `.ql-spark` was a 24px orange rounded square with a filled
  5-point star → 28px `--n-200` circle with the same stroked sparkle path quick-launch uses.
  Same concept, one mark on both pages.

[x] **#10 narrow centred columns (job 6)** — `dashboard/emails-reviews.html` and
  `emails-late-arrivals.html`: `.caption` `text-align: center → left`, `.tabbar`
  `justify-content: center → flex-start`, `.email` `margin: 0 auto → 0`. The tab strip and
  its rule now span the plate and start at the plate's left edge like every other page; the
  600px stays only on the email artefact itself, which is an email measure, not a page frame.
  `dashboard/expert-portal.html`: `.pcontent` `max-width: 900px → none` so the panel uses the
  plate, with a `max-width: 76ch` reading cap moved onto the prose (`.qa-open, .on-text,
  .kk-item-t, .qa-q`) instead of the page.

[x] **#3 two tab components (job 7)** — all four `wireframes/account-view-*.html`
  (`-hybrid`, `-hybrid-kpi-panel`, `-source`, `-topic`) dropped the underline tab
  (32px, transparent, 2px teal bottom border) for the list pages' boxed/filled saved-view tab:
  48px, idle `var(--n-100)`, active white with `1px var(--n-300)` and `6px 6px 0 0`, bottom
  border matched to the surface and `margin-bottom: -1px` so it merges into the rule below.
  `.account-header` went to `align-items: flex-end; padding-bottom: 0` with a 12px bottom
  margin on the title / date-range / spacer so they stay optically centred against the taller
  strip. The set now has one tab component.

[x] **blocking #5 / job 8 — activity-action Progress column widened, done safely.**
  `dashboard/activity-action.html`: the Progress `<col>` was auto-width (`c+='<col>'`) and the
  meter clamped by `max-width: 340px`, rendering ~190px. Every other column in that table is
  already explicitly sized (34+22+200+120+76+118+104 = 674px of 1356px plate), so the column
  model did not need re-cutting — only the one unsized col. Set the Progress col to 660px and
  raised `.pgrid` / `.track` / `.trackc` to `min-width: 560px; max-width: 650px` (the ~650px
  the exploration pages give the same component). Count labels now sit over their own
  segments in both batch rows. Re-checked `scrollWidth > clientWidth` on all 58 pages
  afterwards (`scratchpad/n1chk.js`): **0 pages scroll horizontally.**

Not mine / left open (still live in `FINAL-QA.md`):
- Blocking #2 — the literal `n1` string still renders on `activity-action.html` and
  explorations `-5`, `-6`, `-10`. Touched `activity-action.html` for the column width but did
  not change that `else` branch; the four pages should be fixed together.
- `activity-action.html` row 1's final-state cap is a grey chip with a flag glyph and no
  number (count 0). Legible now that it has room and a divider rule, but it is still a
  different affordance from row 2's numbered cap — a content/logic call, not a restyle.
- `wireframes/customer-table-v1.html` lines ~320/345 carry inline
  `text-transform: uppercase; letter-spacing: .04em` on two "Experiments" sub-headings.
  §21's `!important` neutralises them at render time, so they measure clean, but the inline
  declarations are still in the file.

