/* Song page — LIFTED from design/prototypes/song-page.html by scripts/lift-song-page.mjs.
   Classes carry an sp- prefix so they sit beside the site's own CSS; sc-chip and the
   footer classes are deliberately NOT prefixed because those are the site's own.
   Never hand-edit and never re-author from a description: change the prototype, re-lift. */
@keyframes dye-drift {from{background-position:0% 50%}to{background-position:100% 50%}}

@keyframes athens-crawl {from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (min-width:761px) {
    }
:root { --sl-bg:#0b0b0c; --sl-ink:#f2f2f0; --sl-muted:rgba(242,242,240,.64); --sl-faint:rgba(242,242,240,.4);
  --sl-line:rgba(255,255,255,.08); --sl-line-strong:rgba(255,255,255,.16); --sl-line-faint:rgba(255,255,255,.05);
  --sl-glass:linear-gradient(180deg,rgba(28,28,31,.55),rgba(18,18,21,.42));
  --sl-glass-shadow:0 18px 40px -20px rgba(0,0,0,.6);
  --sl-r:20px; --sl-r-md:12px; --sl-r-sm:6px; --sl-r-pill:999px;
  --sl-display:"Bricolage Grotesque","Geist",system-ui,sans-serif;
  --sl-body:"Geist",system-ui,sans-serif;
  --sl-mono:"Geist Mono",ui-monospace,monospace;
  
  --song-a:#b98c50; --song-b:#8fbfd9;
  --tie:linear-gradient(90deg,#d4514f,#e0574f 24%,#60a5d2 58%,#c9a35f 88%);
  --ink:#f2f2f0; --line:rgba(255,255,255,.08); --muted:rgba(242,242,240,.64); }
* { margin:0;padding:0;box-sizing:border-box }
html { scroll-behavior:smooth }
body { overflow-x:hidden;background:var(--sl-bg);color:var(--sl-ink);font-family:var(--sl-body);font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased }
body.stagelight a { color:inherit;text-decoration:none }
body.stagelight img { max-width:100%;display:block }
body.stagelight button { font:inherit;color:inherit;background:none;border:0;cursor:pointer }
/* THE 820px CAGE. stagelight.css caps every song page at
   body.stagelight .song-main { width: min(820px, calc(100% - 48px)) } — correct for
   the reading-width prose page the other 697 songs render, wrong for this one, which
   is full-bleed. Measured at a 1440 viewport it left main at 820px and this rail at
   772px, so the whole page below the hero ran at half the width of its own hero.
   The handoff named this exact rule and said find it rather than layer another rule
   on top of it; this releases it for the lifted page only, by a modifier the other
   songs never carry, in a stylesheet only this page loads. */
body.stagelight .song-main.song-main-full { width:100%; max-width:none; margin-top:0 }
/* THE BLACK BAR OVER THE HERO. The site renders an .archive-title header carrying
   a breadcrumb ABOVE the page body — right for a prose page, and on this one it put
   94px of empty black between the nav and a full-bleed hero meant to start under it
   (the prototype has none). Gone, and nothing replaces it in flow: the page uses the
   home page's section trail (.home-nav) instead, which is position:fixed, reserves
   no space, and stays hidden until you are past the hero. */
body.stagelight .sp-rail { width:min(1240px,calc(100% - 48px));margin:0 auto }
body.stagelight section { margin:84px 0 }
/* Alex's round-5 two-line lead: a white statement over a muted continuation.
   The site's .sw-lead has no two-line form, so this is the one part of it that
   is genuinely new rather than a re-declaration. */
/* EACH HALF BALANCES ITS OWN WRAP. On a phone a long lead broke wherever it ran
   out of room — one word alone on the second line, or a name split across it.
   text-wrap:balance evens the lines instead (Alex, 2026-08-05: "anytime we have
   a headline on two lines make sure there isn't a random line break on mobile"). */
body.stagelight .sw-lead b,body.stagelight .sw-lead i { display:block;font-style:normal;text-wrap:balance }

/* ── ONE CONTINUOUS LINE PER LINE ────────────────────────────────────────────
   Alex, 2026-08-06: "make sure that there are no visible breaks on the board. It
   should all be one continuous line on each of those headlines."

   Each line carries its own character count as --sp-fit and sizes itself from
   the rail it has to live in. The rail is the viewport less its gutters — 64px
   above 600px, 32px below — and a few extra pixels come off each so a desktop
   scrollbar (which 100vw counts and the layout does not) cannot turn a headline
   that just fits into one that just overflows.

   0.55 is the display face's widest measured advance per character with
   headroom; the number is derived and defended in build.mjs beside leadLine().
   min() caps it at the design size so a short headline never grows; max() floors
   it at 12px so it never becomes unreadable — and the build marks any line that
   cannot hold ONE line at that floor with .sp-fit-wrap, which lets it wrap at a
   word instead. Wrapping is the fallback; it is not the behaviour.

   max-width HAS TO GO. .sw-lead is capped at 30ch (38ch on this page) and a
   nowrap line simply overflows a box that narrow — on a phone that is sideways
   scroll, which is the one layout fault with no taste in it. The fit maths bounds
   the width instead, which is the same job done by the thing that knows the
   length. */
body.stagelight .sp-lead-fit { max-width:none }
body.stagelight .sp-lead-fit .sp-fit {
  display:block; white-space:nowrap; text-wrap:nowrap;
  font-size:max(12px,min(27px,calc((100vw - 72px) / (var(--sp-fit,20) * 0.55))));
}
/* A LINE THAT WRAPS DOES NOT ALSO SHRINK. Shrinking exists to buy a single line;
   once the build has decided this one cannot have one, taking it to the 12px
   floor as well would be paying the price without getting the thing it buys. It
   goes back to the headline's own size and wraps at a word, exactly as it did
   before any of this — the fallback is "unchanged", not "unchanged and tiny". */
body.stagelight .sp-lead-fit .sp-fit.sp-fit-wrap { white-space:normal;text-wrap:pretty;font-size:inherit }
@media (max-width:600px) {
  body.stagelight .sp-lead-fit .sp-fit {
    font-size:max(12px,min(27px,calc((100vw - 44px) / (var(--sp-fit,20) * 0.55))));
  }
}
body.stagelight .sc-chip { display:inline-flex;align-items:center;gap:8px;height:38px;padding:0 18px;border-radius:var(--sl-r-pill);font-size:13.5px;font-weight:560;white-space:nowrap;transition:transform .18s ease,background .18s ease }
body.stagelight .sc-chip-primary { background:var(--sl-ink);color:#111;box-shadow:0 8px 24px -8px rgba(242,242,240,.35),inset 0 1px 0 rgba(255,255,255,.9);border:0 }
body.stagelight .sc-chip-primary:hover { transform:translateY(-1px);background:#fff }
body.stagelight .sc-chip-glass { background:rgba(255,255,255,.055);border:1px solid var(--sl-line-strong);color:var(--sl-ink) }
body.stagelight .sc-chip-glass:hover { transform:translateY(-1px);background:rgba(255,255,255,.09) }
/* Full-bleed: the hero breaks out of archive-main the same way .home-hero and
   .athens-strip already do. */
body.stagelight .sp-hero { position:relative;overflow:hidden;border-bottom:1px solid var(--sl-line);width:100vw;margin-left:calc(50% - 50vw) }
body.stagelight .sp-hero-ambient { position:absolute;inset:-40px;background-image:var(--cover-url);background-size:cover;background-position:center;filter:blur(90px) saturate(1.05);opacity:.3;transform:scale(1.15) }
body.stagelight .sp-hero-tint { position:absolute;inset:0;background:
  radial-gradient(900px 480px at 18% 0%, color-mix(in srgb,var(--song-a) 24%,transparent), transparent 70%),
  radial-gradient(700px 420px at 88% 18%, color-mix(in srgb,var(--song-b) 13%,transparent), transparent 70%),
  linear-gradient(180deg, rgba(11,11,12,.25), rgba(11,11,12,.86) 78%, var(--sl-bg)) }
body.stagelight .sp-hero-in { position:relative;width:min(1240px,calc(100% - 48px));margin:0 auto;padding:60px 0 44px;display:grid;grid-template-columns:264px minmax(0,1fr);gap:44px;align-items:end }
body.stagelight .sp-cover { border-radius:var(--sl-r-md);overflow:hidden;box-shadow:0 24px 60px rgba(0,0,0,.55),0 0 0 1px var(--sl-line-strong);aspect-ratio:1 }
body.stagelight .sp-cover img { width:100%;height:100%;object-fit:cover }
body.stagelight h1.sp-title { font:700 clamp(44px,7vw,88px)/1.02 var(--sl-display);letter-spacing:-.025em;margin:0 0 6px;padding-bottom:.04em;width:fit-content;background:linear-gradient(97deg,#d97a72 0,#8fb9dd .38em,#c9a35f .78em,var(--sl-ink) 1.35em);-webkit-background-clip:text;background-clip:text;color:transparent }
body.stagelight .sp-meta { color:var(--sl-muted);font-size:15px }
body.stagelight .sp-meta b { color:var(--sl-ink);font-weight:600 }
/* THE STAT STRIP IS ONE HORIZONTAL BAR, five cells divided by hairlines — the
   design on Alex's desk (~/Desktop/song-page.html, 09:48 on 08-01), which is the
   copy he reviews from. The repo prototype was edited at 14:15 the same day into
   four stacked cards and lost the longest-gap cell; that stack is what made the
   hero tall and half-empty. Matching his. */
body.stagelight .sp-stat-strip { display:flex;margin:24px 0 26px;border:1px solid var(--sl-line);border-radius:var(--sl-r-md);background:rgba(255,255,255,.02);overflow:hidden }
body.stagelight .sp-stat { flex:1;padding:15px 20px;border-left:1px solid var(--sl-line-faint) }
body.stagelight .sp-stat:first-child { border-left:0 }
body.stagelight .sp-stat .sp-n { font:600 23px/1.1 var(--sl-display);letter-spacing:-.01em }
body.stagelight .sp-rar { display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--sl-ink);margin-right:9px;vertical-align:.08em }
body.stagelight .sp-stat .sp-l { font:500 11px/1.4 var(--sl-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--sl-faint);margin-top:4px }
body.stagelight .sp-actions { display:flex;gap:12px;align-items:center;flex-wrap:wrap }
body.stagelight .sp-lifeline { margin:56px 0 0 }
body.stagelight .sp-ribbon-views { display:flex;gap:8px;margin-bottom:10px }
body.stagelight .sp-rv { border:1px solid var(--sl-line-strong);border-radius:var(--sl-r-pill);padding:7px 14px;font:560 12px/1 var(--sl-body);color:var(--sl-muted);background:transparent }
body.stagelight .sp-rv.sp-on { background:var(--sl-ink);border-color:var(--sl-ink);color:#111 }
body.stagelight .sp-rv:not(.sp-on):hover { color:var(--sl-ink);border-color:rgba(255,255,255,.3) }
/* The year digits sat 4px off the bottom of their canvas with the next block hard against them. */
body.stagelight .sp-ar-ribbon { position:relative;width:100%;margin-bottom:16px }
body.stagelight .sp-ar-ribbon canvas { width:100%;display:block }
body.stagelight .sp-ar-ribbon-tip { position:absolute;top:0;left:0;transform:translate(-50%,-4px);background:rgba(16,16,18,.92);border:1px solid var(--sl-line-strong);border-radius:8px;padding:7px 11px;font:500 12px/1.5 var(--sl-mono);pointer-events:none;opacity:0;transition:opacity .15s;white-space:nowrap;z-index:3 }
body.stagelight .sp-ar-ribbon-tip b { font-weight:600 }
body.stagelight .sp-ar-ribbon-tip .sp-era-line { color:var(--sl-faint) }
body.stagelight .sp-smart-card { border:1px solid var(--sl-line);border-radius:var(--sl-r-md);padding:0;background:linear-gradient(180deg,rgba(24,24,28,.4),rgba(16,16,20,.3));display:flex;flex-direction:column;align-items:stretch;overflow:hidden;cursor:pointer;transition:border-color .18s,transform .18s;text-align:left }
body.stagelight .sp-smart-card:hover { border-color:var(--sl-line-strong);transform:translateY(-2px) }
body.stagelight .sp-smart-card .sp-txt { min-width:0 }
body.stagelight .sp-smart-card .sp-k { font:600 11px/1.3 var(--sl-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--sl-faint) }
body.stagelight .sp-smart-card .sp-v { font:600 15px/1.3 var(--sl-body);margin-top:3px;color:var(--sl-ink) }
body.stagelight .sp-smart-card .sp-w { color:var(--sl-muted);font-size:12.5px;margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap }
body.stagelight .sp-mini-play { width:34px;height:34px;border-radius:50%;border:1px solid var(--sl-line-strong);display:grid;place-items:center;flex:none;color:var(--sl-ink) }
body.stagelight .sp-smart-card:hover .sp-mini-play { background:var(--sl-ink);color:#111;border-color:var(--sl-ink) }
/* THE GHOST LAYERS OVERHANG ON PURPOSE AND MUST BE CLIPPED SIDEWAYS. The scrawl
   is rotated and scaled past its box, and the hero ambient is inset:-40px with
   scale(1.15) — on a 375px phone those boxes measure 394px and 465px, which put
   4px of sideways scroll on every page that has them. Latent until 2026-08-06:
   only one page carried a scrawl, and the phone-scroll gate sampled pages that
   didn't; 159 lyric pages surfaced it at once. overflow-x:clip (never hidden —
   hidden makes a scroll container and forces overflow-y to auto) cuts only the
   horizontal overhang; card hover lift and shadows travel vertically, untouched. */
body.stagelight .sp-bento-region { position:relative;padding:26px 0 8px;overflow-x:clip }
body.stagelight .sp-hero { overflow-x:clip }
/* THE GHOST LYRIC FIELD behind the three bento cards.
   It rendered as two opaque white walls of handwriting stacked on each other. Two
   reasons, both omissions in the lift: this block never carried a COLOUR, so the
   text inherited --sl-ink at full strength where the prototype sets
   rgba(242,242,240,.075); and .sp-scrawl-clear — which initSongScrawl creates in the
   DOM — had no rule anywhere in this stylesheet, so the second copy laid itself out
   in normal flow, at full opacity, over the first.
   The two layers are the point (Alex, commit 7af08c2: "blurred to clear"): a blurred
   field behind, a sharp copy masked in at the bottom so the words resolve as they
   fall. Both are ghosts, and neither is ever read. */
body.stagelight .sp-scrawl,
body.stagelight .sp-scrawl-clear {
  position:absolute; inset:-40px 0 -20px; z-index:0;
  pointer-events:none; user-select:none; overflow:hidden;
  font-family:"PanicHand",cursive; text-transform:uppercase; letter-spacing:.03em;
  color:rgba(242,242,240,.055);
  transform:rotate(-1.4deg) scale(1.04); transform-origin:50% 50%;
}
body.stagelight .sp-scrawl { filter:blur(2.5px); }
/* The sharp copy fades in over the bottom third — the same field, coming into focus. */
body.stagelight .sp-scrawl-clear {
  -webkit-mask-image:linear-gradient(180deg,transparent 55%,#000 100%);
  mask-image:linear-gradient(180deg,transparent 55%,#000 100%);
}
body.stagelight .sp-scrawl .sp-row,
body.stagelight .sp-scrawl-clear .sp-row { display:block; font-size:26px; line-height:1.12; }
/* COUNT-DRIVEN. Fixed at repeat(3,1fr), a song with one card sat in a
   three-column grid with two holes — and most of the catalog has one card, not
   three. The build sets --sp-bento to however many it actually emitted. */
body.stagelight .sp-bento-grid { position:relative;z-index:1;display:grid;grid-template-columns:repeat(var(--sp-bento,3),minmax(0,1fr));gap:16px }
/* ── ONE HEIGHT, WHATEVER THE COUNT ──────────────────────────────────────────
   Alex, 2026-08-07: "should probably expand the height of the cards and width
   so they all look the same whether 2 up or three right? maybe same height but
   different width."

   THE WIDTH WAS ALREADY RIGHT — MEASURED. repeat(var(--sp-bento),1fr) over the
   region's own width means the row has always filled the rail: three cards come
   out 448 apiece at a 1440 viewport, two come out 680, one comes out 1376. What
   was wrong was the HEIGHT, and badly. Sampled across the catalogue at 1440, a
   three-card row ran 237-427px while a two-card row ran 120-298 and a one-card
   row ran 111-183. The reason is the same thing that makes the widths differ:
   a lyric line inside a 448px card wraps and inside a 680px one does not, so
   the fewer the cards, the shorter the band. A 144px strip under a 362px page
   is what "the rail looks short" was.

   460 IS NOT A ROUND NUMBER, ON PURPOSE. It is what Space Wrangler — the page
   this row is reviewed on — already measures, so the three-card case Alex has
   signed off does not move by a pixel; every shorter case rises to meet it.

   RE-DERIVED AT 460 ON 2026-08-07, by measuring all 698 song pages at 1440 with
   the floor removed — not by scaling the old figures. The numbers that used to
   sit here (87 of 90, 435, 173) were the 362-era counts from the four-line
   cards and were wrong in both directions once Lyrics and Origin went to six
   lines:

     3-card   83 pages — 80 land exactly on 460,  3 grow past it, tallest 557
     2-card  424 pages — all land on 460, tallest natural height 395
     1-card  168 pages — all land on 460, tallest natural height 144

   Lyrics is the driver, which is why the wider layouts never reach the floor on
   their own: the same six source lines that wrap to 460 inside a 448px three-up
   card fit in far less inside a 680px or 1376px one. Chords measures 144 and
   Origin 292.

   THE THREE THAT DON'T STILL GROW, AND THEY ARE NOT THE OLD THREE.
   bowlegged-woman (524), one-arm-steve (557) and rock (492) carry lyrics that
   wrap far enough to need the extra room. you-got-yours used to be on this list
   and no longer is. This is a floor and not a fixed height because the
   alternative is cropping somebody's words, and the lyric block is deliberately
   built so that nothing here ever crops.

   ONLY WHERE THERE IS A ROW TO EVEN OUT. Below 901px the grid is already one
   column (see the max-width:900px block), so "two up or three" does not exist
   down there and the stacked floor below is the one that applies. */
body.stagelight .sp-bento-region .sp-bento-card { min-height:330px }
@media (min-width:901px) {
  /* 460 because that is what six lines measures in the narrowest (3-up) card —
     the floor follows the content, so every row agrees whatever it holds. */
  body.stagelight .sp-bento-region .sp-bento-card { min-height:460px }
}
/* A chords card with no chart of its own: the card is a link with a face on it,
   not a lesson, so it carries no diagrams and says so by being quieter. */
body.stagelight .sp-bento-card.sp-bc-ghost .sp-bc-name { opacity:.92 }
body.stagelight .sp-bento-card { display:flex;flex-direction:column;align-items:stretch;position:relative;text-align:left;padding:26px;color:var(--sl-ink);background:linear-gradient(180deg,rgba(24,24,28,.4),rgba(16,16,20,.3));-webkit-backdrop-filter:blur(9px) saturate(1.3);backdrop-filter:blur(9px) saturate(1.3);border:1px solid var(--sl-line);border-radius:var(--sl-r);box-shadow:var(--sl-glass-shadow);transition:transform .18s ease,border-color .18s ease }
body.stagelight .sp-bento-card:hover { transform:translateY(-2px);border-color:var(--sl-line-strong) }
body.stagelight .sp-bc-open { position:absolute;top:20px;right:20px;z-index:2;width:34px;height:34px;display:grid;place-items:center;border:1px solid var(--sl-line-strong);border-radius:10px;color:var(--sl-muted);transition:border-color .2s,color .2s,background .2s }
body.stagelight .sp-bento-card:hover .sp-bc-open { border-color:var(--sl-ink);color:var(--sl-ink);background:rgba(255,255,255,.06) }
body.stagelight .sp-bc-name { display:block;font-family:var(--sl-display);font-weight:640;font-size:21px;letter-spacing:-.005em }
body.stagelight .sp-bc-fact { display:flex;justify-content:space-between;gap:12px;align-items:baseline;font-family:var(--sl-mono);font-size:12px;color:var(--sl-faint);margin-top:auto;padding-top:14px;border-top:1px solid var(--sl-line-faint) }
/* ── SIX LINES: FOUR IN INK, TWO WALKING AWAY ────────────────────────────────
   Alex, 2026-08-06: "The bottom of the lyrics shouldn't clip it should just fade
   out ... two show up at the top and two at the bottom." It was four lines then;
   he asked for six on the 7th (see the origin block below, which moved with it).
   The two that walk away are still two — lines 5 and 6, addressed by :nth-child.

   THE FADE IS PER LINE, AND THAT IS THE WHOLE FIX. It used to be one gradient
   over the last text node of a block built with <br>, so the only thing CSS
   could address was the block — and the block's own bottom edge is where the
   slicing happened. Each line is its own box now: line 3 drops to the muted ink,
   line 4 runs a gradient from a third-strength muted to fully transparent inside
   its own box, and there is padding under it so no descender ever meets an edge.
   NOTHING HERE CROPS. No overflow, no max-height, no mask on the container — a
   line disappears because it stops being painted, not because something cuts it.
   The 130% stop is deliberate: the gradient reaches transparent BELOW the text
   box, so the last line is still faintly legible rather than half-gone, which is
   what "fade out" means and what "clip" did not. */
/* ── ONE GHOST, READ BY BOTH CARDS ───────────────────────────────────────────
   Alex, 2026-08-07: "Why is the ghosted text so far down on the song origin part
   and different color and font size vs. the one on the lyrics? Should look
   similar."

   He was right about two of the three, and the third is worth saying plainly
   because it is the reason the other two went unnoticed. MEASURED on
   /song/space-wrangler/ at 1440 before this change: the type was already
   identical — 18.5px on 32.375px of leading, Bricolage 400, both cards. What
   differed was WHERE the block sat (80px down the lyric card, 178px down the
   origin one, because the origin was pushed to the foot with margin-top:auto)
   and WHAT COLOUR it was (the lyric card opens at full ink and only ghosts its
   last two lines; the origin card was one gradient that started already muted
   and began fading 40% in, which is halfway through line two). Lighter type,
   further down, fading sooner — that reads as smaller even when it is not.

   THE FIX IS THAT THERE IS NOW ONE SET OF NUMBERS AND BOTH CARDS READ IT.
   Two passes authored these separately and they drifted; a shared token cannot
   drift. The lyric card addresses its lines with :nth-child because it always
   has exactly as many as the build emits — six since 2026-08-07. The origin card
   is one text block, so it reproduces the same steps with a gradient whose stops
   are in ABSOLUTE LINE HEIGHTS rather than percentages — 4 lines of ink, 1
   muted, then the fade — which means a quote of any length gets the same
   treatment its lines would get in the lyric card, and a two-line quote is
   simply two lines of ink rather than a block with a fade squeezed into it. */
body.stagelight {
  --sp-ghost-size:18.5px;
  --sp-ghost-lead:1.75;
  --sp-ghost-line:calc(var(--sp-ghost-size) * var(--sp-ghost-lead));
  --sp-ghost-tail:color-mix(in srgb,var(--sl-muted) 55%,transparent);
}
body.stagelight .sp-lyric-lines { margin:20px 0 22px;padding-bottom:6px;font-family:var(--sl-display);font-size:var(--sp-ghost-size);line-height:var(--sp-ghost-lead);font-weight:400;color:var(--sl-ink) }
body.stagelight .sp-lyric-lines .sp-ly { display:block }
body.stagelight .sp-lyric-lines .sp-ly:nth-child(5) { color:var(--sl-muted) }
body.stagelight .sp-lyric-lines .sp-ly:nth-child(6) {
  background:linear-gradient(180deg,var(--sp-ghost-tail) 0%,transparent 130%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
body.stagelight .sp-chord-stage { margin:22px 0 24px;display:flex;flex-direction:column;gap:16px }
body.stagelight .sp-chord-loop { display:flex;align-items:center;gap:10px;flex-wrap:wrap }
body.stagelight .sp-chord-pill { position:relative;font:600 15px/1 var(--sl-mono);padding:11px 16px;border-radius:10px;border:1px solid var(--sl-line-strong);background:rgba(0,0,0,.32) }
body.stagelight .sp-chord-pill.sp-hot { border-color:rgba(242,242,240,.4);box-shadow:0 0 0 1px rgba(242,242,240,.08),0 6px 18px -8px rgba(242,242,240,.25) }
body.stagelight .sp-chord-x { font:500 12px/1 var(--sl-mono);color:var(--sl-faint) }
body.stagelight .sp-chord-lbl { font:500 10px/1 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--sl-faint);min-width:52px }
body.stagelight .sp-frets { display:flex;gap:12px;margin-top:2px;flex-wrap:wrap }
body.stagelight .sp-fret { display:flex;flex-direction:column;align-items:center;gap:6px }
body.stagelight .sp-fret svg { display:block }
body.stagelight .sp-fret em { font:500 11px/1 var(--sl-mono);font-style:normal;color:var(--sl-muted) }

/* ── THE NECK ────────────────────────────────────────────────────────────────
   Six strings drawn in the same hand as the hub's arrows: currentColor ink over
   a wider translucent pressure stroke, round caps, fill:none, and
   vector-effect:non-scaling-stroke so the weight is a property of the pen and
   not of the box. Authored at 70x78 and never scaled — the same rule that stops
   the PanicHand arrows from growing three different nibs.

   THE VIBRATION IS A HAIRLINE, ON PURPOSE. Each string leans a fraction of a
   pixel and back, staggered off --sp-str so the six do not move as one plank.
   A guitar string at rest that you can SEE moving is a cartoon; the point is
   that the card is not quite still. The dots arrive after the strings have
   settled, scaling up from nothing.

   NO LETTER ANYWHERE. There is deliberately no label rule for this drawing —
   see the note in build.mjs. We hold no chord data, so nothing here is allowed
   to name a chord. */
/* ── IT FILLS THE CARD, AND IT IS BEHIND THE CARD ────────────────────────────
   Alex, 2026-08-06: "Make the chords graphic full width and a big ghosted turn
   it to the right it should fill the container area and be ghosted toward the
   bottom just to imply it is back there."

   Four things, in his order. FULL WIDTH: the layer is inset past the card's own
   padding on both sides so the strings run the whole face. BIG: no width or
   height on the <svg> any more — it takes the layer, and the drawing scales with
   it. TURNED TO THE RIGHT: 7 degrees clockwise, enough to read as tilted and not
   enough to read as broken; scaled 1.18 so the corners the rotation opens up
   stay covered. GHOSTED TOWARD THE BOTTOM: the mask runs the other way from
   every other ghost on this page — strongest at the top where the drawing is
   nearly solid, quietest at the foot — which is what "imply it is back there"
   asks for, a thing receding rather than a thing fading in.

   THE MASK NO LONGER REACHES ZERO (2026-08-07). Alex: "this needs to be much
   bigger. Fill the space a lot more." Measured on the built card by shooting it
   twice, once with the layer hidden, and diffing: the tilted drawing PAINTED
   241 of the card's 362px — the strings ran the full height, and the mask
   rubbed out the bottom third before it got there, which is the dead space he
   was looking at. The flat one had the same fault turned on its side: 444 of a
   680px card, the right 35% masked away. Ending both gradients at .4 instead of
   at transparent keeps the quiet end quiet and stops it disappearing, so the
   drawing reads as the card's own texture rather than as an illustration parked
   in the middle of it. Nothing got louder — the strong end is untouched.

   THE PEN DOES NOT GET FATTER. vector-effect:non-scaling-stroke is on the ink
   below, so a drawing authored at 70px wide and painted at 320px still has 1.5px
   strings. That is the same rule that keeps the hub's arrows to one nib, and it
   is the reason this could be blown up at all without redrawing it.

   THE CARD CLIPS IT. .sp-bc-neck takes overflow:hidden — the rotated box
   overhangs the rounded corners, and unclipped it would put a diagonal of
   hairlines across the page and (on a phone) sideways scroll with it. */
body.stagelight .sp-bc-neck { overflow:hidden }
body.stagelight .sp-neck {
  position:absolute; inset:0 -6% -4%; z-index:0;
  pointer-events:none; user-select:none;
  color:var(--sl-ink); opacity:.5;
  transform:rotate(7deg) scale(1.18); transform-origin:50% 60%;
  -webkit-mask-image:linear-gradient(180deg,#000 0%,rgba(0,0,0,.72) 55%,rgba(0,0,0,.4) 100%);
          mask-image:linear-gradient(180deg,#000 0%,rgba(0,0,0,.72) 55%,rgba(0,0,0,.4) 100%);
}
body.stagelight .sp-neck svg { display:block;width:100%;height:100%;overflow:visible }
/* Everything the card actually says sits in front of the drawing. NAMED, not
   `> :not(.sp-neck)` — that blanket form also caught .sp-bc-open, whose whole
   layout is position:absolute in the top-right corner, and turned it back into
   an in-flow box that shoved the word "Chords" sideways and down. A positioned
   backdrop needs the content lifted over it; it does not need the content's own
   positioning rewritten. */
body.stagelight .sp-bc-neck .sp-bc-name,
body.stagelight .sp-bc-neck .sp-chord-stage,
body.stagelight .sp-bc-neck .sp-bc-fact { position:relative;z-index:1 }
body.stagelight .sp-fretline,
body.stagelight .sp-string {
  fill:none;stroke:currentColor;stroke-linecap:round;vector-effect:non-scaling-stroke;
}
body.stagelight .sp-fretline { stroke-width:1.1;opacity:.2 }
body.stagelight .sp-fretline.is-nut { stroke-width:2.4;opacity:.5 }
body.stagelight .sp-string {
  stroke-width:1.5;opacity:.38;
  transform-box:fill-box;transform-origin:50% 50%;
}
/* ── AT REST, ONLY WHAT A HAND IS ACTUALLY HOLDING MOVES ─────────────────────
   Alex, 2026-08-07: "let that run once and then vibrate on the pressed down
   strings or something amazing like that".

   THREE THINGS CHANGED HERE, AND EACH ONE IS THE SAME SENTENCE.

   1. ONLY THE STOPPED STRINGS. It used to be all six, from load, forever. An
      open string with nobody's finger on it is not being vibratoed; it is just
      sitting there. [data-at] is the build's mark for "a finger is on this one"
      — see the note in build.mjs — so the selector says exactly what the rule
      means and a neck whose fingering changes needs no edit here. The string
      the phrase BENDS carries [data-bend] instead, deliberately: it is free,
      the phrase lets it go at the end, and a released string is as still as any
      other open one. Widening this selector to [data-at],[data-bend] would put
      a shimmer on a string nobody is touching.

   2. THE FINGERTIPS COME WITH THEM. Vibrato IS the finger moving; a string that
      shivers under a motionless dot is the thing Alex objected to on 8/7 and it
      would be worse here, not better, because now there is a reason to look.
      Same keyframe offsets, same duration, no stagger — so a dot cannot come
      off its string by a fraction of a frame. THE STAGGER'S REMOVAL IS THE
      POINT, not a simplification: --sp-str delays used to fan the six strings
      out so they did not move as one plank, which is right for six idle wires
      and wrong for one hand holding one chord, which shakes in time with itself.

   3. IT ONLY STARTS AFTER THE PHRASE. .is-rest is added by initNeckPhrase when
      the five seconds are up. Before that the neck is dead still, which is what
      the card looks like above the fold anyway, and if the script never runs at
      all — no IntersectionObserver, a module that failed to load, a reader who
      asked for reduced motion — the drawing simply stays as authored. Every one
      of those is a legitimate rendering of this card rather than a broken one.

   THE AMPLITUDE IS THE ONE NUMBER THAT IS NOT IN STRING-SPACINGS, and the note
   under the old keyframes below explains why: transform is the one property
   vector-effect cannot hold constant, so these are screen pixels wearing user
   units, and each composition needs its own figure to land on the same hairline.
   Both are unchanged from the values reviewed on 8/7. */
body.stagelight .sp-neck svg.is-rest .sp-string[data-at],
body.stagelight .sp-neck svg.is-rest .sp-chord-dot {
  animation:sp-rest-tilt 3.4s ease-in-out infinite;
}
body.stagelight .sp-neck-flat svg.is-rest .sp-string[data-at],
body.stagelight .sp-neck-flat svg.is-rest .sp-chord-dot {
  animation-name:sp-rest-flat;
}
/* --sp-rest IS SET BY THE SCRIPT, per card, from a measurement of this drawing
   at the size this card actually gave it — see the long note in ribbon.mjs. It
   is the ONE figure here that cannot be authored, because a transform inside an
   SVG is in user units and the drawing is scaled to whatever the card is wide:
   the same keyframe painted 1.02px on a three-card page and 2.03px on a page
   whose chords card runs the full rail. The fallbacks are the values reviewed
   on 8/7, which are right for the tilted card they were tuned on and are only
   ever reached if the measurement fails. The shape is a swing to +1 and back
   through -0.58, so travel is 1.58 amplitudes — the script divides by that. */
@keyframes sp-rest-tilt {
  0%,100% { transform:translateX(0) }
  46%     { transform:translateX(var(--sp-rest,.115px)) }
  72%     { transform:translateX(calc(var(--sp-rest,.115px) * -.58)) }
}
@keyframes sp-rest-flat {
  0%,100% { transform:translateY(0) }
  46%     { transform:translateY(var(--sp-rest,.132px)) }
  72%     { transform:translateY(calc(var(--sp-rest,.132px) * -.58)) }
}
/* ── WHY THE RESTING FIGURES ARE THE SIZE THEY ARE ───────────────────────────
   Kept from 2026-08-07, because it is the reason the two keyframe blocks above
   carry different numbers for the same motion, and that looks like a mistake to
   anybody who has not read this.

   THE TRANSLATE IS IN SVG USER UNITS, and when this drawing stopped being a
   70px illustration and became a card-width backdrop the box grew about 5.3x,
   so a swing authored as "a fraction of a pixel" started painting at five whole
   ones. transform is the one property vector-effect cannot hold constant, so it
   scaled when the pen did not. At five pixels the string visibly slid out from
   under the fingertip holding it — a thing a guitar does not do.

   Both figures are set so the ON-SCREEN travel is about one pixel at the size
   this actually renders, and they differ because the flat neck is authored 160
   wide against the tilted one's 70: in a card of the same width its unit is
   roughly 2.1x smaller, so the number has to be bigger to land in the same
   place. A pixel of travel is the only thing being held equal.

   WHAT CHANGED ON 2026-08-07 (evening). The claim used to be "and the dots stay
   exactly where they are". That was right for six idle strings and is wrong now
   that a hand is holding three of them — see the rest block above. The dots move
   WITH their strings, and qa-visual measures the gap between them rather than
   the dots against zero. */
/* ── A FINGERTIP IS A STROKE NOW, NOT A FILL ─────────────────────────────────
   The drawing stretches to whatever the card is (preserveAspectRatio="none" —
   the reasoning is in build.mjs), and a filled circle in a stretched box is an
   ellipse. A zero-length path with a round cap paints a perfect disc of the
   stroke's own width, and vector-effect:non-scaling-stroke fixes that width in
   SCREEN pixels — so this is the one figure in the drawing that is authored in
   px rather than in the box's own units, and it has to be.

   THE SIZES ARE HALF A STRING SPACING, which is what the old radii worked out
   to (1.15 against a 4.4 gap, 2.4 against 10.4) and what a fingertip looks like
   on a neck. The two compositions need different numbers because their strings
   land at different distances apart on screen: the flat neck spreads six
   strings down the card's height, about 58px apart, and the tilted one spreads
   them across its width at about 67px before the layer's own 1.18 scale carries
   it to 79px on screen.

   .42, NOT .86, unchanged from 2026-08-06: at full strength these read as grey
   blobs sitting ON the card rather than as part of a drawing behind it. */
body.stagelight .sp-neck { --sp-dot-w:34px }
body.stagelight .sp-neck-flat { --sp-dot-w:29px }
body.stagelight .sp-chord-dot {
  fill:none;stroke:currentColor;stroke-width:var(--sp-dot-w,29px);stroke-linecap:round;
  vector-effect:non-scaling-stroke;opacity:.42;
  animation:sp-dot-in .5s cubic-bezier(.22,1,.36,1) backwards;
  animation-delay:calc(.55s + var(--sp-dot) * .12s);
}
/* sp-string-hum and sp-string-hum-flat were deleted on 2026-08-07 along with the
   rule that ran them on all six strings from load. Their amplitudes live on in
   sp-rest-tilt and sp-rest-flat above, unchanged; what went is the always-on
   part and the --sp-str stagger. Nothing references them. */
/* FADE, NOT SCALE. The dots used to scale up from nothing on a fill-box origin,
   which worked because a circle's fill box has area. A zero-length path's fill
   box has none, so the same scale is undefined in both axes — the identical
   reason the barre arrived by opacity while it existed. They now do too, and
   they land at the same moment they always did. */
@keyframes sp-dot-in {
  from { opacity:0 }
  to   { opacity:.42 }
}
/* .sp-chord-barre, sp-barre-in and their reduced-motion override were deleted on
   2026-08-07. Alex: "Also the capo doesn't work." A barre drawn as one stroke is
   correct chord-diagram notation, but this drawing is a neck blown up to the
   width of a card and the stroke scaled with it — a uniform 16px bar across
   every string, hard against the nut. That is a capo, and the site holds no capo
   datum for any song. The reasoning, and what the 41 affected pages draw now,
   is in build.mjs where the element used to be built. Nothing references these. */
/* ── LAID FLAT: THE NECK ON A CARD WITH NO ORIGIN WORDS ──────────────────────
   Alex, 2026-08-07: "stretch them out and only show mostly the strings there."

   No rotation and no upscale — the drawing is authored flat, so it needs
   neither. It sits centred rather than pinned to the foot, and it quietens to
   the RIGHT instead of downward: a neck running off the edge of the card reads
   as stretched out, where a downward fade on a horizontal drawing just dims the
   low strings. Quieter than the tilted one on purpose (.5 -> .42) — this is the
   version that appears beside a card with nothing to say, and it should feel
   like grain in the paper rather than a second diagram competing with it. Like
   the tilted mask, it stops at .42 rather than at transparent; the measurement
   and the reason are in the note up there. */
body.stagelight .sp-neck-flat {
  inset:0 -6%; opacity:.42;
  transform:none;
  -webkit-mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,.75) 55%,rgba(0,0,0,.42) 100%);
          mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,.75) 55%,rgba(0,0,0,.42) 100%);
}
/* THE FLAT NECK'S AXIS OVERRIDE now lives with the rest block above, because the
   two selectors are the same weight and it is the ORDER that decides them: the
   flat card carries both .sp-neck and .sp-neck-flat, so both rules match it and
   the later one wins. That is written down rather than relied on quietly — it is
   exactly the kind of accident that stops being true the next time somebody
   moves a block. A string lying left-to-right has to shiver up and down or it
   slides along its own length and nothing appears to move at all. */
/* STATIC, NOT ABSENT. The house pattern for reduced motion is to force the
   resting end state and kill the animation — never to hide the content. A
   reader who asked for stillness still gets the drawing.

   BELT AND BRACES SINCE 2026-08-07. initNeckPhrase reads the same media query
   and returns before it starts anything, so under reduced motion there is no
   phrase, .is-rest is never added, and none of these rules has anything to
   switch off. They stay because the class could arrive by some other road one
   day, and because a stylesheet that only works if a script agrees with it is
   not a guarantee. */
@media (prefers-reduced-motion:reduce) {
  body.stagelight .sp-string,
  body.stagelight .sp-neck svg.is-rest .sp-string[data-at],
  body.stagelight .sp-neck-flat svg.is-rest .sp-string[data-at] { animation:none;transform:none;opacity:.38 }
  body.stagelight .sp-chord-dot,
  body.stagelight .sp-neck svg.is-rest .sp-chord-dot,
  body.stagelight .sp-neck-flat svg.is-rest .sp-chord-dot { animation:none;transform:none;opacity:.42 }
}
/* The card holds the drawing at the bottom, above the FULL CHART rule, the way
   the origin quote does. */
body.stagelight .sp-bc-neck .sp-chord-stage { margin-top:auto }
/* ── THE ORIGIN CARD SETS ITS WORDS EXACTLY LIKE THE LYRIC CARD ──────────────
   REPLACES "GHOSTED, AND AT THE BOTTOM, LIKE THE LYRICS" (Alex, 2026-08-06:
   "make Song Origin a quote ghosted at the bottom"), which put the quote at the
   foot with margin-top:auto. On 2026-08-07 he looked at the row and asked why
   the two ghosts do not match — see the measured before-and-after in the shared
   token block above. "At the bottom" is what made it sit 98px lower than the
   lyric text beside it, so it goes: the words now start where the lyric words
   start, 20px under the card's name, which is where the eye lands on both.

   THE FADE IS THE LYRIC CARD'S, STEP FOR STEP. Four lines of full ink, the
   fifth muted, the sixth running from a 55%-strength muted to transparent 130%
   of a line further down. The lyric card gets that from :nth-child rules because
   it always has six lines; a quote has as many as it has, so the same steps are
   written as one gradient in absolute line-heights. Same computed colour on
   every line, and nothing squeezed to fit.

   THE CAP IS SIX LINES SINCE 2026-08-07 (four before it), and it still cannot
   slice a visible word — the gradient has reached transparent a line before the
   cap does. It is the fade doing the work; the cap only stops a long quote from
   setting the card height.

   THE SPEAKER IS OUTSIDE ALL OF IT: its own element, its own colour, past the
   clamp. A quote whose attribution can be cut is an unsourced quote, and this
   site does not print those. */
body.stagelight .sp-origin-quote { margin:20px 0 22px;padding-bottom:6px }
body.stagelight .sp-origin-words {
  display:block;
  font-family:var(--sl-display);font-size:var(--sp-ghost-size);line-height:var(--sp-ghost-lead);font-weight:400;
  /* SIX LINES, NOT FOUR (Alex, 2026-08-07): "I wanted that text to look just
     like the lyrics and have six lines or something like that." The card stands
     362px now and a four-line block left it short. The ramp keeps its shape —
     full ink, then muted, then dissolving — just stretched over six: four lines
     of ink, one muted, the sixth fading out. A shorter source simply runs
     shorter; nothing is padded or repeated to fill the box. */
  max-height:calc(var(--sp-ghost-line) * 6);overflow:hidden;
  background:linear-gradient(180deg,
    var(--sl-ink) 0,
    var(--sl-ink) calc(var(--sp-ghost-line) * 4),
    var(--sl-muted) calc(var(--sp-ghost-line) * 4),
    var(--sl-muted) calc(var(--sp-ghost-line) * 5),
    var(--sp-ghost-tail) calc(var(--sp-ghost-line) * 5),
    transparent calc(var(--sp-ghost-line) * 6.3));
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
body.stagelight .sp-origin-by { display:block;margin-top:10px;font-family:var(--sl-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--sl-faint) }
/* The rail sits INSIDE the ledger section now, directly under its headline, so it
   carries its own bottom margin — it used to be wrapped in a <section> and got the
   84px block rhythm for free. 30px matches the lead's own margin-bottom above it. */
/* MATCHED TO THE HOME PAGE'S TOUR-STATS ROW, on purpose (Alex, 2026-08-05:
   "just like they are on the home page"). Same three equal columns, same 90px
   floor, same glass, same 30px display figure over an 11px mono uppercase
   label, same hairline between columns, same glass shadow. It was drawing its
   figure at 26px with a 7px gap and no shadow, which is a second rail that
   looks nearly like the first — the worst of the three options.
   The column count is pinned at 3 rather than read from a custom property,
   because the rail is now always three or absent. */
body.stagelight .sp-stats-rail { display:grid;grid-template-columns:repeat(3,minmax(0,1fr));align-items:center;min-height:90px;margin-bottom:30px;border:1px solid var(--sl-line);border-radius:var(--sl-r-md);background:var(--sl-glass);box-shadow:var(--sl-glass-shadow);-webkit-backdrop-filter:blur(26px) saturate(1.4);backdrop-filter:blur(26px) saturate(1.4) }
body.stagelight .sp-stat-col { display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;padding:18px 14px;text-align:center;border-left:1px solid var(--sl-line) }
body.stagelight .sp-stat-col:first-child { border-left:0 }
body.stagelight .sp-stat-col strong { font-family:var(--sl-display);font-size:30px;font-weight:640;line-height:1;color:var(--sl-ink);font-variant-numeric:tabular-nums }
body.stagelight .sp-stat-col span { font-family:var(--sl-mono);font-size:11px;line-height:1.5;letter-spacing:.08em;text-transform:uppercase;color:var(--sl-faint);text-wrap:balance }
/* ── THE LEDGER ─────────────────────────────────────────────────────────────
   STRUCTURE IS THE SITE'S, FINISH IS THE PROTOTYPE'S.
   The table is .tour-table inside a .tour-table-wrap.is-capped, closed by a
   .stats-expand — sticky head, sort affordance, the pinned collapse control and
   the phone card grammar are all inherited, none of it rewritten. What IS
   written here is the ledger's own presentation, because the songbook has no
   equivalent: the inset era pill, the round play chip, the note pills, and seven
   columns' widths.

   The first pass took the songbook's SKIN as well as its plumbing and came out
   coarser than the prototype it was meant to be. The values below are the
   prototype's own (design/prototypes/song-page.html): 14.5px body, 12/14 cells,
   ink date and venue against muted everything else, a 3px era pill inset from
   the row edges, gold on a guest. */

/* Three dropdowns, not fourteen chips — the site's own .show-filter/.custom-select
   (renderCustomSelect), which is the prototype's "All eras ▾" pill exactly. */
body.stagelight .lg-tools { display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:0 0 14px }
body.stagelight .lg-status { flex:1;min-width:0;text-align:right;margin:0;font-family:var(--sl-mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-faint) }
body.stagelight .lg-status:empty { display:none }

/* SEVEN COLUMNS, DECLARED WHERE THE SITE DECLARES ITS OWN. stagelight.css sizes
   .tour-table for the SONGBOOK's five columns in two places — a th/td pair rule
   (33/9/22/23/13) and a higher-specificity thead-th rule (24/12/25/24/15). With
   seven columns those land on the wrong ones and the leftovers get scaled: measured
   at 1440 that gave Date 309px, Venue 155px and Notes ZERO — which is why the guest
   pills, the best thing in this table, were invisible. A col-element group was tried
   and is simply ignored once thead th carries a width, so the widths are declared on
   the same selector shape at the same specificity; song-page.css loads after
   stagelight.css, so these win on source order. All seven are set, deliberately —
   leaving any of them to auto is what let the scaling back in. */
body.stagelight .lg-table thead th:nth-child(1) { width:16% }
body.stagelight .lg-table thead th:nth-child(2) { width:21% }
body.stagelight .lg-table thead th:nth-child(3) { width:14% }
body.stagelight .lg-table thead th:nth-child(4) { width:10% }
body.stagelight .lg-table thead th:nth-child(5) { width:8% }
body.stagelight .lg-table thead th:nth-child(6) { width:7% }
body.stagelight .lg-table thead th:nth-child(7) { width:24% }

/* The prototype's type and rhythm. */
body.stagelight .lg-table { font-size:14.5px }
body.stagelight .lg-table thead th { padding:12px 14px }
/* A sortable header is a <button> inside the <th>, and a button inherits none of
   the th's type — so Date / Venue / Length were rendering in body font, sentence
   case, beside CITY / ERA / SET / NOTES in mono caps. One header row, one voice. */
body.stagelight .lg-table thead th,body.stagelight .lg-table thead th button { font:600 11px/1.3 var(--sl-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--sl-faint) }
body.stagelight .lg-table thead th button { padding:0;background:none;border:0;cursor:pointer }
body.stagelight .lg-table thead th button:hover,body.stagelight .lg-table thead th[aria-sort] button { color:var(--sl-ink) }
/* Length is a right-aligned number, so its header sits over the digits. */
body.stagelight .lg-table thead th:nth-child(6) { text-align:right }
/* stagelight right-aligns the last cell of a .tour-table — right for the
   songbook's "Last played" date, wrong for a column of pills, which belong
   against the data they annotate. */
body.stagelight .lg-table thead th:last-child,body.stagelight .lg-table tbody td:last-child { text-align:left }
body.stagelight .lg-table tbody th[scope="row"],body.stagelight .lg-table tbody td { padding:12px 14px;border-bottom:1px solid var(--sl-line-faint);vertical-align:middle }
body.stagelight .lg-table td { color:var(--sl-muted) }
body.stagelight .lg-venue { color:var(--sl-ink) }
body.stagelight .lg-era,body.stagelight .lg-set { white-space:nowrap }
body.stagelight .lg-length { font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right;color:var(--sl-ink) }
body.stagelight .lg-dash { color:var(--sl-line-strong) }

/* The whole row opens the show (Alex, 08-01); the date cell keeps the real
   anchor so the target is also reachable by keyboard and legible to a crawler. */
body.stagelight .lg-table tbody tr { cursor:pointer;transition:background .14s ease }
body.stagelight .lg-table tbody tr:hover { background:rgba(255,255,255,.025) }
body.stagelight .lg-table tbody th[scope="row"] { position:relative;padding-left:56px;white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--sl-ink);font-weight:600 }
body.stagelight .lg-table tbody th[scope="row"] a { color:inherit }
body.stagelight .lg-table tbody tr:hover th[scope="row"] a { text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--sl-line-strong) }

/* The era pill: inset from the row edges and rounded, as the prototype drew it.
   A full-bleed bar was tried first — it turns forty years of one guitarist into
   an unbroken paint stripe down the table and stops reading as a per-night mark. */
body.stagelight .lg-era-bar { position:absolute;left:14px;top:11px;bottom:11px;width:3px;border-radius:2px }

/* Round, and near the prototype's size. It is the only control in the row, so it
   can afford to look like one. */
body.stagelight .lg-play { position:absolute;left:24px;top:50%;transform:translateY(-50%);width:26px;height:26px;border-radius:50%;border:1px solid var(--sl-line-strong);display:grid;place-items:center;color:var(--sl-ink);background:rgba(255,255,255,.03);cursor:pointer;padding:0;transition:background .15s ease,color .15s ease,border-color .15s ease,transform .15s ease }
body.stagelight .lg-play svg { margin-left:1px }
body.stagelight .lg-play:hover,body.stagelight .lg-play:focus-visible { background:var(--sl-ink);color:#111;border-color:var(--sl-ink);transform:translateY(-50%) scale(1.06) }
body.stagelight .lg-play.is-playing { background:var(--sl-ink);color:#111;border-color:var(--sl-ink) }

/* THE NOTES COLUMN — what happened inside the song that night, and the reason
   this table is worth reading at all. Gold on a guest, blue on an alternate
   version, plain on a jam, rap or tease. */
body.stagelight .lg-notes { white-space:normal }
/* A long note wraps at its spaces but never breaks mid-word: overflow-wrap:anywhere
   was tried and let the browser shrink a pill to one character (measured 20px for
   "with Billy Strings"). */
body.stagelight .lg-note { display:inline-block;max-width:100%;border:1px solid var(--sl-line-strong);border-radius:var(--sl-r-pill);padding:3px 10px;font:600 10.5px/1.45 var(--sl-mono);letter-spacing:.02em;color:var(--sl-muted);margin:2px 5px 2px 0;white-space:normal }
body.stagelight .lg-note.lg-guest { border-color:rgba(201,163,95,.5);color:#c9a35f }
body.stagelight .lg-note.lg-variant { border-color:rgba(96,165,210,.5);color:#60a5d2 }
body.stagelight .lg-foot { margin:14px 2px 0;font-size:13px;line-height:1.6;color:var(--sl-faint) }

/* Seven columns do not survive a tablet. City goes first (the venue already
   places the night), then Set. */
@media (max-width:1080px) {
  body.stagelight .lg-table thead th:nth-child(3),body.stagelight .lg-table tbody td:nth-child(3) { display:none }
}
@media (max-width:860px) {
  body.stagelight .lg-table thead th:nth-child(5),body.stagelight .lg-table tbody td:nth-child(5) { display:none }
}

/* PHONE. The site turns .tour-table into stacked cards below 620px (display:block
   on the table, thead hidden, each row a grid). The block transformation is
   inherited; the GRID is not, because placing <td> elements into named grid
   columns proved unreliable here — with the cells spanning 1/-1 and carrying both
   width:100% and justify-self:stretch, "Orpheum Theatre" still laid out in a 27px
   column, one character per line, and rows measured 188–248px. A flex row places
   the same cells with no such ambiguity: measured, every row is 105px and the
   venue gets the full 295px. Date leads with the length opposite it, venue and era
   read underneath, notes run full width. */
@media (max-width:640px) {
  body.stagelight .lg-table tbody tr { display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;padding:15px 8px }
  body.stagelight .lg-table tbody th[scope="row"],body.stagelight .lg-table tbody td { border:0;padding:0;width:auto;box-sizing:border-box }
  body.stagelight .lg-table tbody th[scope="row"] { flex:1 1 auto;order:1;padding-left:42px;font-size:15.5px }
  body.stagelight .lg-length { flex:0 0 auto;order:2;margin-left:auto;text-align:right;font-size:14px }
  body.stagelight .lg-venue { flex:1 0 100%;order:3;font-size:14px }
  body.stagelight .lg-era { flex:1 0 100%;order:4;font-family:var(--sl-mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-faint) }
  /* The songbook hides its last column on phones (.tour-table tr > td:last-child).
     This table's last column is Notes — the guests and jams — so it opts back in. */
  body.stagelight .lg-table tbody tr > td:last-child { display:block }
  body.stagelight .lg-notes { flex:1 0 100%;order:5 }
  body.stagelight .lg-notes:empty { display:none }
  body.stagelight .lg-city,body.stagelight .lg-set { display:none }
  body.stagelight .lg-era-bar { left:0;top:.2em;bottom:auto;height:1.1em }
  body.stagelight .lg-play { left:10px;top:.05em;transform:none;width:24px;height:24px }
  body.stagelight .lg-play:hover,body.stagelight .lg-play:focus-visible { transform:scale(1.06) }
  body.stagelight .lg-tools { gap:8px }
  body.stagelight .lg-status { flex-basis:100%;text-align:left }
}

/* ── RESTORED 2026-08-01 ───────────────────────────────────────────────────
   Everything below was deleted by accident. A scripted edit to the phone block
   used the file's LAST closing brace as its end anchor, so it cut from that
   block to end-of-file and took the runs cards, the era chips, the pick block,
   the tags and transport, the lyric strip and the dock with it. The brace count
   stayed balanced, which is why the check I ran passed — whole rules went, not
   halves. Balanced braces are not proof a stylesheet is intact; the selectors
   have to still be there. */
body.stagelight .sp-runs { grid-template-columns:repeat(2,1fr) }
  body.stagelight .sp-pick { grid-template-columns:1fr }
  body.stagelight .sp-pick-side { border-left:0;border-top:1px solid var(--sl-line) }
@media (max-width:560px) {
  body.stagelight .sp-hero-in { grid-template-columns:1fr }
  body.stagelight .sp-cover { width:180px }
  body.stagelight .sp-stats-rail { grid-template-columns:repeat(3,minmax(0,1fr)) }
  body.stagelight .sp-runs { grid-template-columns:1fr }
  body.stagelight section { margin:60px 0 }
  body.stagelight .sp-actions .sc-chip { flex:1 1 auto;justify-content:center }
}
@media (prefers-reduced-motion:reduce) {
  body.stagelight h1.sp-title .sp-dye,body.stagelight .sp-scrub .sp-fill,body.stagelight .sp-lyric-track { animation:none }
}


















































body.stagelight .sp-scrawl .sp-row { display:block; white-space:nowrap; line-height:1.12; }
body.stagelight .sp-scrawl span { font-size:26px; line-height:1.12; white-space:nowrap; }



























body.stagelight .sp-runs { display:grid;grid-template-columns:repeat(var(--sp-runs,3),minmax(0,1fr));gap:14px }
body.stagelight .sp-run-card { position:relative;border:1px solid var(--sl-line);border-radius:var(--sl-r-md);padding:20px 22px;background:linear-gradient(180deg,rgba(24,24,28,.4),rgba(16,16,20,.3));cursor:pointer;transition:border-color .18s,transform .18s;display:block }
body.stagelight .sp-run-card:hover { transform:translateY(-2px);border-color:var(--sl-line-strong) }
body.stagelight .sp-run-card .sp-t { display:block;font:600 17px/1.25 var(--sl-display);letter-spacing:-.01em;padding-right:44px }
body.stagelight .sp-run-card .sp-r { display:block;font-family:var(--sl-mono);font-size:11.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--sl-faint);margin-top:7px }
body.stagelight .sp-taper-src { margin-top:16px;font-family:var(--sl-mono);font-size:11.5px;letter-spacing:.02em;color:var(--sl-faint) }
body.stagelight .sp-run-group+.sp-run-group { margin-top:26px }
body.stagelight .sp-run-label { font:600 11px/1 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--sl-faint);margin:0 0 12px }
body.stagelight .sp-run-card .sp-bc-open { top:16px;right:16px }
body.stagelight .sp-run-card:hover .sp-bc-open { border-color:var(--sl-ink);color:var(--sl-ink);background:rgba(255,255,255,.06) }
body.stagelight .sp-era-chips { display:flex;gap:10px;flex-wrap:wrap;margin:0 0 22px }
body.stagelight .sp-chip { border:1px solid var(--sl-line-strong);border-radius:var(--sl-r-pill);padding:9px 18px;font:560 13px/1 var(--sl-body);color:var(--sl-muted);background:transparent }
body.stagelight .sp-chip small { font:500 11px/1 var(--sl-mono);color:var(--sl-faint);margin-left:7px }
body.stagelight .sp-chip.sp-on { background:var(--sl-ink);border-color:var(--sl-ink);color:#111 }
body.stagelight .sp-chip.sp-on small { color:rgba(17,17,17,.6) }
body.stagelight .sp-chip:not(.sp-on):hover { border-color:rgba(255,255,255,.3);color:var(--sl-ink) }
body.stagelight .sp-pick { display:grid;grid-template-columns:minmax(280px,38%) minmax(0,1fr);min-height:280px;border:1px solid var(--sl-line);border-radius:var(--sl-r);overflow:hidden;background:var(--sl-glass) }
body.stagelight .sp-pick-main { padding:32px 36px;display:flex;flex-direction:column;justify-content:center;gap:14px }
body.stagelight .sp-pick-eyebrow { font:600 11px/1 var(--sl-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--sl-faint) }
body.stagelight .sp-pick h3 { font:600 28px/1.05 var(--sl-display);letter-spacing:-.015em }
body.stagelight .sp-pick .sp-where { color:var(--sl-muted);font-size:15px }
body.stagelight .sp-pick-tags { display:flex;gap:8px;flex-wrap:wrap }
body.stagelight .sp-tag { border:1px solid var(--sl-line-strong);border-radius:var(--sl-r-pill);padding:5px 12px;font:600 11px/1 var(--sl-mono);letter-spacing:.06em;color:var(--sl-muted) }
body.stagelight .sp-pick-bar { display:flex;align-items:center;gap:14px;margin-top:auto }
body.stagelight .sp-play-round { width:50px;height:50px;border-radius:50%;background:var(--sl-ink);color:#111;display:grid;place-items:center;box-shadow:0 8px 24px -8px rgba(242,242,240,.4);flex:none;transition:transform .18s }
body.stagelight .sp-play-round:hover { transform:scale(1.05) }
body.stagelight .sp-scrub { position:relative;flex:1;height:6px;border-radius:99px;background:rgba(255,255,255,.14);overflow:hidden }
body.stagelight .sp-scrub .sp-fill { position:absolute;inset:0;width:34%;background:var(--tie);background-size:300% 100%;animation:dye-drift 8s ease-in-out infinite alternate;border-radius:99px }
body.stagelight .sp-clock { font:600 12px/1 var(--sl-mono);color:var(--sl-muted);font-variant-numeric:tabular-nums }
body.stagelight .sp-pick-side { border-left:1px solid var(--sl-line);background:rgba(0,0,0,.25);padding:24px;display:flex;flex-direction:column;justify-content:center }
body.stagelight .sp-pick-side .sp-why { color:var(--sl-muted);font-size:14px;line-height:1.6 }
body.stagelight .sp-pick-side .sp-why b { color:var(--sl-ink) }
body.stagelight .sp-dock { position:fixed;left:50%;transform:translateX(-50%);bottom:18px;z-index:60;width:min(920px,calc(100% - 32px));background:rgba(16,16,18,.85);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);border:1px solid var(--sl-line-strong);border-radius:16px;padding:10px 16px;display:flex;align-items:center;gap:14px;box-shadow:0 18px 50px rgba(0,0,0,.5) }
body.stagelight .sp-dock .sp-thumb { width:42px;height:42px;border-radius:8px;overflow:hidden;flex:none }
body.stagelight .sp-dock .sp-thumb img { width:100%;height:100%;object-fit:cover }
body.stagelight .sp-dock .sp-t { font:600 14px/1.25 var(--sl-body);white-space:nowrap;overflow:hidden;text-overflow:ellipsis }
body.stagelight .sp-dock .sp-w { color:var(--sl-faint);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis }
body.stagelight .sp-dock .sp-play-round { width:40px;height:40px }
body.stagelight .sp-dock .sp-scrub { height:5px }

@media (max-width: 1040px) {
  body.stagelight .sp-hero-in { grid-template-columns: 200px minmax(0,1fr); }
}
@media (max-width: 560px) {
  body.stagelight .sp-hero-in { grid-template-columns: 1fr; }
}

body.stagelight .song-main > .crumbs, body.stagelight .song-main > .archive-title { width: min(1240px, calc(100% - 48px)); margin-left: auto; margin-right: auto; }
body.stagelight .sp-rail, body.stagelight .sp-hero-in { width: min(1440px, calc(100% - 64px)); }
body.stagelight .song-main > .crumbs, body.stagelight .song-main > .archive-title { width: min(1440px, calc(100% - 64px)); }




/* The prototype sets its section leads at 38ch; stagelight's .sw-lead is 30ch,
   which pushed the ledger's lead from three lines to four and broke it after
   "on". Scoped to this page — the site's own leads are untouched. */
/* THE LEADS. stagelight's .sw-lead is margin:0 / max-width:30ch, because on the
   homepage every block beneath a lead brings its own top margin. On this page
   they do not, so five of the six section headlines sat flush against the block
   under them — measured 0px under the ledger, the taper notes, the era chips and
   the runs-with groups. The prototype's own value is margin:0 0 30px at 38ch;
   both are restored here, scoped to this page. The video block's lead is exempt:
   it sits BESIDE its YouTube chip in .fs-head, not above content. */
body.stagelight .song-main-full .sw-lead { max-width:38ch; margin-bottom:30px }
body.stagelight .song-main-full .fs-head .sw-lead { margin-bottom:0 }

/* ── RESPONSIVE ─────────────────────────────────────────────────────────────
   These blocks used to sit at the TOP of this file, above every rule they exist
   to override — so at equal specificity the base rules, being later, won every
   time. .sp-stat { flex:1 1 45% } at the top lost to .sp-stat { flex:1 } further
   down, which is why the five-cell stat bar never wrapped and ran off a 390px
   screen, and why the hero chips never went full width. The lift script emits
   them first; they belong last. */
@media (max-width:900px) {
  body.stagelight .sp-hero-in { grid-template-columns:190px minmax(0,1fr);gap:28px;padding-top:44px }
  body.stagelight .sp-stat-strip { flex-wrap:wrap }
  body.stagelight .sp-stat { flex:1 1 45%;min-width:0;border-top:1px solid var(--sl-line-faint) }
  /* ONE COLUMN, AND EVERY CARD THE SAME HEIGHT. A min-height alone only set a
     floor — Space Wrangler's lyric lines wrap, so its Lyrics card came out at
     362 beside two 330s, which is exactly the ragged column Alex was looking at.
     grid-auto-rows:1fr sizes every row to the tallest one, so the three agree
     whatever any of them holds, and they grow together instead of separately. */
  body.stagelight .sp-bento-grid { grid-template-columns:1fr;grid-auto-rows:1fr }
  /* TWO COLUMNS ALWAYS ORPHANS AN ODD STAT. A three-stat rail became two on top
     and one below spanning half the width, which is what Alex was looking at
     when he said "the three stats should be more intelligently stacked" — the
     grid was the fault, not the styling. auto-fit keeps all three abreast
     wherever 150px each will fit, and only wraps when it genuinely cannot. */
  body.stagelight .sp-stats-rail { grid-template-columns:repeat(auto-fit,minmax(150px,1fr)) }
  /* NO HAIRLINE OVER THE THREE STATS. Alex, 2026-08-06: "there's an extra line
     there on mobile that looks wrong at the top." Three columns sitting abreast
     each drew their own top border, which joins into one continuous rule across
     the whole block — a section divider nobody asked for, sitting between the
     ledger's headline and its own numbers. The border came from .sp-stat, the
     old five-cell strip this replaced, where the cells WRAPPED onto several rows
     and the line separated them. They do not wrap any more, so it separates
     nothing. */
  body.stagelight .sp-stat-col { border-top:0 }
  body.stagelight .sp-runs { grid-template-columns:repeat(2,1fr) }
  body.stagelight .sp-pick { grid-template-columns:1fr }
  body.stagelight .sp-pick-side { border-left:0;border-top:1px solid var(--sl-line) }
}
@media (max-width:560px) {
  body.stagelight .sp-hero-in { grid-template-columns:1fr }
  body.stagelight .sp-cover { width:180px }
  body.stagelight .sp-stats-rail { grid-template-columns:repeat(3,minmax(0,1fr)) }
  body.stagelight .sp-runs { grid-template-columns:1fr }
  body.stagelight section { margin:60px 0 }
  body.stagelight .sp-actions .sc-chip { flex:1 1 auto;justify-content:center }
}
@media (prefers-reduced-motion:reduce) {
  body.stagelight h1.sp-title .sp-dye,body.stagelight .sp-scrub .sp-fill,body.stagelight .sp-lyric-track { animation:none }
}

/* THE DOCK. hp-dock-in is the homepage's choreography for a bar sliding out of
   the hero as it scrolls away. This page has no hero to leave, and the bar ships
   hidden — so the animation is applied to a hidden element, never actually runs,
   and freezes at frame 0 with the bar translated its own height BELOW the fold.
   Measured: still transform:translateY(71px) and playState "running" 2.5s after
   a 0.2s animation. The bar is docked from the start here, so it simply sits. */
body.stagelight .hero-player.is-docked { animation: none; transform: none; }

/* The bar's two text lines crawl when they do not fit, the way nugs.net does
   (Alex, 2026-08-02) — CONTINUOUSLY and in one direction, not sweeping left and
   right. song-player.mjs measures the real overflow, appends a second copy of
   the text and publishes --scroll-w (one copy's width) and --scroll-ms; the
   track then travels exactly one copy before looping, so the wrap is invisible.
   Same mechanism as the site's own footer crawl. Nothing moves unless it has to. */
/* The measurable state comes FIRST and unconditionally. Scoping inline-block to
   .is-scrolling made this circular: the span had no laid-out width until the
   class was added, and the class was only added if it had width, so scrollWidth
   read 0 against a 392px box and nothing ever scrolled. */
body.stagelight .hero-player .hp-scroll,
body.stagelight .hero-player .hp-scroll-twin { display: inline-block; white-space: nowrap }
body.stagelight .hero-player .hp-title.is-scrolling,
body.stagelight .hero-player .hp-context.is-scrolling {
  text-overflow: clip; overflow: hidden;
}
body.stagelight .hero-player .hp-title.is-scrolling .hp-scroll,
body.stagelight .hero-player .hp-title.is-scrolling .hp-scroll-twin,
body.stagelight .hero-player .hp-context.is-scrolling .hp-scroll,
body.stagelight .hero-player .hp-context.is-scrolling .hp-scroll-twin {
  display: inline-block; white-space: nowrap; padding-right: 48px;
  animation: hp-crawl var(--scroll-ms, 8s) linear infinite;
  will-change: transform;
}
@keyframes hp-crawl {
  from { transform: translateX(0) }
  to   { transform: translateX(calc(var(--scroll-w, 0px) * -1)) }
}
/* Reading beats motion: hovering the bar stops it where it is. */
body.stagelight .hero-player:hover .hp-scroll,
body.stagelight .hero-player:hover .hp-scroll-twin { animation-play-state: paused }
@media (prefers-reduced-motion: reduce) {
  body.stagelight .hero-player .hp-scroll,
  body.stagelight .hero-player .hp-scroll-twin { animation: none; transform: none }
  body.stagelight .hero-player .hp-scroll-twin { display: none }
  body.stagelight .hero-player .hp-title.is-scrolling,
  body.stagelight .hero-player .hp-context.is-scrolling { text-overflow: ellipsis }
}

/* ── THE THREE-COLUMN HERO ───────────────────────────────────────────────────
   The record, the song, the facts. The stats used to sit in a five-cell strip
   under the title, which has room for numbers OR marks and not both; moving them
   into a rail down the right is what lets every fact carry its own icon.

   ONE HERO SERVES ALL 698 SONG PAGES. It has to degrade honestly: a song with no
   album art keeps the column and drops the image, a song with one performance
   prints one line, and the fourth slot carries a rank only where a rank is worth
   printing. Nothing here assumes Chilly Water. */
body.stagelight .sp-hero-in {
  display: grid;
  grid-template-columns: minmax(180px, 268px) minmax(0, 1fr) minmax(210px, 264px);
  gap: 0 clamp(28px, 4vw, 62px);
  align-items: center;
  width: min(100% - 64px, var(--sp-rail, 1440px));
  margin-inline: auto;
  padding: clamp(38px, 5vw, 66px) 0 clamp(34px, 4.4vw, 56px);
}
body.stagelight .sp-cover img { width: 100%; height: auto; display: block; border-radius: 10px; }
/* The sleeve sits on its own reflection, which is where the page gets its depth
   from. Masked, never a second copy in the DOM. */
body.stagelight .sp-cover {
  position: relative;
  filter: drop-shadow(0 22px 44px rgba(0,0,0,.55));
}
body.stagelight .sp-cover::after {
  content: ""; position: absolute; inset: 100% 0 auto 0; height: 46%;
  background: var(--cover-url) bottom center / 100% auto no-repeat;
  transform: scaleY(-1); transform-origin: top;
  opacity: .16;
  -webkit-mask-image: linear-gradient(#000, transparent 72%);
  mask-image: linear-gradient(#000, transparent 72%);
  pointer-events: none;
}
body.stagelight .sp-cover-empty { aspect-ratio: 1; border-radius: 10px; background: rgba(255,255,255,.04); border: 1px solid var(--sl-line); }

body.stagelight .sp-hero-mid { min-width: 0; }
body.stagelight .sp-title {
  margin: 0; font: 700 clamp(44px, 5.6vw, 78px)/1.02 var(--sl-display);
  letter-spacing: -.03em; text-wrap: balance;
}
/* ── THE ONE METADATA LINE ─────────────────────────────────────────────────────
   Album (or cover credit), then the rank, on one horizontal line. This began as
   a Space Wrangler-only treatment; it is every song's hero now, so it lives here
   rather than in that page's override sheet — two sheets styling one line is how
   they drift apart. */
/* 15.5px muted grey under a 72px title read as a caption rather than the line
   that tells you what the song IS (Alex, 2026-08-05: "it feels not super
   legible"). Size AND contrast were both working against it, so both moved. */
body.stagelight .sp-meta {
  margin: 14px 0 0; color: var(--sl-soft, rgba(242,242,240,.78)); font-size: 17.5px;
  display: flex; align-items: center; flex-wrap: nowrap; gap: 10px;
}
body.stagelight .sp-meta b { color: var(--sl-ink); font-weight: 620; }
body.stagelight .sp-meta > * { flex: 0 0 auto; }
body.stagelight .sp-meta-sep { color: var(--sl-faint); }
/* RARITY BELOW THE RANK — ON A PHONE AND A TABLET ONLY (Alex, 2026-08-06: "Move
   Common below the number Most Played, so we only have four items below this").
   It sits with the record and the rank there because it is the same kind of
   statement — what this song IS, rather than a count of it — and it leaves the
   stacked rail with four counted facts instead of five of two different kinds.

   THE FIRST PASS APPLIED IT AT EVERY WIDTH, WHICH WAS NOT THE ASK. Alex, later
   the same day: "Rarity level position only changes position for mobile. It
   should stay in original position on desktop view." On a desktop the rail is
   its own column beside the artwork, five rows fit it without running past the
   picture, and rarity has always been its last row.

   SO 900px IS THE SEAM. Above it the rail row shows and this line is gone;
   at 900 and below they swap. Both elements are rendered by renderSongHero and
   exactly one is ever displayed — display:none takes an element out of the
   accessibility tree too, so a screen reader is read one rarity, never two. */
body.stagelight .sp-rarity-line {
  margin: 8px 0 0; display: flex; align-items: center; gap: 8px;
  font-size: 15px; color: var(--sl-muted);
}
body.stagelight .sp-rarity-line strong { color: var(--sl-ink); font-weight: 620; }
body.stagelight .sp-rarity-line .rarity-symbol { display: inline-flex; align-items: center; }
@media (min-width: 901px) { body.stagelight .sp-rarity-line { display: none; } }
/* The other half of the swap — hiding the rail's rarity row below 900 — cannot
   live here: it loses a specificity tie to `.sp-fact` further down the file. It
   is stated beside that rule instead; see the note there. */
body.stagelight .sp-rank-inline {
  display: inline-flex; align-items: center; gap: 6px; vertical-align: middle;
  color: var(--sl-muted); white-space: nowrap;
}
body.stagelight .sp-rank-inline .bt-icon { width: 1.55em; height: 1.55em; flex: none; }
body.stagelight .sp-rank-prefix, body.stagelight .sp-rank-suffix { color: var(--sl-muted); }
body.stagelight .sp-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 22px; margin-top: clamp(22px, 2.6vw, 34px); }
/* The secondary actions are links, not glass chips. Three chips in a row read as
   three equal choices; there is one primary action here and two ways to jump. */
body.stagelight .sp-jump {
  color: var(--sl-ink); text-decoration: none; font-size: 14.5px; font-weight: 560;
  display: inline-flex; align-items: center; gap: 8px;
}
body.stagelight .sp-jump span { transition: translate 160ms var(--bt-out, ease); color: var(--sl-muted); }
body.stagelight .sp-jump:hover span { translate: 3px 0; color: var(--sl-ink); }

/* The fact rail. A hairline separates it from the title column — the facts are a
   different kind of information and the rule says so without a box. */
body.stagelight .sp-facts {
  display: grid; gap: clamp(13px, 1.5vw, 19px);
  padding-left: clamp(22px, 2.6vw, 38px);
  border-left: 1px solid var(--sl-line);
  align-self: stretch; align-content: center;
}
body.stagelight .sp-fact { display: grid; grid-template-columns: 26px minmax(0, 1fr); align-items: center; gap: 13px; }
body.stagelight .sp-fact .bt-icon { color: var(--sl-muted); }
body.stagelight .sp-fact .rarity-symbol { display: block; width: 26px; }
body.stagelight .sp-fact .rarity-symbol svg { width: 100%; height: auto; display: block; max-height: 20px; }
body.stagelight .sp-fact-body strong { display: block; font: 620 20px/1.15 var(--sl-display); letter-spacing: -.015em; }
body.stagelight .sp-fact-body span { display: block; margin-top: 2px; color: var(--sl-muted); font-size: 12.5px; }
/* THE PHONE HIDES THE RAIL'S RARITY ROW, AND THE RULE HAS TO SIT HERE TO DO IT.
   `body.stagelight .sp-fact-rarity` and `body.stagelight .sp-fact` have exactly
   the same specificity and a media query adds none, so wherever this rule was
   written earlier in the file, `.sp-fact { display: grid }` above simply won and
   both rarities showed at 375 — caught by measuring the built page, not by
   reading the stylesheet. It is the same trap as the 2026-08-06 gutter fix, so
   it gets the same answer: state the override immediately after the rule it
   overrides, where it cannot lose. The companion rule (hide .sp-rarity-line
   above 900) is beside .sp-rarity-line and has nothing competing with it. */
@media (max-width: 900px) { body.stagelight .sp-fact-rarity { display: none; } }

/* Below 1080 the fact rail cannot hold its own column without squeezing the
   title, so it goes under the two of them and lays out across. */
@media (max-width: 1080px) {
  body.stagelight .sp-hero-in { grid-template-columns: minmax(150px, 220px) minmax(0, 1fr); }
  body.stagelight .sp-facts {
    grid-column: 1 / -1; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
    margin-top: 34px; padding-left: 0; padding-top: 22px;
    border-left: 0; border-top: 1px solid var(--sl-line);
  }
}
/* THE BREADCRUMB BAR. It sits above the hero on its own line and stays there —
   sticky under the header, so it survives the menu retracting. That persistence
   is the point: it is the one thing on the page that always answers "where am
   I", and a crumb that scrolls away answers it only at the top. */
body.stagelight .song-crumbs {
  position: sticky; top: 0; z-index: 40;
  width: 100vw; margin-left: calc(50% - 50vw); padding: 13px 0 12px;
  font: 500 11px/1 var(--sl-mono); letter-spacing: .14em; text-transform: uppercase;
  background: linear-gradient(#0b0b0c 68%, rgba(11,11,12,0));
}
/* One line, always. The current page's own title is the only crumb allowed to
   give ground — it ellipsizes; the links never wrap. */
body.stagelight .song-crumbs .sc-in {
  display: flex; align-items: center; flex-wrap: nowrap; gap: 9px;
  width: min(100% - 64px, var(--sp-rail, 1440px)); margin-inline: auto;
  overflow: hidden; white-space: nowrap;
}
body.stagelight .song-crumbs [aria-current="page"] {
  overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
body.stagelight .song-crumbs a { color: var(--sl-muted); text-decoration: none; transition: color 140ms var(--bt-out, ease); }
body.stagelight .song-crumbs a:hover { color: var(--sl-ink); }
body.stagelight .song-crumbs .crumb-sep { color: var(--sl-faint); }
/* The song's own name is the end of the trail and is not a link to itself. */
body.stagelight .song-crumbs [aria-current="page"] { color: var(--sl-ink); }

/* SCROLL ANCHORING WAS MOVING THE PAGE 1,600px ON A PLAY CLICK (Alex: "I tapped
   Play this era and it pushed me down to the bottom"). Nothing scrolled it —
   traced with scrollTo, scrollIntoView and focus all instrumented, and none of
   them fired. Nothing moved either: the hero, the ledger, the era section and
   the page height were byte-identical before and after.
   It was the browser. Arming a track flips the docked player from display:none
   to display:grid, and Chrome's scroll anchoring picked a new anchor and jumped
   to it. Measured three ways: as shipped 1,661px, with anchoring off 0px, with
   the dock kept in layout 0px.
   Anchoring off is the fix, because keeping the dock in layout is what put an
   empty transport across the page in the first place. */
body.stagelight .song-main { overflow-anchor: none; }

/* A CARD THAT PLAYS LOOKS LIKE A CONTROL. These were divs with cursor:default
   and a hand-typed count; the ones that can play are buttons now and carry the
   same play mark every other control on the page uses, so the affordance is
   consistent rather than a card you have to discover is clickable. A jam we hold
   no tape for stays quiet and says "no tape" instead of pretending. */
body.stagelight .sp-run-card.is-playable {
  position: relative; width: 100%; text-align: left; font: inherit; color: inherit;
  cursor: pointer; padding-left: 46px;
}
body.stagelight .sp-run-card.is-playable .sp-run-play {
  position: absolute; left: 16px; top: 50%; translate: 0 -50%;
  display: grid; place-items: center; width: 24px; height: 24px; border-radius: 999px;
  border: 1px solid var(--sl-line-strong); color: var(--sl-ink);
  transition: background 140ms var(--bt-out, ease), border-color 140ms var(--bt-out, ease);
}
body.stagelight .sp-run-card.is-playable:hover .sp-run-play,
body.stagelight .sp-run-card.is-playable:focus-visible .sp-run-play {
  background: var(--sl-ink); color: #111; border-color: var(--sl-ink);
}
body.stagelight .sp-run-card.is-playable.is-playing .sp-run-play { background: var(--song-accent, var(--sl-ink)); color: #111; }
body.stagelight .sp-run-card.is-quiet { cursor: default; opacity: .72; }


/* The hero names the band, then the credit. Two lines because they are two
   different claims: who played it (the subject of every number on this page)
   and where it came from. The second is deliberately quieter — on a cover page
   the writer's name used to be the only name in the hero, and it read as though
   the archive belonged to him. */
body.stagelight .sp-credit { margin: 4px 0 0; font-size: 15.5px; }
/* NO UNDERLINE. It sat on a text baseline the rest of the line does not share,
   so on one horizontal metadata line it read as a rule floating at the wrong
   height rather than as a link (Alex, 2026-08-05: "it's not vertically aligned
   and that bothers me"). It is still a link; hover does the telling. */
body.stagelight .sp-album-link {
  color: var(--sl-muted); text-decoration: none;
  transition: color 140ms var(--bt-out, ease);
}
body.stagelight .sp-album-link:hover { color: var(--sl-ink); }

/* A photograph of a night is not a record sleeve — same slot, lighter frame. */
body.stagelight .sp-cover-night { box-shadow: 0 18px 44px rgba(0,0,0,.5), 0 0 0 1px var(--sl-line); }

/* HAND-PICKED ARTWORK CROPS; everything else does not. A picked photograph was
   chosen for a subject — "lock in on the two drummers" — and the hero renders
   images at their natural ratio, so the whole wide frame showed and the subject
   stayed small. Squaring the slot and covering it makes the `focus` value in
   song-artwork-curated.json actually bite: a 3:2 photo shows its middle
   two-thirds, panned to wherever the subject is. */
body.stagelight .sp-cover-picked { aspect-ratio: 1; overflow: hidden; }
body.stagelight .sp-cover-picked img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── ONE PLACE TO PICK A VERSION ──────────────────────────────────────────────
   Two sections used to ask the same question one above the other. This is the
   /listen/ card's shape, which Alex pointed at directly: the lead on the left,
   the era chips on the right of the same line, the featured pick with the
   night's photograph, then the four presets under it.

   The artwork is why the merge was worth doing — neither block had room for a
   picture while both existed. */
body.stagelight .sp-era-head {
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:24px; flex-wrap:wrap; margin-bottom:22px;
}
body.stagelight .sp-era-head .sw-lead { margin-bottom:0 }
body.stagelight .sp-era-head .sp-era-chips { margin:0; flex:0 1 auto }
/* "The only recording there is" — the scarcity fact for songs we hold one tape
   of, in the slot the era chips would occupy (they never do on these pages: one
   recording is one era, so there is nothing to choose between). It is set as a
   LABEL, not a chip: the house's mono caption type, muted, no border and no
   background, because a control-shaped thing that cannot be pressed is a lie.
   Aligned with the heading's first line rather than the chips' row so it reads
   as part of the sentence above it. */
body.stagelight .sp-era-only {
  margin:0; flex:0 1 auto; align-self:center;
  font:600 11px/1.2 var(--sl-mono); letter-spacing:.14em; text-transform:uppercase;
  color:var(--sl-muted);
}

/* The photograph fills its cell — no radius or border of its own; the card's
   frame is the frame. */
body.stagelight .sp-pick-art { position:relative; min-height:100%; background:rgba(255,255,255,.04) }
body.stagelight .sp-pick-art img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block }

/* The preset stands up, Stripe-style: the night's photograph is the top half
   of the card, the play control rides the photo, the words sit under it. */
body.stagelight .sp-era-bento { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:14px }
body.stagelight .sp-era-bento .sp-pick { grid-column:span 4 }
body.stagelight .sp-era-solo .sp-pick { grid-column:1 / -1 }
body.stagelight .sp-era-bento .sp-smart-card { grid-column:span 2 }
body.stagelight .sp-card-face {
  position:relative; display:block; aspect-ratio:16/10; overflow:hidden;
  background:rgba(255,255,255,.04);
}
body.stagelight .sp-card-face img { width:100%; height:100%; object-fit:cover; display:block }
body.stagelight .sp-card-face::after {
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, rgba(9,9,11,0) 55%, rgba(9,9,11,.45) 100%);
}
body.stagelight .sp-card-face .sp-mini-play { position:absolute; top:12px; right:12px; z-index:1; background:rgba(11,11,12,.55); backdrop-filter:blur(6px) }
body.stagelight .sp-smart-card .sp-txt { display:block; padding:16px 18px 18px }

body.stagelight .sp-era-all {
  display:block; text-align:right; margin-top:20px;
  font-family:var(--sl-mono); font-size:12px; letter-spacing:.04em;
  text-transform:uppercase; color:var(--sl-faint);
}
body.stagelight .sp-era-all:hover { color:var(--sl-ink) }

@media (max-width:760px) {
  body.stagelight .sp-era-bento { grid-template-columns:1fr }
  body.stagelight .sp-era-bento .sp-pick,
  body.stagelight .sp-era-bento .sp-smart-card { grid-column:auto }
  body.stagelight .sp-pick { grid-template-columns:1fr; min-height:0 }
  body.stagelight .sp-pick-art { aspect-ratio:16/9; min-height:0 }
  body.stagelight .sp-pick-main { padding:22px; justify-content:flex-start }
  body.stagelight .sp-era-head { gap:14px }
}

/* "Play this one" filled the whole card because .sp-pick-main is a flex column
   and its children stretch by default. It is a button, not a bar. */
body.stagelight .sp-pick-play { align-self:flex-start }

/* ── THE PHONE ────────────────────────────────────────────────────────────────
   The song page had no breakpoint below 1080px. At 390 the hero was still
   running its two-column desktop grid, so the title was laid into a 240px
   column at a 44px minimum size and ran off the right edge; the five-fact rail
   was still grid-auto-flow:column, five abreast in 390px; and the page scrolled
   sideways. Everything below is the phone layout that never existed.

   THE RAIL MATCHES THE HEADER. Under 600px the site header drops to 16px
   gutters and the page rail stayed at 32px, so every card sat inset from the
   hamburger above it. One number, both places. */
@media (max-width: 600px) {
  body.stagelight .sp-rail,
  body.stagelight .sp-hero-in,
  body.stagelight .song-crumbs .sc-in,
  body.stagelight .song-main-full > .song-travels,
  body.stagelight .song-main-full > .song-albums,
  body.stagelight .song-main-full > .song-bestguess,
  body.stagelight .song-main-full > .song-back,
  /* The prev/next pair belongs in this list and was missing from it — the one
     block on the page sitting flush to both screen edges while everything above
     it was inset 16px. */
  body.stagelight .sp-next {
    width: calc(100% - 32px);
    margin-inline: auto;
  }
}

/* Travels With, Appears On, Best Guess and the back link are siblings of the
   rail, not children of it, so they had no width rule at any size — they ran
   the full bleed of the viewport while every card above them sat inside the
   rail. Same width as everything else, at every size. */
body.stagelight .song-main-full > .song-travels,
body.stagelight .song-main-full > .song-albums,
body.stagelight .song-main-full > .song-bestguess,
body.stagelight .song-main-full > .song-back {
  width: min(100% - 64px, var(--sp-rail, 1440px));
  margin-inline: auto;
}
/* The back link belongs at the end of the page, on the side the eye finishes on. */
body.stagelight .song-main-full > .song-back { text-align: right; margin-block: 48px 64px; border-top: 1px solid var(--sl-line); padding-top: 18px; }

@media (max-width: 660px) {
  /* ONE COLUMN, AND THE TITLE LEADS. Alex: the artwork goes on top, right below
     the song title. Title, meta and actions live inside .sp-hero-mid, so the
     sleeve cannot be placed between them without display:contents promoting
     that wrapper's children into the hero grid — which is exactly what it is
     for, and it needs no change to the markup. */
  body.stagelight .sp-hero-in { grid-template-columns: 1fr; gap: 0; padding: 26px 0 30px; align-items: start; }
  body.stagelight .sp-hero-mid { display: contents; }
  body.stagelight .sp-title { order: 1; font-size: clamp(34px, 9.2vw, 46px); }
  body.stagelight .sp-cover,
  body.stagelight .sp-cover-empty { order: 2; width: 100%; margin: 24px 0 0; }
  /* THE PHONE WRAPS INSTEAD OF CLIPPING. This line needs 519px and a 390px phone
     gives it 358, so a nowrap line ended at "…1988 · No." with the badge and the
     words scrolled off inside a hidden sideways scroller. Alex: put the rank on
     its own line and centre it. The separator before the rank goes with it —
     a middot leading a centred line is punctuation pointing at nothing. */
  body.stagelight .sp-meta {
    order: 3; margin-top: 24px;
    flex-wrap: wrap; justify-content: center; text-align: center; row-gap: 6px;
  }
  body.stagelight .sp-meta .sp-rank-inline { flex-basis: 100%; justify-content: center; }
  /* THIS RULE NEVER FIRED, WHICH IS WHY ALEX COULD STILL SEE THE DOT on
     2026-08-06: "Remove the dot after Ain't Life Grand 1994. It's not necessary
     on two lines." :last-of-type counts among SIBLINGS OF THE SAME TAG, and the
     rank that follows the separator is also a <span> — so the last span in the
     line is the rank, not the separator, and the selector matched nothing. The
     intent above was right and only the mechanism was wrong. Once the rank takes
     its own centred line, EVERY separator in this line is punctuation pointing
     at nothing, so they all go. */
  body.stagelight .sp-meta .sp-rank-inline + *,
  body.stagelight .sp-meta .sp-meta-sep { display: none; }
  /* RARITY FOLLOWS THE RANK, WHICH IS WHERE ALEX PUT IT: "Move Common below the
     number Most Played." .sp-hero-mid is display:contents on a phone, so every
     line in the hero is a direct grid item and is placed by `order` alone — an
     element without one takes order:0 and goes to the FRONT. This line shipped
     without one and landed above the song title, which is the opposite end of
     the hero from where it was asked for. It shares .sp-meta's order and follows
     it in the document, which is what puts it directly underneath. */
  body.stagelight .sp-rarity-line { order: 3; justify-content: center; margin-top: 10px; }
  body.stagelight .sp-credit { order: 4; margin-top: 8px; }
  body.stagelight .sp-actions { order: 5; margin-top: 22px; gap: 12px 26px; }
  body.stagelight .sp-actions .sc-chip-primary { flex: 1 1 100%; justify-content: center; height: 48px; font-size: 15px; }
  body.stagelight .sp-actions .sp-jump { font-size: 14px; color: var(--sl-muted); }
  body.stagelight .sp-facts { margin-top: 34px; padding-top: 26px; }
  /* The counted facts, two up. The rail's ≤1080 rule turns it into columns; on a
     phone that is four or five 70px slots side by side, which is unreadable.
     FOUR, not five, is what a phone shows: the rarity row is hidden below 900
     and printed under the rank instead — see the .sp-rarity-line block above. */
  body.stagelight .sp-facts {
    order: 6; grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px 14px; margin-top: 26px; padding-top: 22px;
  }
  body.stagelight .sp-fact-body strong { font-size: 17px; }

  /* The preset cards stack; their thumbnail keeps them from reading as a list. */
  body.stagelight .sp-smart-card { padding: 14px 16px; gap: 12px; }
  body.stagelight .sp-pick-main { padding: 20px; gap: 12px; }
  body.stagelight .sp-era-all { margin-top: 16px; }
  body.stagelight .song-travels { margin-top: 44px; }
}

/* One control at a time: chips on a desktop, the native select on a phone. Both
   ship in the HTML and CSS chooses, so there is no width test in JavaScript to
   fall out of step with this breakpoint. */
body.stagelight .sp-era-select { display: none; }
@media (max-width: 660px) {
  body.stagelight .sp-era-chips { display: none; }
  body.stagelight .sp-era-select { display: block; width: 100%; }
  body.stagelight .sp-era-head { flex-direction: column; align-items: stretch; gap: 16px; }
}

/* ── JAMS AS THE SHELF WATCH CARD ─────────────────────────────────────────────
   A rap that happened once, on one night, that a taper wrote down — the rarest
   fact the page holds, and it was a bordered list row. Now it is the homepage's
   photo card: the night's own picture, the quoted name as the big line. Two
   across; a fifth card turns the row into the same scroll strip the homepage
   uses. */
/* A LITTLE AIR ABOVE THE ROW, and only a little (Alex, 2026-08-06). The
   transitions hub above it ended flush — 0px between the two sections,
   measured — so "Jams, raps and teases" sat on the hub's bottom edge and read
   as part of it. 14px is the smallest gap that separates the two without
   opening a band of empty page between them. */
body.stagelight .sp-jams-region { padding-top: 14px }
body.stagelight .sp-jam-grid { display: grid; grid-template-columns: repeat(var(--sp-jams,2),minmax(0,1fr)); gap: 14px }
body.stagelight .sp-jam-strip {
  display: flex; gap: 14px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: 8px; scrollbar-width: none;
}
body.stagelight .sp-jam-strip::-webkit-scrollbar { display: none }
body.stagelight .sp-jam-strip .sp-jam-card { flex: 0 0 calc((100% - 14px) / 2.12); scroll-snap-align: start }
body.stagelight .sp-jam-card {
  position: relative; display: flex; flex-direction: column; justify-content: flex-end;
  /* TALLER AGAIN, 2026-08-06. 240 -> 320 was the first pass at Alex's "they feel
     like they are short for no reason"; he looked at the result and said the same
     thing about the pair — "short and wide ... doesn't look good". 360 sits just
     above the house scale (.xp-card, the homepage cross-promo pair, is 344) so
     the photograph gets a crop with a body in it rather than a strip. */
  min-height: 360px; border-radius: var(--sl-r-md); overflow: hidden;
  border: 1px solid var(--sl-line); text-align: left; color: var(--sl-ink);
  background: linear-gradient(180deg,rgba(24,24,28,.4),rgba(16,16,20,.3));
  cursor: default; padding: 0;
}
/* ── THE GAP ABOVE THE JAMS HEADLINE ─────────────────────────────────────────
   Alex, 2026-08-06: "reduce the padding above that ... because there's too much
   of it."

   It was two spacings stacked, not one: the transitions hub carries 64px of its
   own bottom padding — which is not decoration, the glow fades out across it —
   and then the section below added the page's own 60px section rhythm on top.
   124px between the hub's last line and this headline on a phone.

   The hub's padding stays and the DUPLICATE goes. Trimming the hub instead would
   have cut the glow's fade off square, which is the exact fault the 08-06 pass
   fixed. Scoped to a section that actually follows the hub, so the page's
   rhythm everywhere else is untouched. */
body.stagelight .sws-preview + section { margin-top: 0 }

/* ── THE JAM CARD JOINS THE PREV/NEXT FAMILY ─────────────────────────────────
   Alex, 2026-08-06: "The previous Jack and Next Little Kin animation is so much
   more beautiful than the one for Jams, Raps, and Teases."

   So it takes .sp-next-card's numbers rather than approximations of them: the
   0.28s ease on transform/shadow/border, the -4px lift (not -2px), the same
   shadow, the same rgba(255,255,255,0.24) hover edge, and the picture scaling
   to 1.05 over 0.5s. Those values trace back to the home page's own .xp-card
   pair, so copying them keeps one gesture across three families instead of
   three near-misses.

   THE CARD KEEPS ITS OWN SHAPE. Only the motion and the affordance are shared —
   its 360px height, its three lines of type and its scrim are the 08-06 taller-
   cards pass and are untouched. Alex asked for the two to feel related, which is
   not the same as identical. */
body.stagelight .sp-jam-card.is-playable {
  cursor: pointer;
  transition: transform .28s ease, box-shadow .28s ease, border-color .28s ease;
}
body.stagelight .sp-jam-card.is-playable:hover {
  transform: translateY(-4px);
  box-shadow: 0 26px 60px -22px rgba(0,0,0,0.85);
  border-color: rgba(255,255,255,0.24);
}
body.stagelight .sp-jam-img { transition: transform .5s ease }
body.stagelight .sp-jam-card.is-playable:hover .sp-jam-img { transform: scale(1.05) }
/* The play mark in a disc, in the corner the prev/next cards put theirs. */
body.stagelight .sp-jam-go {
  position: absolute; right: 20px; bottom: 20px; z-index: 1;
  width: 42px; height: 42px; display: grid; place-items: center; border-radius: 50%;
  border: 1px solid var(--sl-line-strong); background: rgba(11,11,12,.5);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  color: var(--sl-ink);
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
body.stagelight .sp-jam-go svg { width: 13px; height: 15px; margin-left: 2px; display: block }
body.stagelight .sp-jam-card.is-playable:hover .sp-jam-go {
  border-color: var(--sl-ink); color: var(--sl-ink); background: rgba(255,255,255,.06);
}
@media (prefers-reduced-motion: reduce) {
  body.stagelight .sp-jam-card.is-playable,
  body.stagelight .sp-jam-img { transition: none }
  body.stagelight .sp-jam-card.is-playable:hover { transform: none }
  body.stagelight .sp-jam-card.is-playable:hover .sp-jam-img { transform: none }
}
/* THE CROP HOLDS THE FACES. --fx/--fy come from the build, which reads them from
   the same Apple Vision detector that already aims the /watch/ year rail — see
   song-card-focus.json. A card with no detected face keeps the 25% heuristic,
   which is what every card used before and is right for a wide stage shot. The
   taller the card, the more this matters: a 360px crop of a 480px-wide frame
   takes a much narrower slice of the picture than a 240px one did. */
body.stagelight .sp-jam-img { position: absolute; inset: 0; background-size: cover; background-position: var(--fx, 50%) var(--fy, 25%) }
body.stagelight .sp-jam-img::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,9,11,.5) 0%, rgba(9,9,11,.3) 40%, rgba(9,9,11,.9) 100%);
}
/* The right padding clears the play disc in the bottom corner, the same way
   .sp-next-body reserves its right edge for .sp-next-go. Without it the last
   word of a long jam name runs under the button. */
body.stagelight .sp-jam-body { position: relative; display: flex; flex-direction: column; gap: 6px; padding: 22px 78px 20px 24px }
body.stagelight .sp-jam-name { font: 620 22px/1.15 var(--sl-display); letter-spacing: -.015em }
body.stagelight .sp-jam-sub { font: 500 11.5px/1.5 var(--sl-mono); letter-spacing: .05em; text-transform: uppercase; color: var(--sl-muted) }
/* .sp-jam-play is gone with the bare triangle it positioned — see .sp-jam-go. */
@media (max-width:660px) {
  body.stagelight .sp-jam-grid { grid-template-columns: 1fr }
  body.stagelight .sp-jam-strip .sp-jam-card { flex-basis: 86% }
  body.stagelight .sp-bento-top .sp-bento-card { min-height: 170px }
  body.stagelight .sp-jam-card { min-height: 300px }
  /* THE STACKED FLOOR MOVED OUT OF HERE on 2026-08-07 and now sits beside the
     grid rule, unqualified, so that the 660-900px band gets it too — that band
     is already one column and had no floor at all, which left a two-card page
     with an empty lyric card sitting at 120px between a phone that floored at
     330 and a desktop that floored at 362. The 2026-08-06 reasoning is intact
     up there: a floor tall enough for four lines of 18.5/1.75 type plus the
     name and the fact rule, so a lyric card, a quote of unknown length and a
     card holding only a drawing agree instead of reading as three unrelated
     blocks. Nothing about the stacked case changed; it just starts sooner. */
}

/* ── THE SEGUE ROW ────────────────────────────────────────────────────────────
   Alex, after three diagram passes failed: "default to simplicity." His mock,
   built as drawn: three names in one row with two of Garrie's arrows between
   them, then two plain columns of the other partners, the setlist ">" carrying
   direction. Flexbox owns the layout — there is no measuring, no absolute
   positioning, and nothing that can strike through a title. */
body.stagelight .sp-seg-graph { margin-top:clamp(28px,4vw,56px) }
body.stagelight .sp-seg-graph a { text-decoration:none; color:var(--sl-ink) }
body.stagelight .sp-seg-line {
  display:flex; align-items:center; justify-content:space-between;
  gap:clamp(14px,2.4vw,36px);
}
body.stagelight .sp-seg-center {
  font:700 clamp(40px,4.8vw,72px)/1.02 var(--sl-display); letter-spacing:-.025em;
  text-align:center; max-width:5.6em; text-wrap:balance; flex:0 1 auto;
}
body.stagelight .sp-seg-anchor { display:block; max-width:240px; flex:0 1 auto }
body.stagelight .sp-seg-anchor[data-seg-slot="in"] { text-align:right }
body.stagelight .sp-seg-anchor[data-seg-slot="out"] { text-align:left }
body.stagelight .sp-seg-anchor b {
  display:block; font:640 clamp(26px,2.6vw,40px)/1.1 var(--sl-display); letter-spacing:-.02em; text-wrap:balance;
}
body.stagelight .sp-seg-anchor span,
body.stagelight .sp-seg-sat span {
  display:block; margin-top:6px; font:400 14px/1.45 var(--sl-body, inherit); color:var(--sl-muted);
}

/* Garrie's arrow — the homepage separator's right half, same ink, same pacing. */
body.stagelight .sp-seg-arrow { flex:1 1 0; min-width:90px; max-width:230px; height:auto; overflow:visible }
body.stagelight .sp-seg-arrow path { fill:none; stroke:rgba(255,255,255,.6); stroke-linecap:round; stroke-linejoin:round; vector-effect:non-scaling-stroke }
body.stagelight .sp-seg-arrow .ln { stroke-width:2.2 }
body.stagelight .sp-seg-arrow .press { stroke-width:2.35; stroke:rgba(255,255,255,.34) }
body.stagelight .sp-seg-arrow path { opacity:0 }
body.stagelight .sp-seg-arrow.is-inked path { opacity:1 }
body.stagelight .sp-seg-arrow.anim .l2 { opacity:1; stroke-dasharray:300; stroke-dashoffset:300; animation:seg-draw 520ms cubic-bezier(.45,.05,.4,1) calc(var(--seg-i,0) * 700ms) forwards }
body.stagelight .sp-seg-arrow.anim .press { animation:seg-ink 200ms linear calc(var(--seg-i,0) * 700ms + 300ms) forwards }
body.stagelight .sp-seg-arrow.anim .ah2 { opacity:1; stroke-dasharray:34; stroke-dashoffset:34; animation:seg-draw 180ms cubic-bezier(.5,.05,.35,1.06) calc(var(--seg-i,0) * 700ms + 500ms) forwards }
@keyframes seg-draw { to { stroke-dashoffset:0 } }
@keyframes seg-ink { to { opacity:1 } }
@media (prefers-reduced-motion: reduce) {
  body.stagelight .sp-seg-arrow path { opacity:1; animation:none }
}

/* The other partners: two quiet columns, the mark doing the pointing. */
body.stagelight .sp-seg-others {
  display:grid; grid-template-columns:1fr 1fr; gap:18px clamp(40px,6vw,120px);
  margin-top:clamp(36px,4.6vw,60px); padding-inline:clamp(0px,6vw,110px);
}
body.stagelight .sp-seg-col { display:grid; gap:22px; align-content:start }
body.stagelight .sp-seg-sat { display:block; opacity:.85; transition:opacity 160ms var(--bt-out, ease) }
body.stagelight .sp-seg-sat:hover, body.stagelight .sp-seg-sat:focus-visible { opacity:1 }
body.stagelight .sp-seg-sat b { font:600 19px/1.25 var(--sl-display); letter-spacing:-.012em; display:block }
body.stagelight .sp-seg-sat span { font-size:13.5px }
body.stagelight .sp-seg-mark { font-style:normal; color:var(--sl-faint) }
body.stagelight .sp-seg-sat:hover .sp-seg-mark { color:var(--sl-ink) }

/* The list is the phone, the no-JS fallback, and every song below the floor. */
body.stagelight .sp-seg.has-graph .sp-seg-fallback { display:none }
body.stagelight .sp-seg-tw { margin-top:30px }
@media (max-width:900px) {
  body.stagelight .sp-seg-graph { display:none }
  body.stagelight .sp-seg.has-graph .sp-seg-fallback { display:block }
}

/* ── THE ERA STAGE ────────────────────────────────────────────────────────────
   Alex's shape, stated at the outset and rebuilt here after a wrong turn: "the
   feature card off to the left and the other cards stack vertically to its right
   so they can tap in and load a new feature card."

   What this replaces: a featured pick with the four presets in a row UNDERNEATH
   it, plus — on Space Wrangler only — a pager stepping one-at-a-time through 744
   recordings with "1 of 744" printed beside it. The pager is gone, the count is
   gone, and the presets stopped being a second row asking the same question the
   player was already asking.

   The transport sits directly above the progress bar because that is where the
   homepage player puts it, and Alex asked for the two to match. */
body.stagelight .sp-era-stage {
  display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(300px, 1fr);
  gap: 18px; align-items: stretch; margin-top: 26px;
}
body.stagelight .sp-era-stage.sp-era-wide { grid-template-columns: minmax(0, 1fr); }

body.stagelight .sp-stage {
  position: relative; overflow: hidden; min-height: clamp(360px, 42vw, 520px);
  border: 1px solid var(--sl-line); border-radius: var(--sl-r); background: var(--sl-glass);
}
/* TWO LAYERS, ONE BOX. Both stage pictures sit in the same absolute frame, so
   the incoming one can be faded up over the outgoing one instead of the single
   layer dipping to transparent and back — which is a flicker, not a swap. The
   script owns z-index and opacity; all this declares is how long the fade takes.
   200ms is the same beat the rest of the page's state changes use.
   The scrim above them has its own stacking context via position:absolute later
   in the source, so it stays over both layers whichever one is on top. */
body.stagelight .sp-stage-art {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: opacity 200ms linear;
}
/* Stillness kills the fade and keeps the wait: the script still holds the old
   frame until the new picture has decoded, which is not an animation. */
@media (prefers-reduced-motion: reduce) {
  body.stagelight .sp-stage-art { transition: none; }
}
/* THE SCRIM IS EXPLICITLY ABOVE BOTH PICTURES. It used to rely on being later
   in the source than the single <img>, which stops being true the moment the
   crossfade raises the incoming layer — an un-scrimmed photograph would flash
   under the night's name for the length of the fade. The transport moves up
   with it so the text stays above the scrim. */
body.stagelight .sp-stage-scrim {
  position: absolute; inset: 0; z-index: 2;
  background: linear-gradient(180deg, rgba(8,8,10,.10) 18%, rgba(8,8,10,.90) 100%);
}
/* THE NIGHT'S NAME IS THE PLAYER'S LABEL, so it is bottom-left inside the
   transport rather than a separately pinned block above it (Alex, 2026-08-06:
   "Why isn't the player text anchored to the bottom left above the player
   bar?"). It used to sit 133px off the floor with a 90px band of bare
   photograph between it and the scrubber — measured, not guessed — which is
   what made it read as floating at mid-height. It is a grid cell now; the
   positioning below belongs to .sp-stage-transport. */
body.stagelight .sp-stage-copy { min-width: 0; z-index: 1; }
body.stagelight .sp-stage-copy h3 { font: 500 13px/1.25 var(--sl-body); color: var(--sl-muted); }
/* VENUE ON ONE LINE, CITY ON THE NEXT, both left aligned. A long venue and a
   long city on one centred line wrapped wherever it ran out of room — "at The
   Wharf / Amphitheater" split a venue name in half. Two spans, two lines, and
   the break always falls between the two facts instead of inside one. */
body.stagelight .sp-stage-copy p {
  margin: 5px 0 0; color: var(--sl-ink); text-align: left;
  font: 650 clamp(24px, 2.5vw, 36px)/1.1 var(--sl-display); letter-spacing: -.025em;
}
body.stagelight .sp-stage-copy p span { display: block; }
body.stagelight .sp-stage-copy [data-stage-city] { color: var(--sl-muted); font-size: .74em; font-weight: 560; margin-top: 2px; }

/* ONE BOTTOM-PINNED GRID, THE SAME ONE EVERY OTHER PLAYER FACE ON THE SITE USES.
   .media-stage-player on a show page is `minmax(0,1fr) auto` with items aligned
   to the end and the timeline spanning both columns: the night's name bottom
   left, the controls bottom right, the bar under the pair. This is that grid,
   column for column, so the two faces compose alike instead of alike-ish. */
body.stagelight .sp-stage-transport {
  position: absolute; left: 32px; right: 32px; bottom: 26px; z-index: 3;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: end; gap: 14px 24px;
}
/* THE CONTROLS SIT BOTTOM-RIGHT, above the bar (Alex, 2026-08-05). Centred, they
   floated in the middle of the photograph with nothing to align to; on the right
   they sit over the quietest corner of the frame and stack with the bar's end.
   The row gap above places them now, so the old margin would double it. */
body.stagelight .sp-stage-controls { display: flex; align-items: center; justify-content: flex-end; gap: 16px; }
body.stagelight .sp-tbtn {
  width: 38px; height: 38px; display: grid; place-items: center; border-radius: 50%;
  border: 1px solid var(--sl-line-strong); background: rgba(10,10,12,.55);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  color: var(--sl-ink); cursor: pointer; transition: background .16s, color .16s;
}
body.stagelight .sp-tbtn:hover { background: var(--sl-ink); color: #111; border-color: var(--sl-ink); }
body.stagelight .sp-tbtn-play { width: 54px; height: 54px; background: var(--sl-ink); color: #111; border-color: var(--sl-ink); }
body.stagelight .sp-stage-bar { grid-column: 1 / -1; display: flex; align-items: center; gap: 12px; font: 500 12px/1 var(--sl-mono); color: var(--sl-muted); }
/* THE SCRUBBER WAS THE BROWSER'S, NOT THE SITE'S — a blue fill on a white track,
   the one piece of stock UI on a page of drawn controls (Alex, 2026-08-06). It
   was the only range input on burnthday.com that never had `appearance:none`,
   so every house rule below simply never applied to it.
   These values are .listen-scrubber's, copied rather than re-picked: 4px track,
   white fill to --progress and rgba(255,255,255,.32) after it, a 14px white
   thumb with the same shadow. Both engines get their own pseudo-elements —
   WebKit takes one gradient track, Firefox needs the track and ::-moz-range-
   progress as two separate paints, and skipping either is how a scrubber ends
   up styled in one browser and blue in the other.
   --progress is set by the era script on load, on every stage repaint, and on
   each song-player:progress tick; the fallback keeps the track flat rather than
   full if a paint ever runs before the first tick. */
body.stagelight .sp-stage-scrubber {
  --progress: 0%; flex: 1; min-width: 0;
  appearance: none; -webkit-appearance: none;
  height: 24px; margin: 0; background: transparent; cursor: pointer; touch-action: none;
}
body.stagelight .sp-stage-scrubber::-webkit-slider-runnable-track { height: 4px; border-radius: 99px; background: linear-gradient(90deg, var(--sl-ink) var(--progress), rgba(255,255,255,0.32) var(--progress)); }
body.stagelight .sp-stage-scrubber::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; margin-top: -5px; border: 0; border-radius: 50%; background: var(--sl-ink); box-shadow: 0 1px 5px rgba(0,0,0,0.4); }
body.stagelight .sp-stage-scrubber::-moz-range-track { height: 4px; border-radius: 99px; background: rgba(255,255,255,0.32); }
body.stagelight .sp-stage-scrubber::-moz-range-progress { height: 4px; border-radius: 99px; background: var(--sl-ink); }
body.stagelight .sp-stage-scrubber::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: var(--sl-ink); }
body.stagelight .sp-stage-scrubber:focus-visible { outline: 2px solid var(--sl-ink); outline-offset: -2px; }

/* The presets: photograph behind, one bold sentence over it, the mark that says
   which kind of night this is. No tiny grey line — Alex: "I hate the tiny little
   text btw you should remove that tiny text." */
body.stagelight .sp-presets { display: grid; grid-template-rows: repeat(auto-fit, minmax(0, 1fr)); gap: 12px; }
/* ── THE MINI STAGE-CARD — ALEX'S PICK, VARIANT B OF FOUR (2026-08-06) ──────
   "B, remove the left border, remove the icon."
   The night's photograph runs edge to edge BEHIND the card with the site's own
   scrim over it; the facts sit on top as three lines. The 08-05 objection to
   photo cards — four backgrounds, four contrasts, one white text — is answered
   by STATE, not by removing the pictures: the three cards not playing are
   dimmed (art at .52, desaturated, heavy left-weighted scrim) so they read as
   one quiet set, and only the card that IS playing comes up to full colour
   under a thinner scrim with a "Now playing" tag. The difference between
   playing and not is the composition.
   Removed at his word: the 3px lit rule variant B drew down the selected edge,
   and the kind-mark disc — the side-label words carry the kind by themselves. */
body.stagelight .sp-preset {
  position: relative; overflow: hidden; cursor: pointer; text-align: left;
  padding: 0; border: 1px solid var(--sl-line); border-radius: var(--sl-r-md);
  background: rgba(255,255,255,.028); color: var(--sl-ink);
  transition: border-color .18s;
}
/* NO DIMMING (Alex, same day: "dont dim the background of the non active either
   just add the outline that's fine"). Every card wears its photograph at full
   strength; the ONE heavy scrim on all four is what keeps the words readable —
   uniform treatment means uniform contrast, which is what the 08-05 objection
   was actually about. Selection is the lit outline and the Now-playing tag,
   nothing else. */
body.stagelight .sp-preset-art {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: var(--fx, 50%) var(--fy, 32%);
}
body.stagelight .sp-preset-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(9,9,11,.92) 0%, rgba(9,9,11,.74) 46%, rgba(9,9,11,.46) 100%);
}
body.stagelight .sp-preset-body { position: relative; z-index: 1; display: block; padding: 13px 18px; }
body.stagelight .sp-preset-side {
  display: block; font: 600 10px/1 var(--sl-mono); letter-spacing: .16em;
  text-transform: uppercase; color: var(--sl-faint);
}
body.stagelight .sp-preset-head {
  display: block; margin-top: 6px;
  font: 650 19px/1.06 var(--sl-display); letter-spacing: -.02em; color: var(--sl-ink);
}
body.stagelight .sp-preset-where { display: block; margin-top: 3px; font-size: 12.5px; color: var(--sl-muted); }
body.stagelight .sp-preset:hover { border-color: var(--sl-line-strong); }
body.stagelight .sp-preset.is-current {
  border-color: rgba(242,242,240,.52);
  box-shadow: 0 0 0 1px rgba(242,242,240,.2);
}
/* The tag only the playing card wears. With the kind-mark gone it takes the
   right edge on its own. */
body.stagelight .sp-preset-now {
  display: none; position: absolute; right: 16px; top: 50%; translate: 0 -50%; z-index: 2;
  font: 600 9.5px/1 var(--sl-mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--sl-ink); border: 1px solid rgba(242,242,240,.4); border-radius: 999px;
  padding: 5px 9px; background: rgba(11,11,12,.5);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
body.stagelight .sp-preset.is-current .sp-preset-now { display: block; }
body.stagelight .sp-tbtn svg { width: 16px; height: 16px; display: block; }
body.stagelight .sp-tbtn-play svg { width: 15px; height: 17px; margin-left: 1px; }

/* THE PHONE STACKS: player first, then the presets under it. */
@media (max-width: 900px) {
  body.stagelight .sp-era-stage { grid-template-columns: 1fr; }
  /* The copy block no longer positions itself — it is a cell of the transport
     grid, so the phone gutter is set once, on the thing that owns the edges. */
  body.stagelight .sp-stage-transport { left: 20px; right: 20px; }
}

/* ── KEEP BROWSING ────────────────────────────────────────────────────────────
   The last thing on the page, per Alex's section order — transitions hand you to
   the next song, and this is where you take it. Two cards in his screenshot's
   language: the picture, the name, a circular arrow that moves on hover. */
/* ONE GUTTER, THIS BLOCK INCLUDED. Alex, 2026-08-06: "The Fishwater video and
   the Jack and Little Kin boxes are not carrying the same gutter on the left.
   Everything needs the same gutter on the page."

   He is right and it was never only a phone fault: this section is emitted in
   <main> rather than inside .sp-rail, and it carried no width of its own, so it
   ran the full bleed at EVERY width — measured L0/R1440 against the rail's
   L32/R1408 on desktop, and L0/R375 against L16/R359 on a phone. Every other
   block on the page was already inset and this one alone was not, which is
   exactly what makes a page look untidy without looking obviously broken.
   It now takes the rail's own width expression, the same one .sp-rail and the
   crumbs use, at both breakpoints. */
body.stagelight .sp-next {
  margin-top: clamp(56px, 6vw, 96px);
  width: min(1440px, calc(100% - 64px));
  margin-inline: auto;
}
/* THE PHONE GUTTER IS REPEATED HERE ON PURPOSE. The page's own 600px block sets
   it for every other block, but it sits ~400 lines ABOVE this rule and a media
   query adds no specificity — so the desktop width above would have won at 375px
   and put this block on a 32px gutter while the rail beside it used 16px. Which
   is the same fault Alex reported, moved four pixels. Stated next to the rule it
   overrides, where it cannot lose. */
@media (max-width: 600px) {
  body.stagelight .sp-next { width: calc(100% - 32px); }
}
body.stagelight .sp-next-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 22px; }
/* MATCHED TO THE HOME PAGE'S OWN PAIR. Alex, 2026-08-06: "make sure the
   animations hover button etc everything matches the two cards at the bottom of
   the home page that port into lyics and song meaning" — that is .cross-promo's
   two .xp-card links (Song Origins and Lyrics & Chords). Their numbers, copied
   rather than approximated: box-shadow from the token, a 0.28s ease transition
   on transform/shadow/border, a -4px lift, border rgba(255,255,255,0.24) on
   hover, and the picture scaling to 1.05 over 0.5s. */
body.stagelight .sp-next-card {
  position: relative; display: block; overflow: hidden; text-decoration: none;
  /* 220 was the "short and wide" one Alex named. 300 is meaningfully taller and
     deliberately NOT the jam cards' 360 — he asked for the two families to feel
     related, not identical, and these carry one line of type where a jam card
     carries three. */
  min-height: 300px; border: 1px solid var(--sl-line); border-radius: var(--sl-r);
  background: rgba(255,255,255,.032); color: var(--sl-ink);
  box-shadow: var(--sl-glass-shadow); isolation: isolate;
  transition: transform .28s ease, box-shadow .28s ease, border-color .28s ease;
}
body.stagelight .sp-next-card:hover {
  transform: translateY(-4px); box-shadow: 0 26px 60px -22px rgba(0,0,0,0.85);
  border-color: rgba(255,255,255,0.24);
}
body.stagelight .sp-next-card:hover .sp-next-art { transform: scale(1.05); }
body.stagelight .sp-next-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--fx, 50%) var(--fy, 50%); transition: transform .5s ease; }
body.stagelight .sp-next-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,9,11,.30) 0%, rgba(9,9,11,.62) 58%, rgba(9,9,11,.90) 100%);
}
body.stagelight .sp-next-body { position: absolute; left: 24px; right: 84px; bottom: 22px; }
body.stagelight .sp-next-side {
  display: block; font: 600 11px/1 var(--sl-mono); letter-spacing: .16em;
  text-transform: uppercase; color: var(--sl-faint);
}
body.stagelight .sp-next-title {
  display: block; margin-top: 8px; text-wrap: balance;
  font: 650 clamp(22px, 2vw, 30px)/1.1 var(--sl-display); letter-spacing: -.02em;
}
body.stagelight .sp-next-go {
  position: absolute; right: 24px; bottom: 24px; width: 42px; height: 42px;
  display: grid; place-items: center; border-radius: 50%;
  border: 1px solid var(--sl-line-strong); background: rgba(11,11,12,.5);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transition: background .2s var(--bt-out, ease), color .2s var(--bt-out, ease), transform .2s var(--bt-out, ease);
}
body.stagelight .sp-next-go svg { width: 17px; height: 17px; }
/* The same hover the home page gives its open affordance: the button lights to
   ink and the chevron takes a quarter turn left. It used to slide 3px right and
   invert to a white disc, which is a different gesture from the rest of the site. */
body.stagelight .sp-next-go svg { transition: transform .28s ease; }
body.stagelight .sp-next-card:hover .sp-next-go { border-color: var(--sl-ink); color: var(--sl-ink); background: rgba(255,255,255,.06); }
body.stagelight .sp-next-card:hover .sp-next-go svg { transform: rotate(-90deg); }
/* ALL SONGS, hung off the grid's right edge — under the right card's corner. */
body.stagelight .sp-next-all { margin: 16px 0 64px; text-align: right; }
body.stagelight .sp-next-all a {
  font: 600 11px/1 var(--sl-mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--sl-faint); text-decoration: none; transition: color .2s ease;
}
body.stagelight .sp-next-all a:hover { color: var(--sl-ink); }
@media (prefers-reduced-motion: reduce) {
  body.stagelight .sp-next-card, body.stagelight .sp-next-art, body.stagelight .sp-next-go svg { transition: none; }
  body.stagelight .sp-next-card:hover { transform: none; }
  body.stagelight .sp-next-card:hover .sp-next-art { transform: none; }
  body.stagelight .sp-next-card:hover .sp-next-go svg { transform: none; }
}
@media (max-width: 660px) {
  body.stagelight .sp-next-grid { grid-template-columns: 1fr; }
  body.stagelight .sp-next-card { min-height: 168px; }
  body.stagelight .sp-next-body { left: 20px; right: 76px; bottom: 18px; }
}
