fix(#838): buttons in the house themes never lifted or pressed - #865
Merged
Conversation
Both state rules were out-specified by the resting rule and had never applied. On all three ScriptHammer themes, hover and active resolved to the resting `--sh-plate`: buttons did not lift, and they did not press. SPECIFICITY, NOT A TYPO resting chain (0,7,0) hover .btn:hover (0,3,0) active chain-minus-two + :active (0,6,0) `:not()` contributes the specificity of its ARGUMENT, so the five-`:not()` chain on the resting rule scores 7 and both neighbours lost to it. The chain was added by #379 so this block would stop beating the `sh-*` utilities, and it silently disabled the two rules underneath it. Each state now repeats the whole chain, giving a strict ladder 7 < 8 < 9. It is verbose on purpose: doing it by counting rather than by source order means re-ordering this file cannot swap the states back. THE LITERAL BLACK THAT SURVIVED NINE TICKETS The hover rule read `rgb(0 0 0 / 0.3)` — invisible on a dark surface, grey sludge on a saturated one, and exactly what the ink tokens exist to replace. It survived the whole #376/#426 epic because it was never rendered: no screenshot can show a state that does not apply. New `--sh-plate-lift` is built from the same `--sh-ink-*` tokens as `--sh-plate`, just raised further. THE GATE COULD NOT SEE IT EITHER `depth-tokens.spec.ts` read RESTING only — every test in it. Added T5: for each house theme, hover and press a real `.btn` and assert the three states are three different things, plus that none of them uses literal black. It asserts DIFFERENCE rather than exact values, so a legitimate design tweak does not break it while the ladder collapsing does. MUTATION-VERIFIED: sinking the hover selector back to `.btn:hover` (0,3,0) fails with "scripthammer-light: hover must differ from resting". ONE THING THE FIRST DRAFT GOT WRONG. It read the shadow once, straight after `.hover()`. DaisyUI transitions box-shadow, so that catches the animation MID-FLIGHT — measured `7.05px 14.11px -5.26px`, partway between --sh-plate (6/12/-5) and --sh-plate-lift (10/20/-6). A one-shot read is timing-dependent and could land on a value equal to resting and fail for nothing. It polls now. Run three times back to back to confirm: 7 passed, 7 passed, 7 passed. That same truncated one-shot read is also what briefly made it look like the fix had not worked at all — the intermediate value shares its leading offsets with the resting shadow. Confirmed the rule really wins by enumerating the matching CSSOM rules: exactly one `.btn:hover` rule with a box-shadow, and it is ours. Measured after the fix, all three themes: resting != hover != active. lint clean, 4730 vitest, 428 script tests, tsc clean. Closes #838 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
10 tasks
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.
The bug
Buttons on all three ScriptHammer themes never lifted on hover and never pressed on active. Both state rules were out-specified by the resting rule and had never applied — all three states resolved to
--sh-plate.Specificity, not a typo
:not()contributes the specificity of its argument, so the five-:not()chain on the resting rule scores 7 and both neighbours lose to it. The chain was added by #379 so this block would stop beating thesh-*utilities — and it silently disabled the two rules underneath it.Each state now repeats the whole chain, giving a strict ladder 7 < 8 < 9. Verbose on purpose: doing it by counting rather than by source order means re-ordering the file cannot swap the states back.
The literal black that survived nine tickets
The hover rule read
rgb(0 0 0 / 0.3)— invisible on a dark surface, grey sludge on a saturated one, and precisely what the ink tokens exist to replace. It survived the entire #376/#426 epic because it was never rendered: no screenshot can show a state that doesn't apply, and no reviewer can see one.New
--sh-plate-liftis built from the same--sh-ink-*tokens as--sh-plate, just raised further.The gate couldn't see it either
depth-tokens.spec.tsread resting only — every test in it. Added T5: for each house theme, hover and press a real.btn, assert the three states are three different things, and that none uses literal black. It asserts difference rather than exact values, so a legitimate design tweak doesn't break it while the ladder collapsing does.Mutation-verified: sinking the hover selector back to
.btn:hoverfails withscripthammer-light: hover must differ from resting.Two things my first draft got wrong
It read the shadow once, straight after
.hover(). DaisyUI transitionsbox-shadow, so that catches the animation mid-flight — measured7.05px 14.11px -5.26px, partway between--sh-plate(6/12/-5) and--sh-plate-lift(10/20/-6). A one-shot read is timing-dependent and could land equal to resting and fail for nothing. It polls now — three consecutive runs: 7 passed, 7 passed, 7 passed.That same truncated read briefly made it look like the fix hadn't worked, because the intermediate value shares its leading offsets with the resting shadow. I confirmed the rule actually wins by enumerating the matching CSSOM rules — exactly one
.btn:hoverrule carries a box-shadow, and it's ours, resolving tovar(--sh-plate-lift).Verification
Measured after the fix on all three house themes:
resting != hover != active, on every one. Before, all three were byte-identical.lint clean, 4730 vitest tests, 428 script tests,
tsc --noEmitclean.Closes #838 — and this is the named exit condition of epic #426.
🤖 Generated with Claude Code