fix(ui): let a classed h3 own its appearance instead of the card-heading rule - #330
Merged
Merged
Conversation
…ing rule
The card-heading rule `.card h3 { font-size: 15px; margin-bottom: 14px;
color: var(--text) }` (specificity 0,1,1) outranked the component class
`.wallet-hero-label` (0,1,0), so all three of that class's declarations
lost. The wallet page's balance caption has therefore always rendered as
an ordinary card heading — computed style before the fix: `15px /
var(--text) / 14px`, while the class asks for `12px / var(--text-mute) /
0` (the prototype writes `<h3 class="muted" style="font-size:12px">` at
line 588). The class's `margin-bottom: 0` — the thing that pulls the big
number up against its caption — never applied either. A whole class
whose every declaration loses is a `class=` that was never honoured.
Fix: guard the generic card-heading rule with `:not([class])`, so a h3
that carries a class keeps its own look and the generic rule serves only
unclassed headings — the same invariant #329 applied to the field-label
rules.
The gate in src/layout_gate.rs grows a third rule (R3) that makes this
shape derivable rather than a one-off: for every `<element class=...>`
site in ui/index.html, the class must not have *every* declaration it
makes be beaten by a rule that names the element type without using the
element's own classes. R3 compares specificity and source order, counts
only rules that really match (markup nesting is tracked — without it a
single `.page-head p` produced 7 false dead classes), and skips `@media`
rules and state rules such as `[hidden]`.
Measured with jsdom over the whole document: the pre-fix tree has exactly
one dead class site in the entire document (`.wallet-hero-label` on
`<h3>`), the fixed tree has zero, and the other 27 `.card h3` headings are
unchanged at `15px / var(--text) / 14px`.
argszero
force-pushed
the
fix/wallet-hero-label-cascade
branch
from
September 30, 2026 02:15
dd084db to
5a8129e
Compare
Owner
Author
|
Self-review (the author is also the committer on this repo, What I re-verified on the pushed head
One note on process, in case a reviewer wonders about the extra file: besides |
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.
Summary
The card-heading rule
.card h3 { font-size: 15px; margin-bottom: 14px; color: var(--text) }(specificity 0,1,1) outranks the component class.wallet-hero-label(0,1,0), so every declaration that class makes loses: the wallet page's balance caption has always rendered as an ordinary card heading — computed style15px / var(--text) / 14px, while the class asks for12px / var(--text-mute) / 0(the prototype writes<h3 class="muted" style="font-size:12px">at line 588). The class'smargin-bottom: 0— the property that pulls the big number up against its caption — never applied either.A class whose every declaration loses is a
class=that was never honoured. So the fix is the same invariant #329 applied to the field-label rules: guard the generic rule with:not([class]), and let a classed<h3>keep its own look.Related Issue
(none)
Changes
ui/css/style.css—.card h3→.card h3:not([class]), with the reason in a commentui/index.html—style.css?v=moves20260924-3→-4(fix(ui): let a classed label own its box instead of the generic field-label rule #329 also touched this stylesheet without moving the token, so this bump covers both)src/layout_gate.rs— a third rule (R3) so the shape is derivable instead of a one-offThe new rule (R3)
For every
<element class=...>site inui/index.html, the class must not have every declaration it makes beaten by a rule that names the element type without using the element's own classes. R3:.page-head pproduced 7 false dead classes;@mediarules and state rules such as[hidden](a rule that only applies at one breakpoint does not make a class dead; a hidden element is not a component-style contest).It is deliberately lexical:
+/~combinators, pseudo-classes, attribute selectors and!importantare not modelled, and the judgement is a necessary condition (all declarations must lose), so it under-reports rather than producing false reds. The pre-existing R1/R2 rules are untouched.Measured with jsdom over the whole document: the pre-fix tree has exactly one dead class site in the entire document —
.wallet-hero-labelon<h3>— and the fixed tree has zero, while the other 27.card h3headings stay15px / var(--text) / 14pxin both trees.Tests
cargo test— 436 passed, 0 failed (baseline 435)cargo fmt --check— cleancargo clippy --all-targets -- -D warnings— clean:not([class])guards,@media, state rules and specificity.Checklist
fix/)