feat: type scale, status tokens and one KPI card anatomy (#691 phase 1) - #693
Merged
Conversation
Phase 1 of #691. Operator feedback on the reports screens was that nothing stands out and everything is too small. Measured, the complaint was structural rather than a matter of taste: 107 of 116 `font-size` declarations in app.css were 15px or under, the headline figures were 15px sitting over 10px labels, and eleven distinct `font-weight` values crowded the 500-700 band. Nothing on the page had more emphasis than anything else because nothing could. A type scale ------------ Six steps and three weights, stated once as custom properties on :root and referenced everywhere: --type-title 20/700 the page title --type-kpi 30/700 a figure an operator is meant to READ --type-figure 20/700 the same figure in a 230px client-card track --type-heading 16/600 a section heading --type-card-title 14/600 --type-body 14/400 --type-caption 12/400 All 105 remaining literal `font-size` declarations now reference it — the file has none left. The eleven weights collapse to 400 / 600 / 700: a 640 next to a 660 is not a distinction anybody can see. Figures are proportional now, not monospace. The typewriter texture came off thirteen rules and `font-variant-numeric: tabular-nums` moved to the body, so digits still line up in a column. The three rules that really are code — the env-var name and value, the connector URL — keep their monospace. Status tokens, and red narrowed to act-now ------------------------------------------ --status-alert / --status-watch / --status-ok, each with a background and a border variant, in both themes. Which state a thing is in is still decided by reports_triage.js and carried in the markup as .is-attention / .is-watch / .is-ok; this only says what those look like. Red was doing too many jobs. An update being available and an install being out of date are things to LOOK at, so they are amber now. "Not configured" and "wizard step not done" are states rather than problems — most installs leave most of those off on purpose — so they are neutral. What is left red is what withholds a figure or costs money while it stands. `--danger` survives, narrowed to what it always meant on a button: a destructive action (Clear All, Remove, Archive). Two palettes, kept apart. Colour never carries meaning alone, and did not need fixing to keep that property: every element these paint already ships a word or a glyph beside it (the health badge's text, the filter chip's label, the triage row's tag, the ✓/✗ mark). Verified rather than assumed — no decoration was added. One card anatomy ---------------- Caption, then figure, 4px apart, on all three KPI families. The client card built its cells figure-first, so the two families on the index read in opposite orders and a reader scanning a column had to work out which caption belonged to which number. Same nodes, same parent, same classes — only the order two appendChild calls run in. Also a dark-theme bug --------------------- The amber "watch" badges hard-coded `#7a5a12` as their foreground, a light-only value that was unreadable on a dark surface. It is a token now. Scope ----- A restyle: no layout structure, no DOM hierarchy, no wording changed. Deltas and sparklines are phase 4 and wait on the daily-history schema. Test changes ------------ One, and it is a coverage fix rather than a pin update: the height model in tests/js/reports_index_height.test.js reads box metrics straight out of app.css, and several are now stated as tokens one level up. Its `px()` helper resolves a single `var()` so it keeps reading the stylesheet rather than a literal duplicated into the test. Without it ten of its assertions did not fail — they silently stopped running. Refs #691
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Phase 1 of #691: type scale, semantic status colours, and one KPI card anatomy. A restyle — no layout structure, DOM hierarchy or wording changed. Deltas and sparklines are phase 4 and wait on the daily-history schema.
Operator feedback was "nothing stands out, everything is too small". Measured, that was structural: 107 of 116
font-sizedeclarations were ≤15px, the headline figures were 15px over 10px labels, and elevenfont-weightvalues crowded the 500–700 band.1. Type scale
Six steps, three weights, stated once on
:root:--type-title--type-kpi--type-figure--type-heading--type-card-title--type-body--type-caption105 literal
font-sizedeclarations now reference the scale — none are left in the file:--type-caption-size--type-body-size--type-heading-size--type-title-sizeWeights collapse to 400 / 600 / 700:
500 ×2, 520 ×3, 540 ×1, 550 ×3, 560 ×2, 620 ×2, 640 ×5, 650 ×2, 660 ×4all become 600; the seven 700s stay.The client-card figure is 20px, not 30px — it sits in a 230px grid track four across, and the mockup draws the two steps differently (
.client-figs .val20/700 vs.kpi .value30/700). Flagging because the brief said 30px forreports-client-kpi-value; I followed the mockup as the stated source of truth.Font stack leads with
"Inter", "Noto Sans JP"then the system stack. No@import, no<link>, no CDN — offline behaviour is unchanged; the named faces are used only if the machine already has them.Monospace off figures: removed from 13 rules, replaced by
font-variant-numeric: tabular-numson the body so digits still align. Kept on the 3 rules that really are code —.dashboard-env-name,.dashboard-env-value,.connector-url-row code. (The brief said 5 monospace sites; there were 18, of which 3 are legitimately code.)2. Status tokens, and red narrowed to act-now
--status-alert/--status-watch/--status-okwith-bgand-linevariants, in both themes. Which state a thing is in is still decided byreports_triage.jsand carried as.is-attention/.is-watch/.is-ok; the CSS only says what those look like.Red audit — every previously-red rule, classified:
.reports-triage,.reports-client-card.is-conflicted,.reports-client-card-mark,.report-card-conflict,.report-card-stale,.report-card.is-conflicted,.reports-client-card-fresh.is-stale,.report-card-fresh.is-stale,.report-chip.is-danger,.reports-client-card-item.is-triaged--status-alert.nav-badge-update,.about-update-outdated--status-watch.landing-legacy-notice,.report-card-not-collected,.report-chip.is-warn--status-watch-*.mark-no--muted.wizard-step-pill.not-done--surface-2/--muted.btn-danger(+ hover, focus),.landing-legacy-notice button,.reports-client-archive:hover--dangerTwo palettes now, deliberately apart:
--danger= destructive action,--status-alert= act-now state.Colour never carries meaning alone — and did not need fixing to keep that property. Verified rather than assumed, at each site: the health badge sets
textContentfromdashboard.reports_health_<state>; the filter dot is followed by a label and a count; the triage dot is followed by a text tag chip;statusMarkemits a ✓/✗ glyph; the card's left rule is paired with the status badge in its head. No decoration added — there was no colour-only signal to fix.3. One card anatomy
Caption → figure, 4px apart, on all three KPI families (
.reports-client-kpi,.reports-kpi,.report-card-headline— previously 1px, 3px and 2px gaps).clientKpiCellbuilt its cell figure-first, so the two families on the index read in opposite orders; twoappendChildcalls swap. Same nodes, same parent, same class names.4. Dark theme
Both
:rootand theprefers-color-scheme: darkblock carry the full status set. This also fixes a dark-theme bug: the amber watch badges hard-coded#7a5a12as a foreground — a light-only value, unreadable on a dark surface. Now a token. Swept the file for other hard-coded hex outside the token blocks: the 28 remaining are#fffforegrounds on accent fills, the toast pair, and provider brand colours (Google#4285f4, Meta#1877f2, …), none of them status colours.Test changes: one, and it is a coverage fix
tests/js/reports_index_height.test.jscomputes a height estimate by reading box metrics out ofapp.css. Several are now stated as tokens one level up, which itspx()helper could not parse — and the failure mode was the bad one: ten of its assertions stopped running rather than failing (367 → 357 collected).px()andline()now resolve a singlevar(--token)against:root, which is what "read the metric out of the stylesheet" means once the stylesheet has tokens. One level only, deliberately.No font-size, weight or colour pin needed updating — the sweep found none beyond this. Its height budgets (
TOP_BUDGET900,TOTAL_BUDGET2200) are unchanged and still pass at the larger type, which is the meaningful check that the page did not blow up.Verification
node --test tests/js/*.test.js→tests 367, pass 367, fail 0— same count asorigin/main, so no test silently dropped.pytest tests/ -q→14 failed, 9844 passed, 8 skipped in 409.12s— the same 14 pre-existing failures asorigin/main, name for name. Zero new failures.black --check mureo/ tests/→ 742 files unchanged.ruff check mureo/ tests/→ All checks passed.node --checkon the touched JS → clean.font-sizevalues left, 0 occurrences of#7a5a12,--font-monoon exactly 3 rules.Capture verification is not done here — per the process, the rendered screenshots are taken and reviewed before merge.
Refs #691