Public: anyone can read this; the crew can change it.
Design: the home KPIs are §5 stat tiles, and the kpi* classes leave §5d #4048
Check · Review · Land · Live done — Landed and live in production.
The home page's nine KPI figures are now built with the shared design-system tile, `stat()`, inside a `.stats mb` section. Every link, value, `title`, note and `aria-label` is still there, and the overdue-backup tile still carries `data-tone="attn"`. The type check passes, 87 tests across the ten home/KPI/stat suites pass, and `bun scripts/design-lint.ts` passes; `--update` kept the baseline as it…
shipped production is serving it deploy c564139
The home page's nine KPI figures are now built with the shared design-system tile, stat(), inside a .stats mb section. Every link, value, title, note and aria-label is still there, and the overdue-backup tile still carries data-tone="attn". The type check passes, 87 tests across the ten home/KPI/stat suites pass, and bun scripts/design-lint.ts passes; --update kept the baseline as it was. No before/after screenshots are included: this sandbox has no browser, so they still need taking from the preview, light and dark, desktop and 390 px.
stat() (src/web/ui.ts): to carry the old tiles' content without loss, it now also takes:
- markup for
valueandnote, for the commit hash and "live 5m ago"; noteTitleandaria;tone: "attn", with a matching.stat[data-tone="attn"]border rule incomponents.ts(it mirrors the existing card rule).
The sparkline slot is no longer wrapped in aria-hidden, so each sparkline keeps its role=img and aria-label; an unlabelled one stays decorative. The §5 stat row in docs/DESIGN.md describes these options.
Classes removed: the .kpis, .kpi, .kpi-value and .kpi-note rules are gone from src/web/studio/feed_style.ts and from its §5d bullet.
.kpi-spark stays, unlike the issue asked. A search for the kpi names showed the app settings page's visitors card (appVisitorsView → daySpark) also uses it, and that sparkline is not inside a stat tile. So daySpark still emits class="kpi-spark", while the home sparklines now have no class and take the .stat-spark slot's styling. One visible effect: in that slot (56 × 24 px, top right) the home sparklines draw smaller than before.
Tests:
- The home KPI page test now asserts that none of
kpis,kpi,kpi-value,kpi-noteorkpi-sparkappears in a class on the home page. It also asserts the KPI links (now including/settings/backups) and the sparkline'srole=img/aria-labelare still there. - Some existing tests had to change, because they pinned the old class names:
home-kpi-row,home-kpi-page,home-kpis,home-cache,client-homeandkpi-spark. They now look for thestatnames instead. The CSS assertion inhome-kpi-rownow checks the.stat/.stat-noterules: fixed height, note clamped to two lines, nonowrap.
To try it, sign in as an admin on the preview and open /: the figures row should look like the stat tiles elsewhere. Then compare the app settings page's visitors sparkline, which should look unchanged.
🤖 Generated with Claude Code
Approved. The nine home tiles now go through stat() in a .stats grid, as docs/DESIGN.md §5 asks. Every link, title, aria-label and the attn tone survive. The kpis, kpi, kpi-value and kpi-note rules are gone from §5d. Tests pin the new markup and the absence of the old classes. Keeping .kpi-spark for the settings-page daySpark is right, and the pull says so. The tiles are plain <a> links and the page is server-rendered, so it works with JavaScript off. I could not see the admin-only row in the preview without an admin session, so the layout is read from the CSS, not from a screenshot.
Two things I would do next:
- Check the 160px tiles at 360px and in dark mode. .stat-spark is absolutely positioned at top right (56px wide) over the label row, and the label is only ellipsised at the tile edge. A label like "Shipped per hour" can run under the sparkline. Reserve the spark width on .stat-label when a spark is present, e.g. padding-right on .stat:has(.stat-spark) .stat-label.
- Attach the before/after screenshots (light and dark, desktop and 390px) that the pull says are still missing.
The home page's nine KPI figures are now built with the shared design-system tile,
stat(), inside a.stats mbsection. Every link, value,title, note andaria-labelis still there, and the overdue-backup tile still carriesdata-tone="attn". The type check passes, 87 tests across the ten home/KPI/stat suites pass, andbun scripts/design-lint.tspasses;--updatekept the baseline as it was. No before/after screenshots are included: this sandbox has no browser, so they still need taking from the preview, light and dark, desktop and 390 px.stat()(src/web/ui.ts): to carry the old tiles' content without loss, it now also takes:valueandnote, for the commit hash and "live 5m ago";noteTitleandaria;tone: "attn", with a matching.stat[data-tone="attn"]border rule incomponents.ts(it mirrors the existing card rule).The sparkline slot is no longer wrapped in
aria-hidden, so each sparkline keeps itsrole=imgandaria-label; an unlabelled one stays decorative. The §5 stat row indocs/DESIGN.mddescribes these options.Classes removed: the
.kpis,.kpi,.kpi-valueand.kpi-noterules are gone fromsrc/web/studio/feed_style.tsand from its §5d bullet..kpi-sparkstays, unlike the issue asked. A search for the kpi names showed the app settings page's visitors card (appVisitorsView→daySpark) also uses it, and that sparkline is not inside a stat tile. SodaySparkstill emitsclass="kpi-spark", while the home sparklines now have no class and take the.stat-sparkslot's styling. One visible effect: in that slot (56 × 24 px, top right) the home sparklines draw smaller than before.Tests:
kpis,kpi,kpi-value,kpi-noteorkpi-sparkappears in a class on the home page. It also asserts the KPI links (now including/settings/backups) and the sparkline'srole=img/aria-labelare still there.home-kpi-row,home-kpi-page,home-kpis,home-cache,client-homeandkpi-spark. They now look for thestatnames instead. The CSS assertion inhome-kpi-rownow checks the.stat/.stat-noterules: fixed height, note clamped to two lines, nonowrap.To try it, sign in as an admin on the preview and open
/: the figures row should look like the stat tiles elsewhere. Then compare the app settings page's visitors sparkline, which should look unchanged.🤖 Generated with Claude Code
Closes #3982