fix(ui): a hover that never moved anything, and a selection that vanished under the pointer - #21
Merged
Merged
Conversation
…shed under the pointer
Reviewing the two interface changes that just landed, against the browser rather than
against the source. Three of them were doing nothing, and the same reason runs through all
three: a class cannot outrank an inline style, and Tailwind's `ring` is not a ring.
**`.lift` moved nothing.** It set `transform: translateY(-2px)`, and both cards it is on are
Motion elements — Motion animates by writing `transform` into the inline style, which no
class can beat. Worse, the `transition: transform` beside it *did* apply to the inline
transform Motion rewrites every frame, so the library's entrance animation had a 180 ms lag
chasing itself. Moved to the `translate` property: its own slot, composes with whatever
`transform` holds, and Motion never touches it. Measured after the change —
`translate: 0px -2px` on hover, on a plain button and on a Motion element alike.
**The chosen agent lost its outline under the pointer.** `.lift:hover` sets `box-shadow`,
which beat the selected card's `shadow-[0_0_0_1px_accent]`, so pointing at the selected
agent deselected it visually. The first attempt was `ring-1 ring-accent`, and the browser
said no: Tailwind v4 implements a ring *as* a box-shadow, and the computed style came back
with the same two shadows and no accent anywhere. `outline` is a separate property and
survives both. Confirmed at rest and on hover: `rgb(15, 115, 80) solid 1px` in each.
**`Ticker` re-counted on every change.** Its own doc says a number that changes because the
user filtered the screen should snap, because they are comparing it against what was there a
moment ago — and the code counted from zero every time, which on the analytics range switch
turns a comparison into a wait. Counted once now, and the flag is set on completion rather
than on start so React's development double-invoke does not eat the only run.
Also: `Recent`'s cards were lifting through `whileHover={{ y: -2 }}` — a spring and a rAF
loop per hovered card, to move something two pixels. They use the same `.lift` as everything
else now, which costs nothing while the pointer is elsewhere.
The token test grew `outline-` alongside `text-`, `bg-`, `border-` and `ring-`, since that is
now a colour this interface names.
Full gate on this tree: `cargo fmt --check`, `clippy --workspace --all-targets --features
bundled -D warnings`, 1312 Rust tests, 298 web tests, all 18 browser suites, and 44
screenshots in both schemes with no overflow and contrast AA everywhere.
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.
Review of the two interface changes that just landed (#19, #20), done against the browser rather than against the source. Three things were doing nothing, and the same reason runs through all three: a class cannot outrank an inline style, and Tailwind's
ringis not a ring..liftmoved nothingIt set
transform: translateY(-2px), and both cards it is on are Motion elements. Motion animates by writingtransforminto the inline style, which no class can beat. Worse, thetransition: transformbeside it did apply to the inline transform Motion rewrites every frame — so the library's entrance animation had a 180 ms lag chasing itself.Moved to the
translateproperty: its own slot, composes with whatevertransformholds, and Motion never touches it. Measured after the change:The chosen agent lost its outline under the pointer
.lift:hoversetsbox-shadow, which beat the selected card'sshadow-[0_0_0_1px_accent]— so pointing at the selected agent deselected it visually.The first attempt was
ring-1 ring-accent, and the browser said no: Tailwind v4 implements a ring as a box-shadow, and the computed style came back with the same two shadows and no accent anywhere.outlineis a separate property and survives both:Tickerre-counted on every changeIts own doc says a number that changes because the user filtered the screen should snap, because they are comparing it against what was there a moment ago. The code counted from zero every time, which on the analytics range switch turns a comparison into a wait. Counted once now, with the flag set on completion rather than on start so React's development double-invoke does not eat the only run.
Also
Recent's cards were lifting throughwhileHover={{ y: -2 }}— a spring and a rAF loop per hovered card, to move something two pixels. They use the same.liftas everything else now, which costs nothing while the pointer is elsewhere.The token test grew
outline-alongsidetext-,bg-,border-andring-, since that is now a colour this interface names.Verification
Full gate on this tree:
cargo fmt --check,clippy --workspace --all-targets --features bundled -D warnings, 1312 Rust tests, 298 web tests, all 18 browser suites, and 44 screenshots in both schemes — no overflow, contrast AA everywhere.🤖 Generated with Claude Code