Highlight the hovered app row on the Updates tab

The row head is the click target that expands a row and already set
cursor:pointer, but nothing changed under the pointer — so a clickable row
looked identical to a static one right up until it opened, and the only visual
state was post-click.

The tint is painted by the row rather than the head. .ov-row's `padding: 0`
loses to .updater-row's `padding: 12px 15px` on equal specificity, so the head
is only 34px tall inside a 60px row; filling the head left a floating band with
13px of untinted row above and below it. Painting the row covers the full
height and picks up its 11px radius for free.

Keyed on `:has(> .ov-row-head:hover)` rather than `.ov-row:hover` so the
highlight tracks what is actually clickable: on an expanded row, drifting into
the detail body stops indicating a click target, because there isn't one there.
The head-level rule stays as the fallback for engines without :has() — it still
marks the row, just inset — and the pair is mutually exclusive so the two tints
never stack. :has() is already relied on elsewhere in the WebUI CSS.

Verified against the running WebUI by driving Chrome over CDP and dispatching a
real mouseMoved, since lp-shot cannot hover: the hovered row goes from
rgba(255,255,255,.035) to .086, its neighbour stays at .035, and the head fill
reads transparent so nothing double-tints. Confirmed visually in the capture
too. ov-row-head is emitted only by renderUpdates(), so no other tab changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
librelad 2026-08-19 21:28:30 +01:00
parent b8c23f0dc9
commit 1b3d68d9f7

View File

@ -213,6 +213,28 @@
.ov-row-head .updater-row-ver { margin-left: auto; }
.ov-row-head .ov-row-actions { margin-left: 12px; display: flex; align-items: center; gap: 8px; }
.ov-row-head:focus-visible { outline: 2px solid rgba(var(--page-updater-rgb), .7); outline-offset: -2px; }
/* Hover feedback. The head is the click target for expanding a row and already
sets cursor:pointer, but nothing changed under the pointer, so a clickable row
looked identical to a static one right up until it opened.
The tint is painted by the ROW, not the head. .ov-row's `padding: 0` loses to
.updater-row's `padding: 12px 15px` on equal specificity, so the head is only
34px tall inside a 60px row filling the head left a floating band with 13px
of untinted row above and below it. Painting the row covers the full height and
picks up its 11px radius for free.
Keyed on the head rather than `.ov-row:hover` so the highlight tracks the thing
that is actually clickable: on an expanded row, drifting into the detail body
stops indicating a click target, because there isn't one there.
The head rule is the fallback for engines without :has() it still marks the
row, just inset. The pair is mutually exclusive so the two tints never stack. */
.ov-row, .ov-row-head { transition: background-color .15s ease; }
.ov-row-head { border-radius: 10px; }
.ov-row-head[aria-expanded="true"] { border-radius: 10px 10px 0 0; }
.ov-row-head:hover { background: rgba(var(--text-rgb), .06); }
.ov-row:has(> .ov-row-head:hover) { background: rgba(var(--text-rgb), .085); }
.ov-row:has(> .ov-row-head:hover) > .ov-row-head { background: transparent; }
@media (prefers-reduced-motion: reduce) {
.ov-row, .ov-row-head { transition: none; }
}
/* Tasks-style app row: icon tile + status pill + Details toggle -------------- */
.ov-row-icon {