You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SPA: elevation hierarchy — stop using one card treatment for stat cards, panels, toolbars and entry panes #651
Part of the SPA look-and-feel pass (design review 2026-09-02). Sibling slices: numeric typesetting, all-caps labels, table layout, dashboard rework, empty states, visual identity.
Problem
Every surface gets the same treatment: .stat, .panel, .toolbar, .entry-pane, .card, .order-panel all carry --r-card: 16px + --shadow-card + hairline (web/src/styles.css ~1052, ~1496, ~1541). A filter bar has the same visual weight as a data panel, and a data panel the same as a floating dialog. The result reads as a generic SaaS card kit and gives the eye no hierarchy.
Proposal
Elevation encodes what floats; radius encodes nesting depth.
Floats (dialogs, the Daily entry sticky action bar, the mobile tab bar): keep shadow.
Panels / stat cards / entry panes: border only, no shadow.
Toolbars (filter bars): inset — --surface-2 fill, no border or a hairline, no shadow, smaller radius.
Radius scale of three steps (e.g. 6 / 10 / 16) by depth: page-level container 16, nested panel 10, controls/chips 6. --r-card stays for the top level; add --r-panel and reuse --r-input.
Heads-up from #654, merged as 396ba233: the stat-card CSS is gone.
.stat-grid, .stat, .stat-value and .stat-label were deleted from web/src/styles.css, because the dashboard was their only renderer and #654 replaced that row with capture-status tiles. Both of your scopes list those selectors, so that part of your work is already done — please re-read your issue body against main before picking it up rather than against the version written on 2026-09-02.
What #654 deliberately did not touch, so it is still yours:
One thing worth knowing before you edit those files: web/src/styles.test.ts gained a guard that walks every rule whose selector reaches a dashboard surface — including a selector list like .unrelated, .capture-tile:hover — and fails on box-shadow, text-transform, transition, animation, or any colour that does not resolve through a var(--token). It is deliberately strict; if your slice needs one of those on a dashboard surface, change the guard in the same commit and say why.
Delivered:box-shadow removed from .card, .panel, .order-panel and .toolbar; .named-picker-listbox re-pointed at --shadow-dialog; --shadow-card retired entirely (no consumer left, both :root declarations deleted); three-step radius scale as tokens (--r-input: 6px, new --r-panel: 10px, --r-card: 16px), no literal radius added; web/src/styles.elevation.test.ts walks the whole stylesheet and pins the shadow allow-list, with the radius scale pinned beside it.
Two things this issue asked for that it did not get, recorded rather than dropped:
"Light + night + all farm palettes checked (screenshots)" — partially met. Before/after screenshots were captured from real rebuilt sim stacks and posted on feat(web): elevation hierarchy and sentence-case labels (#651, #652) #661, but only in light, default palette. Night and the forest / slate / terracotta palettes were not visually checked. What was checked across all four palettes and both modes is the contrast maths, asserted in styles.caps.test.ts via the repo's own contrast() helper, and the --canvas/--surface-2 separation (1.05:1–1.21:1 everywhere), which is what drove the decision to keep the toolbar's hairline border. Filed as SPA: visual check of #651/#652 in night mode and the three non-default farm palettes #664 rather than left as a checked box that nobody ticked.
Also worth recording, because it changes how this issue reads in hindsight: two of the five selectors this issue named did not carry the defect. .stat/.stat-label no longer exist — #654 replaced them with .capture-tile*, which already shipped border-only and sentence-case. .entry-pane already had no shadow. And --shadow-card was rgba(29,21,33,0.04) / rgba(29,21,33,0.05) — 4% and 5% alpha — so removing it is close to imperceptible. The honest summary is that this slice was token hygiene plus groundwork, not a visible change. The verified inventory is in docs/designs/651-652-spa-elevation-and-caps.md.
Activity
mforce commentedon Sep 2, 2026
Heads-up from #654, merged as
396ba233: the stat-card CSS is gone..stat-grid,.stat,.stat-valueand.stat-labelwere deleted fromweb/src/styles.css, because the dashboard was their only renderer and #654 replaced that row with capture-status tiles. Both of your scopes list those selectors, so that part of your work is already done — please re-read your issue body againstmainbefore picking it up rather than against the version written on 2026-09-02.What #654 deliberately did not touch, so it is still yours:
.capture-tile,.capture-more,.meter-stack,.dash-list,.panel-wide) carry a border and--r-card, with nobox-shadowat all, so they already sit on the side of the line your issue argues for;.panel,.cardand.order-panelare untouched and still carry--shadow-card.text-transformrule was added or removed..badgestill uppercases, which is why a no-entry tile readsNO ENTRYon the merged dashboard; that is your slice's call to make.One thing worth knowing before you edit those files:
web/src/styles.test.tsgained a guard that walks every rule whose selector reaches a dashboard surface — including a selector list like.unrelated, .capture-tile:hover— and fails onbox-shadow,text-transform,transition,animation, or any colour that does not resolve through avar(--token). It is deliberately strict; if your slice needs one of those on a dashboard surface, change the guard in the same commit and say why.test(web): catch a shadow painted through filter: drop-shadow() (#651)
test(web): fold case and walk every declaration in the style guards (#…
test(web): a keyframe is not a surface that floats (#651, #652)
docs(web): record that .toolbar is styled ahead of #653, not dead (#651)
feat(web): elevation hierarchy and sentence-case labels (#651, #652) (#…
mforce commentedon Sep 2, 2026
Shipped in #661, merged as
28db4c75.Delivered:
box-shadowremoved from.card, .panel, .order-paneland.toolbar;.named-picker-listboxre-pointed at--shadow-dialog;--shadow-cardretired entirely (no consumer left, both:rootdeclarations deleted); three-step radius scale as tokens (--r-input: 6px, new--r-panel: 10px,--r-card: 16px), no literal radius added;web/src/styles.elevation.test.tswalks the whole stylesheet and pins the shadow allow-list, with the radius scale pinned beside it.Two things this issue asked for that it did not get, recorded rather than dropped:
"Toolbar reads as inset (screenshot before/after in the PR)" — not demonstrable.
.toolbarhas zero call sites in the SPA; nothing applies the class. The rule is styled correctly but renders nowhere, so no before/after screenshot of it exists or can. It is kept deliberately as groundwork for SPA: table layout — provenance column to one line, date-range filters into a bounded toolbar #653, which introduces the filter-bar consumers — see the note on that issue and the comment now carried on the rule itself. Not a follow-up: SPA: table layout — provenance column to one line, date-range filters into a bounded toolbar #653 owns it."Light + night + all farm palettes checked (screenshots)" — partially met. Before/after screenshots were captured from real rebuilt sim stacks and posted on feat(web): elevation hierarchy and sentence-case labels (#651, #652) #661, but only in light, default palette. Night and the forest / slate / terracotta palettes were not visually checked. What was checked across all four palettes and both modes is the contrast maths, asserted in
styles.caps.test.tsvia the repo's owncontrast()helper, and the--canvas/--surface-2separation (1.05:1–1.21:1 everywhere), which is what drove the decision to keep the toolbar's hairline border. Filed as SPA: visual check of #651/#652 in night mode and the three non-default farm palettes #664 rather than left as a checked box that nobody ticked.Also worth recording, because it changes how this issue reads in hindsight: two of the five selectors this issue named did not carry the defect.
.stat/.stat-labelno longer exist — #654 replaced them with.capture-tile*, which already shipped border-only and sentence-case..entry-panealready had no shadow. And--shadow-cardwasrgba(29,21,33,0.04)/rgba(29,21,33,0.05)— 4% and 5% alpha — so removing it is close to imperceptible. The honest summary is that this slice was token hygiene plus groundwork, not a visible change. The verified inventory is indocs/designs/651-652-spa-elevation-and-caps.md.docs(sim): commit the dashboard screenshot, capture the palette matri…
chore(main): release 0.1.0 (#542)