fix(design): the keyboard ring of a flush row stays visible (E28)

A list item's ring sat 2 px outside it. On a table row it ran under the
sticky head and past the table's sides; on a Plex playlist show header, flush
in its clipping card, it was cut away and the focus was invisible. A table row
(by its tag), a log line and the Plex show header and episode rows now ring
inside themselves, the show header with its card's corners.

The sticky header's fade-below was drawn at rest, over the first row's top
16 px, hiding the ring's top edge: it now fades in with the first 1rem of
scroll (a scroll-driven animation; no fade where unsupported).
This commit is contained in:
2026-09-26 20:01:04 +02:00
parent 47c12f9405
commit 3e7c79fa69
7 changed files with 116 additions and 6 deletions
+30
View File
@@ -144,6 +144,19 @@
/* B9: the header + fade edge — a crisp band with a 1rem gradient of the colour it sits on, so content
dissolves as it slides under (the reference is DataTable's sticky header). The host is positioned. */
/* A STICKY header's fade (a table head, the server log's toolbar), inside the scroller it sticks in.
It shows only once content has slid under it: at rest it lay over the first row's top 16 px,
dimming it and hiding the top edge of its keyboard ring (E28, seen live). It fades in over the
first 1rem of scroll by a scroll-driven animation; an engine without one draws no fade rather than
a fade over the resting first row. */
@keyframes fade-edge-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@utility fade-below {
&::after {
content: "";
@@ -153,6 +166,14 @@
top: 100%;
height: 1rem;
background: linear-gradient(to bottom, var(--bg), transparent);
opacity: 0;
}
@supports (animation-timeline: scroll()) {
&::after {
animation: fade-edge-in linear both;
animation-timeline: scroll(nearest block);
animation-range: 0 1rem;
}
}
}
@utility fade-below-panel {
@@ -595,6 +616,15 @@ body {
[data-nav-index] [data-nav-open]:focus-visible {
outline-color: transparent;
}
/* An item with no room round it rings inside its own box — outside, the ring ran under a sticky
table head and past the table's sides, or a clipping card cut it away and the focus vanished.
Every table row is such an item, by its tag; any other says so (`navItemAttrs(…, { inset: true })`:
a log line, a row flush in a clipping card). */
:is(tr, [data-nav-inset])[data-nav-index],
:is(tr, [data-nav-inset])[data-nav-index]:focus-visible,
:is(tr, [data-nav-inset])[data-nav-index]:has([data-nav-open]:focus-visible) {
outline-offset: -2px;
}
/* ===== R10 S4 · Selection-paint recipes =====
The ~14 hand-rolled "this is the selected / current / active one" idioms all painted the SAME