artist page: put the load status in the chip row it hands over to

The floating pill worked but sat in the wrong place and at the wrong scale: top
right of the pane, far from the content it describes, 30px tall with 12px text
against a row of 27px chips at 11.5px.

The stat chips are gated on `!page.art_preview` -- they do not exist yet while
the page resolves. So the status simply takes their slot and hands the row over
when they arrive: same container, same `.chip` metrics, with only a spinning
accent ring and a softer label colour of its own. Measured across the handover,
the status chip and the first real chip occupy the identical box (x 230, y 1145,
height 27), and neither the row top nor the play button moves.

That also keeps the property the floating version was chosen for. Nothing
reflows when the status goes, because it is the only thing in the row and the
chips that replace it start at the same origin -- no absolute positioning, no
z-index fight with the sticky .results-head, and no element parked outside the
layout it belongs to.
This commit is contained in:
KeelrLeek committed 2026-07-25 20:20:17 -05:00
1 parent d67df6f55e
commit 8e623e3d8d
1 file changed
+27 -45
+27 -45
View File
@@ -3423,14 +3423,6 @@
single pixel of content. It must NOT live in .fade-flow with the
rest of the body: that carries a transform and sits inside the
clipped .fade-frame, which would both re-anchor and mask it. -->
{#if page.art_preview}
<div class="stage-pill" role="status" aria-live="polite">
<span class="ring" aria-hidden="true"></span>
{page.albums.length || popularTracks.length
? "Refining release details"
: "Loading songs and releases"}
</div>
{/if}
<!-- ROUND 12, "three layers" (the user's own model, mocked and
approved as research/artist-header-scroll/v12-three-layers.html
build 5). Content on top (z 3) → the page background SHEET with
@@ -3752,6 +3744,22 @@
{/each}
{/if}
</div>
{:else}
<!-- The stat chips do not exist yet while the page is
resolving, so the load status simply occupies
their slot and hands the row over when they
arrive. Same container, same chip metrics: the
row's height never changes, so nothing below it
moves — which is what the old in-flow paragraph
above the actions got wrong. -->
<div class="stat-chips">
<span class="chip stage-chip" role="status" aria-live="polite">
<span class="ring" aria-hidden="true"></span>
{page.albums.length || popularTracks.length
? "Refining release details"
: "Loading songs and releases"}
</span>
</div>
{/if}
</div>
{/if}
@@ -6259,61 +6267,35 @@
contain-intrinsic-size: auto 360px;
}
/* Transient load status, pinned to the pane's top-right and out of flow.
It shares the top band with the sticky .results-head (z-index 40), which
is why this has to clear 40 rather than merely clearing .scrollbody's 3 —
at any lower value the bar paints straight over it and the pill is
invisible with no other symptom. */
.stage-pill {
position: absolute;
top: 16px;
right: 20px;
z-index: 41;
display: inline-flex;
align-items: center;
gap: 9px;
height: 30px;
padding: 0 14px;
border-radius: 15px;
background: rgba(14, 14, 16, 0.72);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.4);
backdrop-filter: blur(14px);
color: var(--text-secondary);
font-size: 12px;
font-weight: 500;
white-space: nowrap;
/* Load status wearing the stat chip's own metrics — it stands in for those
chips while they resolve, so it must measure exactly like them or the row
changes height as it hands over. Inherits .chip for everything but the
spinner and the slightly softer label colour. */
.stage-chip {
gap: 8px;
color: rgba(255, 255, 255, 0.62);
pointer-events: none;
animation: stage-pill-in 180ms ease-out;
}
.stage-pill .ring {
.stage-chip .ring {
width: 11px;
height: 11px;
border-radius: 50%;
border: 2px solid var(--accent);
border-right-color: transparent;
animation: stage-pill-spin 0.9s linear infinite;
animation: stage-chip-spin 0.9s linear infinite;
}
@keyframes stage-pill-spin {
@keyframes stage-chip-spin {
to {
transform: rotate(360deg);
}
}
@keyframes stage-pill-in {
from {
opacity: 0;
transform: translateY(-4px);
}
}
/* The spinner is decoration; honour a reduced-motion preference by holding
it still rather than removing the only signal that work is happening. */
@media (prefers-reduced-motion: reduce) {
.stage-pill,
.stage-pill .ring {
.stage-chip .ring {
animation: none;
}
}