Design pass on the portfolio table (critique: 27/40; P0 was the unmodelled state).
- onboard: a mixed-safe "not modelled yet" nudge above the table — shown whenever
any loaded property lacks a plan (so a part-modelled portfolio still gets it),
wired to Run modelling. Turns a wall of empty cells into a next step without
hiding real data for the rows that ARE modelled.
- harden: one empty-cell vocabulary (EmptyCell) replacing the four divergent
renderings (blank div, slate-300 "—", italic "No cost", "Unknown"); AA-legible
and aria-labelled. Empty EPC bubble is now a labelled placeholder ring, not an
invisible div. Export failures surface an inline error instead of dying silently.
- a11y: the quick-filter clear is no longer a <span role=button> nested inside a
<button> — pill is a container with sibling open/clear buttons.
- distill: exactly one navy CTA at a time — Add properties leads an empty
portfolio, Run modelling leads a populated one; the other demotes to neutral.
- colorize: black tokens in PropertyFilters + the Edit-Columns checkboxes now use
the brand navy/brandmidblue scale (was raw black, drifting off the toolbar).
- cleanup: removed the unreachable delete-property modal (no DELETE endpoint,
onDeleteProperty never called). Real property deletion is its own slice.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses the P1 accessibility cluster from the impeccable critique (WCAG
AA is a stated procurement requirement):
- Focus: one scoped [data-reporting] :focus-visible outline in globals.css
covers every control (was 0 focus styles across 17 buttons); EPC ladder
bands restructured from display:contents (no focus box) to real focusable
grid-row buttons with aria-pressed.
- Contrast: swept content-bearing text-gray-400 (~2.5:1) → text-gray-600
(~7:1) across the surface (43 occurrences) — KPI labels/units, scenario
sublines, data-quality definitions.
- Semantics: ScenarioCombobox gains role=listbox/option, aria-selected,
aria-expanded, aria-haspopup, labelled search; filter toggles get
aria-pressed and their ⓘ tooltip triggers become focusable buttons
(were non-focusable spans); ledger ⓘ likewise.
- States: role=alert on the drill/measures error messages; reduced-motion
disables the loading-skeleton pulse (scoped media query).
- Colour-only cue: compare 'best' cell is now a 'Best' tag, not a 0.5rem
green dot.
tsc clean, 446 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Impeccable critique (25/40) fixes: window.confirm replaced by a
two-step confirm inside the folder menu (states the unfile consequence,
red confirm takes focus, Escape cancels); mutation failures now render
a dismissible notice as well as the live region, and folder-create
errors are no longer swallowed; list-view card menu uses fixed
positioning measured on open so the table's overflow container can't
clip it; Escape closes card/folder menus with focus returned. Also:
search placeholder and rail-count contrast to >=4.5:1, folder-menu and
New-folder hit targets to >=24px, th scope=col, decorative ticks
aria-hidden, rename input regains a visible focus state.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Design references and critique snapshot for the portfolio home redesign;
impeccable design skill added to devcontainer postCreateCommand on trial.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>