
    /* --ar-glint / --ar-leadin are the tie-dye at reading volume: they carry
       alpha and fade to nothing at their edges, so a slice painted over the
       ordinary setlist ink blends instead of cutting a hard band out of a word. */
    /* Registered so they can be INTERPOLATED. A plain custom property is an
       untyped token to the engine: it flips from one string to the other with no
       in-between, which is exactly the snap the rail used to do. Declaring the
       type is what buys the tween. */
    @property --rail-w{syntax:"<length>";initial-value:232px;inherits:false}
    @property --rail-gap{syntax:"<length>";initial-value:40px;inherits:false}
    :root{--ar-tie:linear-gradient(100deg,#d4514f 0%,#e0574f 24%,#60a5d2 58%,#c9a35f 88%);
      
      --ar-leadin:linear-gradient(90deg,rgba(212,81,79,.5) 0%,rgba(224,87,79,.34) 55%,rgba(96,165,210,0) 100%)}
    body.listen-archive{background:var(--sl-bg,#090a0d)}
    /* COLLAPSING IS AN ANIMATION OF LAYOUT, NOT A DISPLAY TOGGLE.
       It used to snap: grid-template-columns went to 0 and the rail's children
       went display:none in the same frame, so the canvas jumped sideways into
       the space. Now a REGISTERED custom property carries the width, which is
       what makes it interpolable — an unregistered var would jump between two
       token strings the way the old rule did. The gap rides the same curve, so
       the canvas glides rather than steps. ~240ms on an ease-out, which is the
       length these sidebars run at everywhere they feel good. */
    /* D5 (Alex): the gutter right of the sticky rail was clamp(28,4vw,64) —
       ~58px at 1440, real estate the photograph and the setlist wanted. */
    .ar-shell{display:grid;--rail-w:232px;--rail-full:232px;--rail-gap:clamp(22px,2.2vw,36px);grid-template-columns:var(--rail-w) minmax(0,1fr);gap:var(--rail-gap);width:min(1400px,calc(100% - 56px));margin:0 auto;padding:26px 0 120px;align-items:start;
      transition:--rail-w .24s cubic-bezier(.22,1,.36,1),--rail-gap .24s cubic-bezier(.22,1,.36,1)}
    .ar-main{min-width:0}
    /* D4 (Alex): the canvas is a <main>, so the site's global
       main-element width rule (min 1400px / 100% - 56px, auto margins) was boxing it INSIDE
       its own grid column — 28px of dead margin each side, so the content
       stopped short of the hamburger's gutter. The shell already owns the page
       gutter; the canvas fills its column and the right edge now lines up with
       the header's right edge on every /listen/ page. */
    .ar-canvas{width:100%;max-width:none;margin:0}

    /* ---- the rail ----
       One vertical scroll for the whole rail below the search field — years and
       eras expand INLINE and push the sections below them; nothing nests a
       second scrollbar inside the first. overflow-x is locked to hidden and no
       child uses negative margins, which is what allowed the old rail to pan
       sideways and clip its icons. */
    .ar-cabinet{position:sticky;top:78px;display:flex;flex-direction:column;max-height:calc(100vh - 102px);min-width:0}
    /* The rail column itself never scrolls sideways while it animates — the
       clipping is .ar-cab-body's job, and a scrollbar appearing for one frame
       mid-collapse is exactly the flash we are avoiding. */
    .ar-cabinet{overflow:visible}
    /* SAME FAMILY AS THE RAIL (Alex, 7/28: it "doesn't match the vibe").
       It was the boldest-bordered object in the sidebar — --sl-line-strong at
       rest, which this system reserves for hover and active states — while being
       the one passive thing in it. Now it rests on the ordinary hairline like
       the cards do, takes the strong one on hover, and only goes bright on
       focus. Radius 12 matches .ar-songcard / .ar-placecard; the type matches the
       nav rows it sits above rather than running a size of its own. */
    /* The drawer header exists only when the rail IS a drawer. On the desktop
       rail the collapse handle is the affordance and an X would mean something
       different (close vs. hide), so it is not drawn there at all. */
    .ar-drawer-head{display:none}
    .ar-cab-search{display:flex;align-items:center;gap:9px;flex:none;margin-bottom:8px;padding:0 12px;border:1px solid var(--sl-line);border-radius:12px;background:rgba(255,255,255,.035);transition:border-color .16s,background .16s}
    .ar-cab-search:hover{border-color:var(--sl-line-strong);background:rgba(255,255,255,.05)}
    .ar-cab-search:focus-within{border-color:rgba(255,255,255,.42);background:rgba(255,255,255,.06)}
    .ar-cab-search svg{width:15px;height:15px;flex:none;color:var(--sl-faint,#6b6f78);transition:color .16s}
    .ar-cab-search:focus-within svg{color:var(--sl-muted)}
    /* 16px exactly (M1): anything smaller and iOS zooms the whole page on
       focus — this input rides inside the mobile drawer, so it was zooming the
       menu itself. */
    .ar-cab-search input{flex:1;min-width:0;height:40px;border:0;background:none;color:var(--sl-ink);font:500 16px/1 var(--sl-display)}
    .ar-cab-search input:focus{outline:none}
    .ar-cab-search input::placeholder{color:var(--sl-faint,#6b6f78)}
    .ar-cab-search input::-webkit-search-cancel-button{filter:invert(1);opacity:.4}
    .ar-cab-scroll{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.14) transparent}
    .ar-cab-scroll::-webkit-scrollbar{width:3px}
    .ar-cab-scroll::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:3px}
    /* Sections separate with quiet rules, not heavy headings. */
    .ar-cab-section{padding:14px 0 12px;border-bottom:1px solid var(--sl-line,rgba(255,255,255,.08))}
    .ar-cab-section:last-of-type{border-bottom:0}
    /* Two section labels remain (Browse, Featured Shows, Resources) and they now
       have to look chosen rather than left over, since the top group has none.
       Slightly larger, slightly less tracked, and more air under them. */
    .ar-cab-label{margin:0 0 10px;color:var(--sl-faint,#6b6f78);font:600 11px/1 var(--sl-mono);letter-spacing:.15em;text-transform:uppercase}
    .ar-cab-group{display:grid;gap:1px}
    /* The primary destinations. No eyebrow above them — they are the first thing
       in the panel, which is the only introduction they need. */
    .ar-cab-top{margin-bottom:4px}
    .ar-cab-primary{gap:2px}
    .ar-cab-onlymobile{display:none}
    /* RAIL TYPE SCALE — one step up across the board (Alex, 7/28: it read like
       fine print beside the canvas). The HIERARCHY is unchanged: nav rows are
       still the largest thing in the rail, the year/era sub-lists sit a step
       under them, Featured Shows a step under that, the footer smallest. Every
       size moved together so the relationships hold. */
    .ar-cab-group a,.ar-cab-group button{display:flex;align-items:center;gap:12px;padding:9px 9px;border:0;border-radius:9px;background:none;color:var(--sl-muted);font:500 16.5px/1.35 var(--sl-display);text-align:left;cursor:pointer;transition:color .16s,background .16s}
    .ar-cab-group svg{width:17px;height:17px;flex:none;opacity:.62;transition:opacity .16s}
    .ar-cab-group a:hover svg,.ar-cab-group button:hover svg,.ar-cab-group a.is-active svg{opacity:1}
    .ar-cab-group a:hover,.ar-cab-group button:hover,.ar-cab-group a:focus-visible,.ar-cab-group button:focus-visible{color:var(--sl-ink);background:rgba(255,255,255,.05)}
    .ar-cab-group a.is-active{color:var(--sl-ink);background:rgba(255,255,255,.06)}
    .ar-cab-resources a{font-size:15.5px}
    /* The credit used to strand a single word on its own last line. A slightly
       tighter measure plus text-wrap:pretty (which browsers that have it use to
       avoid exactly this orphan) settles it, and the copyright underneath turns a
       floating sentence into a footer that looks intended. */
    .ar-cab-foot{margin:18px 0 4px;padding:0 8px;max-width:24ch;color:var(--sl-faint,#6b6f78);font-size:12.5px;line-height:1.55;text-wrap:pretty}
    /* The "© 2026 Burnthday" line is gone (Alex, 7/28 — he didn't like the
       look). Deleted rather than left describing markup that no longer exists.
       The Internet Archive attribution stays: it is a credit we owe, not chrome. */
    .ar-cab-foot a{color:inherit;text-decoration:underline;text-underline-offset:2px}
    .ar-cab-foot a:hover{color:var(--sl-ink)}

    /* ---- featured shows: city + date, nothing else ---- */
    .ar-featured-list{display:grid;gap:2px}
    .ar-feat{display:flex;align-items:center;gap:10px;padding:5px 8px;border-radius:8px;color:inherit;transition:background .16s}
    .ar-feat:hover,.ar-feat:focus-visible{background:rgba(255,255,255,.05)}
    .ar-feat-art{flex:none;width:31px;height:31px;border-radius:50%;overflow:hidden;border:1px solid var(--sl-line,rgba(255,255,255,.14));background:radial-gradient(120% 130% at 28% 14%,hsl(var(--tone,210) 50% 30%/.9),transparent 62%),linear-gradient(160deg,#161a23,#0b0c10);background-size:cover;background-position:center 30%}
    .ar-feat-body{min-width:0}
    .ar-feat-body strong{display:block;font:600 14.5px/1.25 var(--sl-display);letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .ar-feat-body span{display:block;margin-top:2px;color:var(--sl-faint,#6b6f78);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

    /* ---- collapse: a circle on the boundary, like a drawer handle ----
       Collapsed hides the rail entirely — no icon totem pole — and leaves the
       same circle floating at the page edge to bring it back. */
    /* OFF THE SEARCH FIELD (Alex, 7/28). At top:4px it sat in the same 40px band
       as the input and read as a control belonging to it — two unrelated things
       crowding one corner. It drops below the field, onto the boundary beside
       the first nav group, where "drawer handle" is the only thing it can mean.
       It rides the animating edge rather than jumping to it, and the chevron
       turns to say which way the rail will go. */
    /* THE CONTENTS DO NOT SQUASH. .ar-cab-body is pinned to the rail's FULL
       width and clipped by the shrinking column, so every row keeps its own
       measure the whole way — nothing re-wraps mid-animation, which is the tell
       that gives a cheap sidebar away. The handle is deliberately NOT inside
       this wrapper: it hangs off the rail's edge and must not be clipped with
       the rest.
       The fade runs AHEAD of the width on the way out (120ms, no delay) and
       BEHIND it on the way back (90ms delay), so you never see text sliding
       under its own edge in either direction. */
    /* M7 (Alex): only the left half of the drawer scrolled — the body was
       still pinned to the old rail's 232px (collapse-era shrapnel; the handle
       is deleted). It now fills whatever holds it: the rail column on
       desktop, the full drawer panel on mobile. */
    .ar-cab-body{display:flex;flex-direction:column;min-height:0;flex:1;width:auto;overflow:hidden}
    @media(prefers-reduced-motion:reduce){
      .ar-shell,.ar-cab-body{transition:none}
    }
    /* The handle used to switch to position:fixed at a hard-coded corner the
       moment the class landed, which TELEPORTED it — and its flight path crossed
       the search field's band on the way. It now simply stays where it is: an
       absolute child of the (sticky) rail, riding the animating edge down to
       x=15 on its own. Same resting place, no jump, and it is never anywhere
       near the search box at any point in the animation. */
    /* ---- shared ---- */
    .ar-kicker{margin:0 0 12px;color:var(--sl-muted);font:600 10.5px/1.2 var(--sl-mono);letter-spacing:.2em;text-transform:uppercase}
    .ar-canvas h1{margin:0;font:700 clamp(40px,6.2vw,88px)/.92 var(--sl-display);letter-spacing:-.04em}
    .ar-hero-sub{margin:16px 0 0;color:var(--sl-muted);font-size:15px}
    .ar-head{display:flex;justify-content:space-between;align-items:baseline;gap:18px;margin-bottom:20px;padding-bottom:12px;border-bottom:1px solid var(--sl-line,rgba(255,255,255,.1))}
    .ar-head h2{margin:0;font:650 clamp(21px,2.4vw,29px)/1 var(--sl-display);letter-spacing:-.02em}
    .ar-head span,.ar-head a{color:var(--sl-muted);font:500 11px/1 var(--sl-mono);letter-spacing:.08em;text-transform:uppercase}
    /* The 'More' / 'All' links were an 11px line of type and therefore an 11px
       TAP TARGET — a third of the 44px thumb minimum, on the one control that
       moves you between archive views. Padding gives them a real hit area
       without moving the type: the negative margin keeps the baseline aligned
       with the heading exactly as before. */
    .ar-head a{display:inline-block;padding:12px 0;margin:-12px 0;min-height:0}
    .ar-head a:hover{color:var(--sl-ink)}
    /* PRE-DEPLOY SWEEP (2026-07-28). These section links — "More", "All" — were
       30x11 and 22x11 on a phone: real destinations rendered at a size no thumb
       can reliably hit. An invisible ::after halo gives them a 44px field without
       moving the label a pixel or disturbing the baseline the row is aligned on
       (padding would have pushed the rule below it out of line). */
    .ar-head a{position:relative}
    .ar-head a::after{content:"";position:absolute;z-index:1;left:50%;top:50%;width:max(100%,64px);height:44px;transform:translate(-50%,-50%)}
    /* The canvas IS a <main>, so the site-wide main > section rule (96px)
       landed on its FIRST section too — 96px of nothing above every view, stacked
       on the shell's own padding, once search moved out of the canvas and into the
       rail. The first section starts at the top; the rhythm between sections is
       unchanged. */
    .ar-canvas>section:first-child,body.listen-archive .ar-canvas>section:first-child{margin-top:0}
    /* M2 (Alex): the canvas renders client-side, so for a beat the page was
       header + footer with nothing between — the footer painted first and got
       shoved down when the view arrived, a full-viewport layout shift. An
       empty canvas now reserves a viewport of height, so the footer starts
       below the fold and the arriving view replaces space instead of taking
       it. */
    .ar-canvas[aria-busy="true"]{min-height:100dvh}
    /* THE CRAWLER LINE WAS RENDERING AS AN 88px BILLBOARD. .ar-seo-h1 asks for
       a 20-26px line, but '.ar-canvas h1' — the archive's own view title, the
       one that sets 1997 in 88px display type — is a class AND an element and
       therefore out-ranks a lone class. So the shell's SEO heading has always
       been painted at view-title scale: two enormous lines that fill the screen
       before the app arrives. Naming both wins the cascade honestly, at the
       same weight, instead of reaching for !important. Crawlers and no-script
       clients now get the modest heading the markup always intended. */
    .ar-canvas h1.ar-seo-h1{font:650 clamp(20px,2.2vw,26px)/1.2 var(--sl-display);letter-spacing:-.02em}
    /* AND A VISITOR SHOULD NOT SEE IT AT ALL (Alex, 7/29, twice: pages "say
       'Widespread Panic Live Archive' and then have a bunch of stuff underneath
       them, and then the page loads"). The heading, the summary sentence and
       the forty-year link cloud exist for clients that never run the app. A
       browser that IS about to paint the archive — html.js, stamped inline
       before first paint — hides all three and shows one small mono line in
       their place, so booting reads as the archive opening instead of a
       different page being torn down. The first fix here kept the heading
       visible; at view-title scale that WAS the complaint. If the app never
       boots, aria-busy never clears and the ::before line stands alone — but
       the heading, sentence and year links all still shipped in the document
       for anything that does not run scripts. */
    html.js .ar-canvas[aria-busy="true"] .ar-seo-h1,
    html.js .ar-canvas[aria-busy="true"] .ar-seo-years,
    html.js .ar-canvas[aria-busy="true"] .ar-empty{display:none}
    html.js .ar-canvas[aria-busy="true"]::before{content:"Opening the archive…";display:block;font:500 11px/1.2 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--sl-faint,#6b6f78);animation:ar-seo-wait 1.2s ease-in-out infinite alternate}
    @keyframes ar-seo-wait{from{opacity:.4}to{opacity:.85}}
    @media(prefers-reduced-motion:reduce){html.js .ar-canvas[aria-busy="true"]::before{animation:none}}
    .ar-canvas>section+section{margin-top:clamp(46px,6vw,86px)}
    .ar-seo-h1{margin:0 0 10px;font:650 clamp(20px,2.2vw,26px)/1.2 var(--sl-display);letter-spacing:-.02em;color:var(--sl-ink)}
    .ar-seo-years{display:flex;flex-wrap:wrap;gap:8px 14px;margin-top:14px}
    .ar-seo-years a{color:var(--sl-muted);font:500 12px/1 var(--sl-mono)}
    .ar-empty{padding:30px 0;color:var(--sl-muted)}
    .ar-linkish{border:0;background:none;padding:0;color:var(--sl-ink);text-decoration:underline;text-underline-offset:3px;cursor:pointer;font:inherit}
    .ar-section-label{display:flex;align-items:baseline;gap:10px;margin:0 0 14px;color:var(--sl-muted);font:600 10.5px/1 var(--sl-mono);letter-spacing:.18em;text-transform:uppercase}
    .ar-section-label+.ar-section-label,.ar-show-side .ar-section-label:not(:first-child),.ar-notes+.ar-section-label{margin-top:34px}
    .ar-provenance{letter-spacing:.04em;text-transform:none;font-weight:500;color:var(--sl-faint,#6b6f78)}
    .ar-chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:14px}
    .ar-chips a{padding:7px 13px;border:1px solid var(--sl-line-strong);border-radius:999px;color:var(--sl-ink);font:600 11px/1 var(--sl-mono);letter-spacing:.05em}
    .ar-chips a:hover{background:var(--sl-ink);color:var(--sl-bg,#090a0d)}

    .ar-invite-label{display:block;color:var(--sl-muted);font:600 10px/1 var(--sl-mono);letter-spacing:.2em;text-transform:uppercase}
    .ar-invite strong{display:block;margin:13px 0 7px;font:650 clamp(19px,2.2vw,25px)/1.1 var(--sl-display);letter-spacing:-.02em}
    .ar-invite-meta{display:block;color:var(--sl-muted);font-size:13px;line-height:1.45}


    /* ---- dense rows: the research surface ---- */
    .ar-rows{border-top:1px solid var(--sl-line,rgba(255,255,255,.1))}
    .ar-row{display:grid;grid-template-columns:92px minmax(120px,.85fr) minmax(160px,1.3fr) 96px;gap:20px;align-items:baseline;padding:13px 10px 13px 4px;border-bottom:1px solid var(--sl-line,rgba(255,255,255,.07));color:inherit;transition:background .14s,padding-left .14s}
    .ar-row:hover{background:rgba(255,255,255,.05);padding-left:10px}
    .ar-row:focus-visible{background:rgba(255,255,255,.05);padding-left:10px;outline:2px solid rgba(255,255,255,.8);outline-offset:-2px;border-radius:6px}
    .ar-row time{color:var(--sl-muted);font:600 11.5px/1.3 var(--sl-mono);font-variant-numeric:tabular-nums}
    .ar-row-city{font-weight:640;letter-spacing:-.01em}
    .ar-row-venue{color:var(--sl-muted);font-size:14px}
    .ar-row-count{text-align:right;color:var(--sl-faint,#6b6f78);font:500 10.5px/1.3 var(--sl-mono)}

    /* ---- year chronology ---- */
    .ar-yearhead h1{font-size:clamp(64px,11vw,150px)}
    .ar-yearnote{margin:18px 0 0;color:var(--sl-muted);font-size:14px;line-height:1.6}
    .ar-yearnote a{color:var(--sl-ink);text-decoration:underline;text-decoration-color:rgba(255,255,255,.28);text-underline-offset:3px}
    .ar-yearnav{display:flex;justify-content:space-between;margin-top:26px;padding-top:16px;border-top:1px solid var(--sl-line,rgba(255,255,255,.1));color:var(--sl-muted);font:600 11px/1 var(--sl-mono);letter-spacing:.08em;text-transform:uppercase}
    .ar-yearnav a:hover{color:var(--sl-ink)}
    .ar-chronology{margin-top:clamp(40px,5vw,72px);display:grid;gap:42px}
    .ar-month{display:grid;grid-template-columns:132px minmax(0,1fr);gap:26px;align-items:start}
    .ar-month h3{position:sticky;top:96px;margin:0;color:var(--sl-faint,#6b6f78);font:600 11px/1 var(--sl-mono);letter-spacing:.18em;text-transform:uppercase}
    .ar-month-blocks{display:grid;gap:11px;min-width:0}
    /* M5 (Alex): the run bar's 17px indent pushed grouped rows right of the
       ungrouped ones — date and city columns drifted. EVERY block reserves
       the bar's lane; only runs paint it. Columns align regardless. */
    .ar-block{position:relative;display:grid;gap:1px;padding-left:17px}
    .ar-block.is-run::before{content:"";position:absolute;left:0;top:22px;bottom:9px;width:2px;border-radius:2px;background:var(--ar-tie);background-size:100% 220%;opacity:.62}
    .ar-run-label{display:block;margin-bottom:7px;color:var(--sl-faint,#6b6f78);font:600 9.5px/1 var(--sl-mono);letter-spacing:.16em;text-transform:uppercase}
    .ar-block-night{display:grid;grid-template-columns:34px minmax(90px,.8fr) minmax(0,1.4fr) auto;gap:16px;align-items:baseline;padding:9px 10px 9px 4px;border-radius:6px;color:inherit;transition:background .14s}
    .ar-block-night:hover{background:rgba(255,255,255,.06)}
    .ar-block-night:focus-visible{background:rgba(255,255,255,.06);outline:2px solid rgba(255,255,255,.8);outline-offset:-2px}
    .ar-block-night time{color:var(--sl-ink);font:600 15px/1 var(--sl-mono);font-variant-numeric:tabular-nums}
    .ar-block-city{font-weight:620}
    .ar-block-venue{color:var(--sl-muted);font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .ar-block-count{color:var(--sl-faint,#6b6f78);font:500 10px/1 var(--sl-mono)}

    /* ---- the stage ---- */
    /* max-width is load-bearing, not belt-and-braces: aspect-ratio + min-height
       resolve the WIDTH from the height when nothing pins it, so the stage grew
       past its column and pushed a horizontal scrollbar onto the front door
       (min-height 32vw x 21/9 = wider than the canvas). Pinning the width lets
       min-height do only what it is for — keep the stage from collapsing on a
       narrow screen — while the ratio governs the height. */
    .ar-show-stage{position:relative;isolation:isolate;overflow:hidden;width:100%;max-width:100%;border:1px solid var(--sl-line,rgba(255,255,255,.14));border-radius:18px}
    /* Only the image-less stage keeps a fixed shape — there is no photograph to
       take a ratio from, so the tie-dye needs one of its own. */
    .ar-show-stage:not(:has(.ar-stage img)){aspect-ratio:21/9;min-height:340px}
    /* The front door's lead stage paints its photo as a BACKGROUND (the index
       has no loaded show doc), so no <img> props it open — without its own
       ratio it collapsed to 0px tall and the lead card rendered as an empty
       black rectangle (Alex's punch list #1, 2026-07-28). */
    .ar-stage-art{aspect-ratio:21/9;min-height:340px}
    /* Faces ride the upper frame of concert photography; 30% cropped brows on
       the lead (Alex: "Nick's face"). 22% keeps heads whole in the 21:9 cut —
       a heuristic until per-photo focal data exists. */
    /* D3 (Alex): faces were landing UNDER the identity text. Measured, not
       guessed: the 21:9 window shows 64% of a 3:2 photo, the text band starts
       57% down the frame, and stage performers sit ~46% down the source — at
       the old 22% that put their heads at 60% of the frame, i.e. behind the
       type. 58% lifts them to ~40%, clear of the text, and drops the dead
       lighting rig off the top. Concert photography puts people in that same
       middle band, so this reads as a general rule rather than one photo's
       fix; a per-photo focal point would still beat it. */
    .is-lead .ar-stage-art{background-position:center 58%}
    .ar-lead-link{position:absolute;inset:0;z-index:1}
    .is-lead .ar-show-id{z-index:2}
    .is-lead .ar-show-actions .sc-chip{position:relative;z-index:3}
    /* THE PHOTOGRAPH IS NEVER CROPPED (DESIGN-SYSTEM.md: setlist photography
       renders at its natural ratio; object-fit:cover is not used to force one).
       The stage was a 21:9 window with object-fit:cover behind it, which threw
       away most of a portrait frame — 759x1024 rendered as 1.78. The image now
       sets the stage's height, and the identity block still lays over its lower
       edge because the stage remains its positioning context. */
    .ar-stage{position:relative;display:block;width:100%;margin:0}
    .ar-stage img{display:block;width:100%;height:auto;object-fit:contain}
    .ar-stage::after{content:"";position:absolute;inset:0;background:linear-gradient(175deg,rgba(4,4,6,.34) 0%,rgba(4,4,6,.1) 34%,rgba(4,4,6,.9) 100%)}
    .ar-stage figcaption{position:absolute;z-index:3;top:14px;right:14px;max-width:60%;padding:6px 11px;border:1px solid rgba(255,255,255,.16);border-radius:999px;background:rgba(8,8,10,.5);color:rgba(255,255,255,.78);font:500 10px/1.3 var(--sl-mono);-webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px)}
    .ar-stage figcaption a{color:inherit;text-decoration:underline;text-underline-offset:2px}
    /* No image is a designed state, not a hole: the night's own hue, a tie-dye
       wash and the year set at architectural scale. */
    .ar-stage-empty{position:absolute;inset:0;display:grid;place-items:center;overflow:hidden;background:
      radial-gradient(120% 150% at 18% 8%,hsl(var(--tone) 52% 26%/.85),transparent 62%),
      radial-gradient(110% 130% at 88% 22%,hsl(calc(var(--tone) + 58) 46% 24%/.7),transparent 58%),
      linear-gradient(168deg,#111318,#08090c)}
    .ar-stage-empty::after{content:"";position:absolute;inset:0;background:linear-gradient(178deg,rgba(4,4,6,.2),rgba(4,4,6,.88))}
    .ar-stage-year{font:700 clamp(160px,26vw,360px)/.8 var(--sl-display);letter-spacing:-.06em;color:rgba(255,255,255,.055)}
    .ar-show-id{position:absolute;z-index:2;left:clamp(20px,3.4vw,44px);right:clamp(20px,3.4vw,44px);bottom:clamp(20px,3vw,38px)}
    .ar-show-id time{display:block;color:rgba(255,255,255,.7);font:600 11px/1.2 var(--sl-mono);letter-spacing:.12em;text-transform:uppercase}
    .ar-show-id h1{margin:10px 0 5px;font-size:clamp(38px,6.4vw,84px);color:#fff}
    .ar-show-id>p{margin:0;color:rgba(255,255,255,.8);font-size:clamp(15px,1.6vw,19px)}
    .ar-show-actions{display:flex;flex-wrap:wrap;align-items:center;gap:11px;margin-top:22px}
    /* The show page's play control is now the site's own .sc-chip pair (styled in
       stagelight.css, which this page loads). The all-caps mono .ar-play-show
       pill that used to live here is gone rather than left behind — one chip
       system, one place it is defined. */
    /* .ar-show-meta / .ar-dot / .ar-lineup are gone with the show hero's meta
       line (Alex, 7/28) — the hero carries date, city, venue and the play action
       only, and the lineup fact reads as a sentence in Show Notes. Deleted rather
       than left orphaned, so nothing here describes markup that no longer exists. */
    a.ar-show-era:hover{color:#fff;text-decoration:underline;text-underline-offset:3px}
    .ar-show-body{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(240px,.75fr);gap:clamp(30px,4vw,70px);margin-top:clamp(30px,4vw,52px)}
    /* IMAGE RIGHT, SETLIST LEFT (Alex's pick of three; matches burnthday.com's
       own show layout). The split show page is a two-column grid: identity and
       setlist read down the LEFT where reading starts, the photograph stands
       as a column asset on the RIGHT with the recordings under it. A portrait
       photo simply runs taller in its column instead of owning the screen.
       The rail narrows one step at tighter widths to make room — a trade Alex
       approved explicitly. */
    /* ROWS: auto auto 1fr (Alex, 7/29: "gigantic gap between [the photo] and
       recordings"). Without an explicit row plan, the setlist — spanning rows
       2-3 — helped size row 2, so the side column could start ~300px below
       where the photo actually ended. With row 3 flexible, the setlist's
       height pours into row 3 instead, and row 2 ends where the photo does:
       Recordings now starts directly under the image. */
    .ar-show.is-split{display:grid;grid-template-columns:minmax(0,1.55fr) clamp(320px,30vw,470px);grid-template-rows:auto auto 1fr;grid-template-areas:"head visual" "main visual" "main side";column-gap:clamp(30px,4vw,64px);row-gap:0;align-items:start}
    .ar-show.is-split .ar-show-head{grid-area:head;padding-bottom:clamp(22px,3vw,34px)}
    .ar-show.is-split .ar-show-head time{display:block;color:var(--sl-muted);font:600 11px/1.2 var(--sl-mono);letter-spacing:.12em;text-transform:uppercase}
    .ar-show.is-split .ar-show-head h1{margin:12px 0 6px;font:700 clamp(34px,4.2vw,62px)/.95 var(--sl-display);letter-spacing:-.035em;color:#fff}
    .ar-show.is-split .ar-show-head>p{margin:0;color:rgba(255,255,255,.8);font-size:clamp(15px,1.5vw,18px)}
    .ar-show.is-split .ar-show-head .ar-show-actions{margin-top:18px}
    /* The night's own facts, one line, mono like the date above it — a night
       with no notes and no photograph still says something true about itself. */
    /* Plain chronological navigation, distinct from the discovery rails below:
       two quiet slabs, previous on the left, next on the right. The empty span
       holds the grid column when a night has no neighbour on that side, so the
       first and last shows in the archive do not shift their sole button over. */
    /* BOTH BOTTOM RAILS SPAN THE WHOLE ARTICLE. They carry no grid-area, so
       before the rows were declared they auto-placed into an implicit row; once
       grid-template-rows named three, auto-placement dropped them into the
       narrow right column and the show cards crammed to 224px each against the
       right edge. Saying 1 / -1 makes the intent explicit instead of a
       side-effect of how many rows happen to be declared above. */
    .ar-show.is-split .ar-showstats,
    .ar-show.is-split .ar-steps,
    .ar-show.is-split .ar-onward{grid-column:1 / -1}
    .ar-steps{display:grid;grid-template-columns:1fr 1fr;gap:clamp(14px,1.8vw,26px);margin:clamp(30px,4vw,48px) 0 0}
    /* The cards ARE .ar-night now, so they inherit the archive's card language
       — framed art, radius, border, shadow, hover lift — and only the eyebrow
       and the right-alignment of the next card are added here. */
    .ar-steps .ar-step .ar-step-dir{position:absolute;top:14px;left:16px;z-index:2;font:600 10.5px/1.2 var(--sl-mono);letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.85);text-shadow:0 1px 8px rgba(0,0,0,.7)}
    .ar-steps .ar-step-next .ar-step-dir{left:auto;right:16px}
    .ar-steps .ar-step.is-empty{border:0;background:none;box-shadow:none}
    .ar-steps .ar-step-next{text-align:right}
    /* The night's own facts sit a step below the venue, not level with it.
       Inheriting .ar-show-head>p made this read as important as the venue and
       shoved the play chip down the page. */
    .ar-show.is-split .ar-show-head .ar-show-summary{margin:8px 0 0;color:var(--sl-muted);font:500 12.5px/1.5 var(--sl-mono);letter-spacing:.03em}
    @media(max-width:560px){.ar-steps{grid-template-columns:1fr}.ar-steps .ar-step.is-empty{display:none}.ar-step-next{text-align:left}}
    /* NOT STICKY (Alex, 7/29). The photo used to follow the scroll, so the
       recordings and the night cards slid up BEHIND it — their outlines peeking
       out under the credit pill read as overlap on every report. It scrolls
       away with the page now, like everything else. */
    .ar-show.is-split .ar-show-visual{grid-area:visual}
    .ar-show.is-split .ar-show-visual .ar-show-stage{aspect-ratio:auto;min-height:0}
    /* The night's numbers: one scrolling row under the photograph, the
       homepage's rarity symbols at archive scale. Scrollbar hidden the same
       way the year strip hides it — the row invites a swipe, not chrome. */
    /* EC-homage Song Stats: the REFERENCE lives under the setlist as a quiet
       mono table — every song, every number, uncurated. The strip above the
       fold is now the STORY: it speaks only when a night has a debut or a
       bustout, per Alex ('curate them when it matters'). */
    .ar-showstats{margin:26px 0 0;border-top:1px solid var(--sl-line,rgba(255,255,255,.12));padding-top:14px}
    .ar-showstats summary{cursor:pointer;list-style:none;display:flex;align-items:baseline;gap:10px;font:600 11px/1.2 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted)}
    .ar-showstats summary::-webkit-details-marker{display:none}
    .ar-showstats summary span{letter-spacing:0;text-transform:none;font-weight:400;font-size:11.5px}
    /* The table IS the house .data-table from stagelight.css — the site has
       one table language and this page had no business inventing a second
       (Alex: "looks nothing like the other tables... it is ugly"). Only the
       numeric right-alignment and the summary line are scoped here. */
    .ar-showstats .data-table{table-layout:auto}
    .ar-showstats .data-table th:nth-child(n+3),.ar-showstats .data-table td:nth-child(n+3){text-align:right;font-family:var(--sl-mono)}
    .ar-showstats .data-table td:first-child{font-weight:650}
    .ar-showstats .data-table a{color:inherit;text-decoration:underline;text-underline-offset:2px;text-decoration-color:color-mix(in oklab,currentColor,transparent 65%)}
    /* THE TRENDING COLUMN. It takes the room the full-width table freed up —
       the line needs horizontal distance to read as a slope at all. Its
       subtitle says what the line counts, because a chart nobody can name the
       units of is decoration. The Gap wedge gets the other wide share. */
    .ar-showstats .data-table th.ar-trend-col{width:24%;text-align:left}
    .ar-showstats .data-table th.ar-trend-col span,.ar-showstats .data-table th.ar-gap-col span{display:block;margin-top:3px;font:400 10px/1.3 var(--sl-mono);letter-spacing:.02em;text-transform:none;color:var(--sl-faint,#6b6f78)}
    .ar-showstats .data-table td.ar-trend-col{text-align:left;padding-top:6px;padding-bottom:6px}
    /* The table scrolls sideways on a phone rather than crushing six columns
       into 375px; on wide screens the wrapper is inert. */
    .ar-showstats-scroll{overflow-x:auto;scrollbar-width:thin}
    .ar-showstats-scroll .data-table{min-width:640px}
    /* Rarity beside the name: the strip's own bursts at table scale. The slot
       is on EVERY row (empty on the routine ones) so the song names stay on
       one left edge — a burst is a flag, not an indent. */
    .ar-showstats td.ar-ss-song .rarity-symbol{display:inline-block;width:34px;min-width:34px;vertical-align:-2px}
    .ar-showstats td.ar-ss-song .rarity-symbol svg{height:12px;width:auto;display:inline-block}
    /* THE GAP WEDGE. One shape per row, longer on the big gaps (log scale set
       inline as --gw), tapering to a point — a pointer whose length IS the
       number. Gold when the gap is bustout-grade for that year, the same gold
       as the strip's burst stars; quiet steel otherwise. The digit rides at
       the tip: whispered until the row is hovered where hover exists, always
       visible on touch, and always in the title for anyone who asks. */
    .ar-showstats th.ar-gap-col{width:22%;text-align:left}
    .ar-showstats td.ar-gap-col{text-align:left;font-family:var(--sl-mono)}
    .ar-gapbar{display:inline-flex;align-items:center;gap:8px;width:100%;min-width:90px}
    .ar-gapbar i{display:block;flex:none;width:var(--gw,6%);height:9px;border-radius:1px;
      clip-path:polygon(0 0,100% 50%,0 100%);
      background:linear-gradient(90deg,rgba(255,255,255,.34),rgba(255,255,255,.14));
      transform-origin:left center;animation:ar-gap-grow .5s cubic-bezier(.2,.7,.3,1) backwards;animation-delay:calc(var(--row,0) * 22ms)}
    .ar-gapbar.is-deep i{background:linear-gradient(90deg,#e8c766,rgba(232,199,102,.32))}
    .ar-gapbar b{font:500 11.5px/1 var(--sl-mono);font-variant-numeric:tabular-nums;color:var(--sl-muted);opacity:0;transition:opacity .18s ease}
    .ar-gapbar.is-deep b{color:#e8c766}
    .ar-showstats tr:hover .ar-gapbar b,.ar-gapbar:focus-visible b{opacity:1}
    @media(hover:none){.ar-gapbar b{opacity:1}}
    @keyframes ar-gap-grow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
    @media(prefers-reduced-motion:reduce){.ar-gapbar i{animation:none}}
    /* TEN TICKS. The filled ones are the /10 count — countable, so the mark
       is the number rather than standing in front of it. Filled ticks borrow
       the heat red the trend line already speaks. */
    .ar-showstats th.ar-ticks-col{text-align:left}
    .ar-showstats td.ar-ticks-col{text-align:left}
    .ar-ticks{display:inline-flex;gap:3px}
    .ar-ticks i{width:4px;height:12px;border-radius:1px;background:rgba(255,255,255,.13)}
    .ar-ticks i.is-on{background:#e5726f}
    /* The colours are Tonight's Odds' own heat tiers (.tn-hot / .tn-warm), so a
       song in heavy rotation is the same red here as it is on the homepage.
       currentColor carries it into the stroke. */
    .ar-trend{display:block;width:100%;height:34px;overflow:visible}
    .ar-trend.is-hot{color:#e5726f}
    .ar-trend.is-warm{color:#e5b3b1}
    .ar-trend.is-cold{color:var(--sl-faint,#6b6f78)}
    /* Drawn in, not blinked in — the year ribbon's gesture, arrived at a
       different way. A stroke-dashoffset draw cannot work here: the viewBox is
       stretched horizontally to fill the column, the dash pattern is measured
       after that stretch, and the line comes out full of holes. This wipes a
       clip-path across the SVG's own box instead, which does not care what the
       geometry inside it is doing. The stagger walks DOWN the table. */
    @keyframes ar-trend-draw{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}
    .ar-trend{clip-path:inset(0 100% 0 0);animation:ar-trend-draw .5s cubic-bezier(.2,.7,.3,1) forwards;animation-delay:calc(var(--row,0) * 22ms)}
    @media(prefers-reduced-motion:reduce){.ar-trend{clip-path:none;animation:none}}
    .ar-fact-strip{display:flex;gap:8px;margin:14px 0 0;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-bottom:2px}
    .ar-fact-strip::-webkit-scrollbar{display:none}
    .ar-fact{flex:none;display:inline-flex;align-items:center;gap:8px;padding:7px 12px;border:1px solid var(--sl-line,rgba(255,255,255,.12));border-radius:10px;background:rgba(255,255,255,.03)}
    .ar-fact .rarity-symbol{display:inline-flex;width:20px;flex:none}
    .ar-fact .rarity-symbol svg{width:100%;height:auto;display:block}
    .ar-fact-body{display:grid;gap:1px}
    .ar-fact-body strong{font:650 12.5px/1.2 var(--sl-display);color:rgba(255,255,255,.94);white-space:nowrap}
    .ar-fact-body small{font:500 10px/1.3 var(--sl-mono);letter-spacing:.05em;color:var(--sl-muted);white-space:nowrap}
    .ar-fact-body a{color:inherit;text-decoration:underline;text-underline-offset:2px}
    /* Type is off the photo, so the heavy identity scrim would be mud on the
       picture; a whisper stays for the figcaption pill. */
    .ar-show.is-split .ar-stage::after{background:linear-gradient(180deg,rgba(4,4,6,.22) 0%,rgba(4,4,6,0) 26%,rgba(4,4,6,.14) 100%)}
    .ar-show.is-split>.ar-show-body{display:contents}
    .ar-show.is-split .ar-show-main{grid-area:main;min-width:0}
    .ar-show.is-split .ar-show-side{grid-area:side;margin-top:clamp(26px,3vw,40px)}
    @media(max-width:1400px){.ar-shell{--rail-w:196px;--rail-full:196px}}
    .ar-show-main{min-width:0}

    /* ---- setlist: the best thing on the page ---- */
    .ar-setlist{display:grid;gap:19px}
    /* THE LABEL SITS ON THE FIRST SONG LINE'S BASELINE (Alex, 7/28).
       It used to be nudged with a 6px padding, which cannot hold: the songs are
       clamp(17px,1.9vw,21px) on a 2.05 line-height, so their first baseline moves
       with the viewport while a fixed padding does not — the label floated high
       on wide screens and low on narrow ones. Grid baseline alignment aligns the
       two items' FIRST baselines by definition, so it stays correct at every size
       and for one-line and many-line sets alike. */
    .ar-set{display:grid;grid-template-columns:66px minmax(0,1fr);gap:14px;align-items:baseline}
    .ar-set-label{padding-top:0;color:var(--sl-faint,#6b6f78);font:600 10.5px/1.2 var(--sl-mono);letter-spacing:.12em;text-transform:uppercase}
    .ar-set-songs{margin:0;font-size:clamp(17px,1.9vw,21px);line-height:2.05;letter-spacing:-.01em}
    /* No pill. The title itself is the target: weight comes up and a tie-dye
       underline is drawn tight under the type.
       The underline MUST hang off the song's own text box, not its line box —
       that distinction is the entire bug Alex reported. An inline button's box
       is as tall as the paragraph's 2-ish line-height, so an underline anchored
       to its bottom lands on top of the next line. inline-block + a tight
       internal line-height shrinks the box back to the glyphs, so "bottom" means
       just under the descenders and nothing below can be touched. */
    .ar-song{position:relative;display:inline-block;max-width:100%;line-height:1.15;vertical-align:baseline;padding:0;border:0;background:none;color:inherit;font-family:inherit;font-size:inherit;text-align:left;cursor:pointer;transition:color .16s,font-weight .16s;font-weight:450}
    .ar-song::after{content:"";position:absolute;left:0;right:0;bottom:-.02em;height:1.5px;border-radius:2px;background:var(--ar-tie);background-size:240% 100%;opacity:0;transform:scaleX(.35);transform-origin:left;transition:opacity .18s,transform .22s cubic-bezier(.2,.7,.3,1)}
    /* Hover must NOT change weight. A weight shift changes the text's width, so
       the setlist reflows under the pointer and the whole surface feels unstable.
       Geometry stays fixed: only colour, the underline and brightness respond. */
    .ar-song:hover,.ar-song:focus-visible{color:#fff}
    .ar-song:hover{outline:none}
    /* Hover cannot be the only signal: a keyboard user gets the same weight and
       underline PLUS a real ring, so focus is never ambiguous. */
    .ar-song:focus-visible{outline:2px solid rgba(255,255,255,.85);outline-offset:3px;border-radius:3px}
    .ar-song:hover::after,.ar-song:focus-visible::after{opacity:.85;transform:scaleX(1)}
    .ar-song.is-current{--song-progress:0%;color:transparent;background:var(--ar-tie);background-size:220% 100%;-webkit-background-clip:text;background-clip:text;animation:ar-tiedye 8s ease-in-out infinite alternate}
    /* The played-through indicator is the same tight underline, filled to the
       song's own progress. */
    .ar-song.is-current::after{opacity:1;transform:none;right:auto;width:var(--song-progress);max-width:100%;transition:width .18s linear}
    .ar-song.is-static{cursor:default}
    .ar-song.is-static::after{display:none}
    /* LEADING: the tape is on a track no setlist song owns — an Intro, tuning,
       the walk back on for an encore — and the NEXT mapped song is coming. Its
       letters fill with tie-dye from the left as that in-between track runs out,
       so you can watch the night head into Fishwater before Fishwater starts.
       Two layers clipped to the text: the gradient sized to var(--lead), solid
       white behind it. archive-app.mjs sets --lead; home-player.mjs paints the
       identical state on the main site. */
    /* ---- POSITIONAL HINTS: where a thing sits inside a song ----
       The setlist is one line of prose per set, but the tape knows more than the
       line does: a tease happens somewhere in the MIDDLE of a song, and a
       standalone Jam runs INTO the song that follows it. Both facts are already
       in the data (units.teases / units.raps carry the song they happened
       during; a standalone unit carries its segue), so they are drawn rather
       than written out a second time.

       NO TEASE GLINT (Alex, 7/29: "There should be no tease indicator with the
       tie-die on the setlists" — the Porch Song glow. The mid-song --ar-glint
       wash is deleted on BOTH surfaces, not restyled, and .has-unit still rides
       in the markup for the hover/aria hint). What remains is the lead-in: the
       first-letters sliver for a song a standalone Jam segued into, which he
       has never flagged. A lead-in = the first sliver only, static and quiet.

       :not(.is-current):not(.is-leading) because live playback outranks a
       resting hint every time. */
    .ar-song.has-lead-in:not(.is-current):not(.is-leading){color:transparent;background-repeat:no-repeat,no-repeat;background-clip:text;-webkit-background-clip:text;background-image:var(--ar-leadin),linear-gradient(var(--sl-ink),var(--sl-ink));background-size:13% 100%,100% 100%;background-position:left center,left center}
    /* Hover brightens the base layer instead of the colour, since the colour is
       transparent while a hint is painted. Same brightening, same geometry. */
    .ar-song.has-lead-in:not(.is-current):not(.is-leading):hover,.ar-song.has-lead-in:not(.is-current):not(.is-leading):focus-visible{background-image:var(--ar-leadin),linear-gradient(#fff,#fff)}
    .ar-song.is-leading{--lead:0%;color:transparent;background-image:var(--ar-tie),linear-gradient(#fff,#fff);background-size:var(--lead) 100%,100% 100%;background-repeat:no-repeat,no-repeat;background-position:left center,left center;-webkit-background-clip:text;background-clip:text;transition:background-size .2s linear}
    .ar-song.is-leading::after{display:none}
    @keyframes ar-tiedye{from{background-position:0% 50%}to{background-position:100% 50%}}
    .ar-segue{color:var(--sl-muted);font-weight:400;padding:0 .12em}
    /* A SEPARATOR BELONGS TO THE SONG BEFORE IT (Alex, 7/28: commas and ">" were
       stranded at the start of wrapped lines). The mark is an inline span after a
       song button, and the break opportunity sits BETWEEN them — so the fix is a
       word joiner at the head of each mark (see setlistMarkup), which forbids a
       break at exactly that point.
       Deliberately NOT white-space:nowrap on these spans: that also makes the
       mark's TRAILING space unbreakable, so the whole ", " had to travel to the
       next line with the song that followed it — which put the comma back at a
       line start, the very thing being fixed. The trailing space must stay a
       break opportunity; only the joint before the mark must not be one. */
    .ar-set-songs{text-wrap:pretty}
    .ar-sep{color:var(--sl-muted)}
    .ar-set-songs>:last-child.ar-sep{display:none}
    /* The comma-glue wrappers (.ar-nb) made the old last-child rule blind — the
       final separator now lives INSIDE the last wrapper, so the set printed a
       trailing comma. Hide it wherever a glued unit closes its container. */
    .ar-set-songs>.ar-nb:last-child .ar-sep,p>.ar-nb:last-child .ar-sep{display:none}
    .ar-tracks{margin:0;padding:0;list-style:none;border-top:1px solid var(--sl-line,rgba(255,255,255,.1))}
    .ar-track{display:flex;justify-content:space-between;align-items:baseline;gap:16px;width:100%;padding:11px 6px;border:0;border-bottom:1px solid var(--sl-line,rgba(255,255,255,.07));background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
    .ar-track:hover{background:rgba(255,255,255,.05)}
    .ar-track.is-current{font-weight:660}
    .ar-track-time{flex:none;color:var(--sl-muted);font:11px var(--sl-mono);font-variant-numeric:tabular-nums}

    /* ---- sources ---- */
    .ar-show-side{min-width:0}
    .ar-sources{display:grid;gap:7px}
    .ar-source{display:block;width:100%;padding:13px 15px;border:1px solid var(--sl-line);border-radius:10px;background:none;color:inherit;text-align:left;cursor:pointer;transition:border-color .16s,background .16s}
    .ar-source:hover{border-color:var(--sl-line-strong);background:rgba(255,255,255,.04)}
    .ar-source.is-active{border-color:rgba(255,255,255,.4);background:rgba(255,255,255,.06)}
    .ar-source strong{display:block;font-size:14px;font-weight:620}
    .ar-source small{display:block;margin-top:4px;color:var(--sl-muted);font-size:11.5px;line-height:1.45;overflow-wrap:anywhere}
    .ar-source-len{font-family:var(--sl-mono);font-size:10.5px !important;letter-spacing:.04em}
    .ar-archive-link{display:inline-block;margin-top:14px;color:var(--sl-muted);font-size:12px;text-decoration:underline;text-underline-offset:3px}
    .ar-archive-link:hover{color:var(--sl-ink)}


    /* ---- atmosphere: the homepage mechanism, reused ---- */
    /* Scoped to body.listen-archive for the same reason the dock is: the site's
       body.stagelight > * { position: relative } out-specifies a bare class and
       would drop this back into document flow as a 520px hole. */
    body.listen-archive > .ar-echo{position:fixed;z-index:0;top:0;left:0;right:0;height:520px;overflow:hidden;pointer-events:none;opacity:0;transition:opacity .6s ease}
    .ar-echo.is-on{opacity:1}
    .ar-echo::before{content:"";position:absolute;inset:0;background-image:var(--echo);background-size:cover;background-position:center 28%;transform:scale(1.35);filter:blur(30px) saturate(1.12);opacity:.34}
    .ar-echo::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(9,10,13,.72) 0%,rgba(9,10,13,.5) 22%,rgba(9,10,13,.86) 62%,var(--sl-bg,#090a0d) 100%)}
    /* The glow the tint publishes is the same custom property the homepage hero
       drives, so the archive inherits that behaviour instead of re-deriving it. */
    body.listen-archive{background:
      radial-gradient(62% 40% at 74% 2%,var(--hero-glow,transparent),transparent 72%),
      radial-gradient(52% 34% at 10% 0%,var(--hero-glow,transparent),transparent 70%),
      var(--sl-bg,#090a0d);
      background-attachment:fixed}
    .ar-shell,.ar-dock{position:relative;z-index:1}
    .ar-show-stage{box-shadow:0 40px 90px -40px var(--hero-glow-strong,rgba(0,0,0,.8)),0 30px 70px -30px rgba(0,0,0,.75)}

    /* ---- cabinet icons + years folder ---- */
    .ar-cab-group a,.ar-cab-group button{display:flex;align-items:center;gap:10px;padding:7px 0 7px 2px}
    .ar-cab-group svg{width:17px;height:17px;flex:none;opacity:.62;transition:opacity .16s}
    .ar-cab-group a:hover svg,.ar-cab-group button:hover svg,.ar-cab-group a.is-active svg{opacity:1}
    .ar-cab-group a::before,.ar-cab-group button::before{display:none}
    .ar-cab-group a.is-active{color:var(--sl-ink)}
    /* Years is a contained drawer, not an accordion that shoves Songs/Places/Eras
       down the page. The cabinet's height never changes: all 42 years live in a
       fixed-height scroller, and the chevron sits directly beside the label. */
    .ar-years-folder{display:grid}
    .ar-years-toggle{width:100%;gap:10px !important}
    .ar-years-chev{width:12px !important;height:12px !important;margin-left:2px;opacity:.5 !important;transition:transform .22s ease,opacity .16s}
    .ar-years-toggle:hover .ar-years-chev{opacity:.9 !important}
    .ar-years-toggle.is-open .ar-years-chev{transform:rotate(180deg);opacity:1 !important}
    .ar-years-list[hidden]{display:none}
    /* Inline expansion: the list pushes Songs/Places/Eras down inside the rail's
       single scroll. No inner scrollbar, no "show more". */
    /* No indent rule. The step in from the toggle is what says these belong to it;
       a hairline down the left edge was one more line on a page already made of
       them (Alex). The total left offset is unchanged, so nothing shifts. */
    .ar-years-list{display:grid;gap:0;margin:2px 0 4px 37px;padding:2px 0}
    .ar-years-list a{display:flex;align-items:baseline;gap:8px;padding:7px 4px 7px 0;color:var(--sl-muted);font:500 15px/1.2 var(--sl-mono);letter-spacing:.04em}
    .ar-years-list a em{font-style:normal;font-size:12px;color:var(--sl-faint,#6b6f78);opacity:.8}
    .ar-eras-list a{font-family:var(--sl-display);font-size:15.5px;letter-spacing:0}
    .ar-years-list a:hover{color:var(--sl-ink)}
    .ar-years-list a.is-active{color:transparent;background:var(--ar-tie);background-size:300% 100%;-webkit-background-clip:text;background-clip:text;font-weight:700}
    .ar-years-list a.is-active em{color:var(--sl-ink);opacity:1}

    .ar-latest-lead .ar-nights.is-lead{grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr))}
    .ar-nights.is-lead .ar-night{aspect-ratio:4/3}
    .ar-nights.is-lead .ar-night-city{font-size:clamp(22px,2.4vw,28px)}



    /* ---- year ribbon: a tour path, not a chart ---- */
    /* NO SCROLL CONTAINER, EVER (Alex, 7/28: the scrollbar sat across the month
       labels and read as broken). The strip FITS its column at every desktop
       width — the year is distributed across whatever room there is, and the
       separation a squeeze was trying to buy is bought by the stair instead.
       overflow-x:clip rather than auto: if anything ever does exceed the box it
       is trimmed silently instead of growing a scrollbar over the months. */
    .ar-ribbon{position:relative;margin-top:26px;padding-bottom:132px;overflow-x:clip;overflow-y:visible}
    .ar-ribbon-track{position:relative;height:96px;border-bottom:1px solid var(--sl-line,rgba(255,255,255,.14))}
    .ar-ribbon-month{position:absolute;bottom:-22px;left:0;padding-left:6px;border-left:1px solid var(--sl-line,rgba(255,255,255,.09));height:calc(100% + 14px);top:0}
    .ar-ribbon-month em{position:absolute;bottom:-20px;left:6px;font-style:normal;color:var(--sl-faint,#6b6f78);font:500 9.5px/1 var(--sl-mono);letter-spacing:.12em;text-transform:uppercase}
    /* A run of consecutive nights reads as one move down the road. */
    /* THE STAIR. Consecutive nights sit a day apart, which on a year-wide axis
       is under half a percent — three nights used to be three dots on top of one
       another with no way to aim at the middle one. Each night of a run now
       climbs one --step, so the run reads as a diagonal and every dot has its own
       air. Consecutive days are only ~3px apart on a year-wide axis, so the CLIMB
       is what makes each night its own target — 18px a step against a 26px-tall
       box. The box is narrow (16px, barely wider than the 12px dot) on purpose:
       a wide one would swallow the neighbours it is only 3px away from, and the
       dot is the thing being aimed at anyway.
       Later nights are later in the DOM and therefore paint on top, so the small
       remaining overlap resolves to the night you can actually see. The stair restarts
       every four (set in ribbonMarkup) so a long run cannot climb off the track.
       Horizontal position is still the real date — only the height is invented,
       and it only ever means "the next night of this run". */
    .ar-node{position:absolute;bottom:calc(8px + var(--step,0) * 18px);width:16px;height:26px;margin-left:-8px;padding:0;border:0;background:none;display:grid;place-items:center;cursor:pointer;z-index:2}
    .ar-node-dot{width:12px;height:12px;border-radius:50%;background:rgba(255,255,255,.55);box-shadow:0 0 0 3px rgba(255,255,255,.07);transition:transform .18s cubic-bezier(.2,.7,.3,1),background .18s,box-shadow .18s}
    .ar-node:hover .ar-node-dot,.ar-node:focus-visible .ar-node-dot{background:var(--ar-tie);background-size:200% 200%;transform:scale(1.5);box-shadow:0 0 0 4px rgba(255,255,255,.1)}
    .ar-node:focus-visible{outline:none}
    .ar-node:focus-visible .ar-node-dot{box-shadow:0 0 0 3px rgba(255,255,255,.85)}
    /* The connector climbs WITH the nights instead of lying flat beneath them, so
       a run looks like one thing going up rather than a bar with dots near it. */
    /* The connectors are stroked with the tie-dye ramp itself (the gradient def
       lives once in the ribbon markup), so a run climbing the year is drawn in
       the same colour the setlist uses for a song that is playing. */
    .ar-runline{position:absolute;bottom:13px;height:72px;overflow:visible;opacity:.62;pointer-events:none;z-index:1}
    .ar-tie-defs{position:absolute;width:0;height:0;pointer-events:none}
    /* THE LAMP. A wide, soft tie-dye light parked at the cursor's position along
       the year (--ar-cursor, written once a frame by wireRibbon). screen blending
       means it BRIGHTENS what is under it — the dots and the connectors near the
       pointer light up and fall away with distance — rather than washing a panel
       over the top of them. Deliberately weak: the hovered node's own scale and
       its preview card have to stay obviously stronger, because those are the
       affordance and this is only the room's light. Off until the pointer is
       actually over the strip (.is-lit), so it never sits there glowing at
       nobody, and absent entirely on touch and under reduced motion. */
    .ar-lamp{position:absolute;top:-24px;bottom:-24px;left:var(--ar-cursor,50%);width:min(420px,46%);margin-left:calc(min(420px,46%) / -2);border-radius:50%;opacity:0;pointer-events:none;z-index:0;mix-blend-mode:screen;transition:opacity .35s ease;
      background:radial-gradient(closest-side,rgba(224,87,79,.30),rgba(96,165,210,.16) 46%,transparent 78%)}
    .ar-ribbon.is-lit .ar-lamp{opacity:1}
    @media(prefers-reduced-motion:reduce){.ar-lamp{display:none}}
    @media(hover:none),(pointer:coarse){.ar-lamp{display:none}}
    /* ARRIVAL, ONCE. The connectors draw themselves and the nights settle up in
       date order with a small stagger — the year assembling rather than appearing
       fully formed. Roughly 500ms end to end, transform/opacity only, and nothing
       loops: it happens on the render of a year view and then the strip is still.
       --i is the show's index in the year, set in ribbonMarkup, so the stagger
       follows the calendar rather than the DOM by accident. */
    @keyframes ar-node-settle{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
    @keyframes ar-line-draw{from{stroke-dashoffset:var(--len,240)}to{stroke-dashoffset:0}}
    .ar-ribbon .ar-node{opacity:0;animation:ar-node-settle .34s cubic-bezier(.2,.7,.3,1) forwards;animation-delay:calc(var(--i,0) * 3.4ms)}
    .ar-ribbon .ar-runline polyline{stroke-dasharray:var(--len,240);animation:ar-line-draw .5s cubic-bezier(.2,.7,.3,1) forwards;animation-delay:calc(var(--i,0) * 3.4ms)}
    @media(prefers-reduced-motion:reduce){
      .ar-ribbon .ar-node{opacity:1;animation:none}
      .ar-ribbon .ar-runline polyline{stroke-dasharray:none;animation:none}
    }
    /* Below the track, not above it — above collides with the year heading. */
    /* Below the track AND below the month labels. The strip grew taller when the
       stair went in, and a preview measured from the top of it landed across the
       months. Anchored to the bottom of the ribbon's own reserved space instead,
       so it cannot collide with them whatever height the stair reaches. */
    .ar-preview{position:absolute;z-index:6;top:auto;bottom:0;left:var(--x,50%);transform:translateX(-50%);display:flex;gap:12px;width:min(320px,86vw);padding:11px;border:1px solid var(--sl-line-strong);border-radius:13px;background:rgba(13,14,19,.95);box-shadow:0 26px 60px -26px rgba(0,0,0,.9);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);pointer-events:none}
    .ar-preview-media{flex:none;width:74px;height:56px;border-radius:8px;background:radial-gradient(120% 130% at 26% 12%,hsl(var(--tone) 50% 30%/.9),transparent 62%),linear-gradient(160deg,#161a23,#0b0c10);background-size:cover;background-position:center 30%}
    .ar-preview-media.has-art{background-blend-mode:normal}
    .ar-preview-body{min-width:0;display:grid;gap:2px}
    .ar-preview-body time{color:var(--sl-muted);font:600 10px/1.2 var(--sl-mono);letter-spacing:.08em;text-transform:uppercase}
    .ar-preview-body strong{font:650 15px/1.2 var(--sl-display);letter-spacing:-.015em}
    .ar-preview-body span{color:var(--sl-muted);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .ar-preview-body em{margin-top:3px;font-style:normal;color:var(--sl-faint,#6b6f78);font:500 9.5px/1 var(--sl-mono);letter-spacing:.1em;text-transform:uppercase}

    /* ---- archive-sourced notes + performance units ---- */
    .ar-notelist.is-archive li::before{opacity:.4}
    .ar-notes-prov{margin:8px 0 0;color:var(--sl-faint,#6b6f78);font:500 9.5px/1.4 var(--sl-mono);letter-spacing:.1em;text-transform:uppercase}
    .ar-units{display:flex;flex-wrap:wrap;gap:7px;margin-top:14px}
    .ar-unit{display:inline-flex;align-items:baseline;gap:7px;padding:6px 11px;border:1px solid var(--sl-line);border-radius:999px;font-size:12.5px;color:var(--sl-ink)}
    .ar-unit em{font-style:normal;color:var(--sl-faint,#6b6f78);font:600 9px/1 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase}
    .ar-tapenotes{margin:12px 0 0;padding:0;list-style:none;display:grid;gap:5px}
    .ar-tapenotes li{color:var(--sl-faint,#6b6f78);font-size:12px;line-height:1.5}

    /* ---- the front door's lead show ---- */
    /* THE FRONT DOOR'S LEAD IS THE SHOW HERO, SCALED. It used to be its own
       two-column composition — a 16:10 thumbnail beside a text column — so the
       same night looked like two different objects depending which page you were
       on. It now renders the show page's own .ar-show-stage / .ar-stage /
       .ar-show-id markup, and this modifier is the entire difference: a shorter
       minimum height and a type scale that suits a card rather than a page. Same
       ratio, same crop, same scrim, same inset, same chip. */
    .ar-show-stage.is-lead{min-height:clamp(240px,26vw,340px)}
    .ar-show-stage.is-lead .ar-show-id h1{font-size:clamp(32px,4.6vw,58px)}
    .ar-show-stage.is-lead .ar-show-id>p{font-size:clamp(14px,1.4vw,17px)}
    .ar-show-stage.is-lead .ar-show-id h1 a:hover{color:#fff}
    /* The front door has only the index in memory, so the lead's photograph
       arrives through the same lazy [data-card-art] fill the night cards use —
       a background image rather than an <img>. Everything else about the stage,
       including its scrim (.ar-stage::after), is inherited untouched. */
    .ar-stage-art{background-size:cover;background-position:center 30%;background-image:linear-gradient(150deg,hsl(var(--tone,210) 48% 26%),#0b0c10)}
    .ar-stage-art.has-art{background-image:var(--art)}
    .ar-lead-open{color:rgba(255,255,255,.8);font-size:13.5px}
    .ar-lead-open:hover{color:#fff}

    /* ---- taper track list as provenance under Recordings ---- */
    .ar-tapelist{margin-top:16px}
    .ar-tapelist summary{cursor:pointer;color:var(--sl-muted);font:600 10.5px/1.4 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase}
    .ar-tapelist summary:hover{color:var(--sl-ink)}
    .ar-tapelist[open] summary{margin-bottom:8px}

    /* ---- related nights: the site's own show-card language ----
       Built from .sc-date / .sc-city / .sc-venue and the framed .sc-photo
       treatment used by the homepage setlist cards, so these belong to the same
       family instead of being a second card system. No gray slab on hover: the
       image responds, the type sharpens. */
    .ar-onward{display:grid;gap:clamp(38px,5vw,64px);margin-top:clamp(52px,7vw,96px);padding-top:clamp(30px,4vw,48px);border-top:1px solid var(--sl-line,rgba(255,255,255,.1))}
    .ar-onward .ar-head h2{font-size:clamp(17px,1.7vw,21px)}
    .ar-nights{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(210px,100%),1fr));gap:clamp(14px,1.6vw,22px)}
    /* TEXT OVER THE IMAGE (Alex, 7/29: the homepage's elegant cards, 'darkened
       fade', not text under a thumbnail). Same markup — the media block becomes
       the card's whole surface and the type sits on a bottom scrim whose stops
       are lifted from the homepage sc-bg treatment, flipped to fade upward. */
    .ar-night{position:relative;display:block;color:inherit;overflow:hidden;aspect-ratio:16/11;border-radius:var(--sl-r-md,12px);border:1px solid var(--sl-line,rgba(255,255,255,.12));box-shadow:0 30px 60px -24px rgba(0,0,0,.8),inset 0 1px 0 rgba(255,255,255,.1)}
    /* THE ART LIVES ON ::before AS var(--art) — that is the contract the app
       paints to (archive-app.mjs sets --art and .has-art on [data-card-art] as
       each card scrolls into view). Rewriting this block for the overlay look
       dropped that layer and every card went blank. The scrim is ::after so it
       sits ABOVE the art and below the type. */
    .ar-night-media{display:block;position:absolute;inset:0;overflow:hidden;border-radius:0;border:0;box-shadow:none}
    .ar-night-media::before{content:"";position:absolute;inset:0;background-image:var(--art);background-size:cover;background-position:center 30%;transform:scale(1);transition:transform .5s cubic-bezier(.2,.7,.3,1);opacity:0}
    .ar-night-media.has-art::before{opacity:1}
    .ar-night:hover .ar-night-media.has-art::before{transform:scale(1.04)}
    .ar-night-media::after{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(0deg, rgba(11,11,12,0.94) 0%, rgba(10,10,12,0.72) 26%, rgba(9,9,11,0.30) 52%, rgba(0,0,0,0) 74%)}
    .ar-night-media.has-art .ar-night-fallback{display:none}
    .ar-night-fallback{position:absolute;inset:0;display:grid;place-items:center;font:700 clamp(38px,5vw,58px)/1 var(--sl-display);letter-spacing:-.04em;color:rgba(255,255,255,.09)}
    .ar-night-date{position:relative;z-index:2;display:block;margin:0;padding:0 16px;font-family:var(--sl-mono);font-size:11px;letter-spacing:.08em;color:rgba(255,255,255,.78);font-variant-numeric:tabular-nums}
    .ar-night-city{position:relative;z-index:2;display:block;margin-top:5px;padding:0 16px;font-family:var(--sl-display);font-weight:720;font-size:clamp(18px,1.9vw,22px);letter-spacing:-.015em;line-height:1.1;color:#fff;transition:color .18s}
    .ar-night-venue{position:relative;z-index:2;display:block;margin-top:4px;padding:0 16px 16px;font-size:13px;font-weight:440;color:rgba(255,255,255,.66);line-height:1.35}
    /* The type stack rides the card's bottom, over the scrim. */
    .ar-night{display:flex;flex-direction:column;justify-content:flex-end}
    .ar-night-meta{display:block;margin-top:8px;font:500 10px/1 var(--sl-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--sl-faint,#6b6f78)}
    /* ---- THE YEAR STRIP (Alex, 2026-07-28) ----
       The Codex Atlanticus gesture wearing Burnthday's clothes: a count and a
       long arrow on the left, a free-scrolling filmstrip of the whole catalog
       on the right. One photograph per year; the frames AGE with the band —
       Polaroid white borders and warm fade in the club years, dark Super-8
       card through the 90s, thin print border in the 2000s, clean digital
       after. The year numerals are the hand (Panic-Hand), because the years
       belong to Garrie's world, not the UI's. */
    .ar-yearstrip{display:grid;grid-template-columns:132px minmax(0,1fr);gap:26px;align-items:center;padding:0 0 clamp(4px,.6vw,8px)}
    /* THE SPACING NEEDS THE SPECIFICITY (the hazard docs/HANDOFF names): the
       sitewide rhythm rule is body.stagelight main > section at margin-top 96px,
       at 0,1,3 — a bare .ar-yearstrip at 0,1,0 loses silently, which is why the
       strip still sat 96px below the featured image and threw 84px at Latest
       Shows after the margin was "reduced". Alex, 7/29: "why is there so much
       white space?" — 180px of air around a 188px strip. */
    body.stagelight .ar-yearstrip{margin-top:clamp(16px,2vw,28px)}
    body.stagelight .ar-yearstrip + section{margin-top:clamp(24px,3vw,44px)}
    .ar-ys-side{display:block}
    .ar-ys-head{margin:0;font:700 clamp(19px,1.8vw,24px)/1.2 var(--sl-display);letter-spacing:-.02em;color:#fff}
    .ar-ys-viewport{overflow:hidden;cursor:grab;touch-action:pan-y;outline:none;
      -webkit-mask-image:linear-gradient(90deg,transparent,#000 34px,#000 calc(100% - 34px),transparent);
      mask-image:linear-gradient(90deg,transparent,#000 34px,#000 calc(100% - 34px),transparent)}
    .ar-ys-viewport:active{cursor:grabbing}
    .ar-ys-viewport:focus-visible{outline:2px solid rgba(255,255,255,.7);outline-offset:4px}
    .ar-ys-track{display:flex;align-items:flex-end;gap:clamp(14px,1.6vw,22px);padding:34px 34px 6px;width:max-content;will-change:transform}
    .ar-ys-item{display:flex;flex-direction:column;align-items:center;gap:9px;color:inherit;text-decoration:none;transform:rotate(var(--tilt,0deg));transition:transform .28s cubic-bezier(.22,1,.36,1)}
    .ar-ys-item:hover,.ar-ys-item:focus-visible{transform:rotate(0deg) translateY(-6px) scale(1.32);z-index:2}
    .ar-ys-frame{position:relative;display:block;width:56px;height:74px;overflow:hidden;background:#14161c}
    .ar-ys-frame img{width:100%;height:100%;object-fit:cover;object-position:center 30%;display:block}
    .ar-ys-blank{display:grid;place-items:center;width:100%;height:100%;color:rgba(255,255,255,.22);font:600 11px/1 var(--sl-mono)}
    .ar-ys-credit{position:absolute;left:0;right:0;top:0;z-index:3;padding:3px 4px;
      font:600 7px/1.25 var(--sl-mono);letter-spacing:.04em;text-align:center;color:rgba(255,255,255,.94);
      background:linear-gradient(180deg,rgba(0,0,0,.82),rgba(0,0,0,0));
      opacity:0;transition:opacity .18s ease;pointer-events:none;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .ar-ys-item:hover .ar-ys-credit,.ar-ys-item:focus-visible .ar-ys-credit{opacity:1}
    @media(prefers-reduced-motion:reduce){.ar-ys-credit{transition:none}}
    .ar-ys-year{font-family:"PanicHand","MilkRun",sans-serif;font-size:19px;line-height:1;color:var(--sl-muted);transition:color .2s}
    .ar-ys-item:hover .ar-ys-year,.ar-ys-item:focus-visible .ar-ys-year{color:#fff}
    /* era treatments — the photographs age with the band */
    /* THE DRUGSTORE PRINT, not a Polaroid (Alex asked whether Polaroids were a
       thing in '85 — they were, but HIS photographs are 35mm 4x6 prints, and
       a Polaroid frame is a costume that doesn't match the garment). Thin
       even white border, glossy, warm and slightly faded, with the orange
       film date-stamp those cameras burned into the corner. */
    .ar-ys-item.is-polaroid .ar-ys-frame{border:5px solid #f2ede1;border-bottom-width:15px;box-shadow:0 9px 20px rgba(0,0,0,.52)}
    .ar-ys-item.is-polaroid img{filter:sepia(.3) contrast(1.02) saturate(.76) brightness(1.05)}
    .ar-ys-item.is-print35 .ar-ys-frame{border:3px solid #f4f1e8;box-shadow:0 8px 18px rgba(0,0,0,.5)}
    .ar-ys-item.is-print35 img{filter:sepia(.24) contrast(1.03) saturate(.82) brightness(1.03)}
    .ar-ys-item.is-print35 .ar-ys-frame::after{content:attr(data-stamp);position:absolute;right:4px;bottom:3px;z-index:2;
      font:600 6.5px/1 var(--sl-mono);letter-spacing:.02em;color:#ff8a3d;text-shadow:0 0 3px rgba(255,120,40,.55);opacity:.92}
    .ar-ys-item.is-film .ar-ys-frame{border:3px solid #1c1a17;box-shadow:0 6px 16px rgba(0,0,0,.55),inset 0 0 0 1px rgba(255,244,214,.14)}
    .ar-ys-item.is-film img{filter:saturate(.62) contrast(1.12) brightness(.96) sepia(.12)}
    .ar-ys-item.is-print .ar-ys-frame{border:1px solid rgba(255,255,255,.24);box-shadow:0 6px 16px rgba(0,0,0,.45)}
    .ar-ys-item.is-print img{filter:saturate(.9)}
    .ar-ys-item.is-digital .ar-ys-frame{box-shadow:0 8px 20px rgba(0,0,0,.5);border:1px solid rgba(255,255,255,.12)}
    @media(max-width:820px){
      .ar-yearstrip{grid-template-columns:1fr;gap:2px;margin-top:8px}
      .ar-ys-item:hover,.ar-ys-item:focus-visible{transform:rotate(0deg) translateY(-3px) scale(1.14)}
    }
    @media(prefers-reduced-motion:reduce){.ar-ys-item{transition:none}}

    /* ---- THE LIFELINE RIBBON (song pages) ---- */
    /* The dye caps: the song title's first letters take the same ramp as the
       silk below — clipped to the glyphs, lightened well past half so it
       reads as a wash, drifting on the same slow clock as a playing song. */
    .ar-dye-cap{color:transparent;background-image:linear-gradient(rgba(242,242,240,.52),rgba(242,242,240,.52)),var(--ar-tie);background-size:100% 100%,240% 100%;-webkit-background-clip:text;background-clip:text;animation:ar-tiedye 12s ease-in-out infinite alternate}
    @media(prefers-reduced-motion:reduce){.ar-dye-cap{animation:none}}
    .ar-lifeline{margin-top:clamp(40px,5vw,64px)}
    .ar-ribbonwrap{position:relative;cursor:crosshair}
    .ar-ribbon-canvas{display:block;width:100%}
    .ar-ribbon-tip{position:absolute;top:6px;padding:5px 10px;border:1px solid var(--sl-line-strong);border-radius:999px;background:rgba(10,10,13,.82);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:var(--sl-ink);font:600 11px/1 var(--sl-mono);letter-spacing:.06em;pointer-events:none;white-space:nowrap}

    /* ---- THE GARRIE SEPARATOR (parked 7/22, unparked 2026-07-28) ----
       Two lazy strokes meeting his hand-looped "o", heavier ink where the pen
       lands, drawn with real pen pacing when it scrolls into view. The strip
       above carries no hairlines — this is the punctuation. */
    .ar-garrie{display:block;width:min(560px,calc(100% - 12px));height:auto;margin:clamp(4px,.8vw,8px) auto -16px;overflow:visible}
    .ar-garrie path{fill:none;stroke:rgba(255,255,255,.6);stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
    .ar-garrie .ln{stroke-width:2.2}
    /* The press marks were sitting AT the stroke ends, doubling the ink and
       reading as hot white tips (Alex). They live mid-stroke now, and their
       weight came down a step. */
    .ar-garrie .press{stroke-width:2.35;stroke:rgba(255,255,255,.34)}
    .ar-garrie .oo{stroke-width:2}
    .ar-garrie.anim .ah1{stroke-dasharray:34;stroke-dashoffset:34;animation:garrie-d 170ms cubic-bezier(.5,.05,.35,1) forwards}
    .ar-garrie.anim .l1{stroke-dasharray:244;stroke-dashoffset:244;animation:garrie-d 520ms cubic-bezier(.45,.05,.4,1) 140ms forwards}
    .ar-garrie.anim .p1{opacity:0;animation:garrie-ink 240ms linear 260ms forwards}
    .ar-garrie.anim .oo{stroke-dasharray:64;stroke-dashoffset:64;animation:garrie-d 240ms cubic-bezier(.5,.05,.35,1.08) 620ms forwards}
    .ar-garrie.anim .l2{stroke-dasharray:244;stroke-dashoffset:244;animation:garrie-d 520ms cubic-bezier(.45,.05,.4,1) 840ms forwards}
    .ar-garrie.anim .p2{opacity:0;animation:garrie-ink 160ms ease-in 1150ms forwards}
    .ar-garrie.anim .ah2{stroke-dasharray:34;stroke-dashoffset:34;animation:garrie-d 180ms cubic-bezier(.5,.05,.35,1.06) 1370ms forwards}
    .ar-garrie:not(.anim) path{opacity:0}
    @keyframes garrie-d{to{stroke-dashoffset:0}}
    @keyframes garrie-ink{to{opacity:1}}
    @media(prefers-reduced-motion:reduce){.ar-garrie:not(.anim) path{opacity:1}.ar-garrie.anim path{animation:none;stroke-dashoffset:0;opacity:1}}

    /* ---- ONE CARD HOVER, SITE-WIDE ----
       Ported verbatim in feel from the homepage's cross-promo cards (.xp-card,
       in renderStagelightCss): a 4px lift, a deeper shadow, the hairline coming
       up to .24 white, and the artwork easing in ~5%. Nothing tints.
       WHAT THIS REPLACED, and why: hovering a night used to run the date through
       --ar-tie, whose first stop is #d4514f — a red wash across the one line on
       the card that has to stay legible, on a different treatment from every
       other card on the site. Tie-dye still means exactly one thing here, and it
       is the thing it means everywhere else: this song is playing. It is not a
       hover colour. Every card below (.ar-night, .ar-songcard, .ar-placecard,
       .ar-eracard, the front-door lead) now shares these numbers. */
    /* THE TYPE DOES NOT MOVE (Alex, 7/28: translating the whole card "looks
       cheap"). Lifting the entire card drags the date, the city and the venue
       with it, which reads as a widget animating rather than a photograph
       responding. The frame stays exactly where it is and the IMAGE answers
       inside it — the same thing the homepage's own cards do. */
    .ar-night-media{transition:border-color .28s ease,box-shadow .28s ease}
    .ar-night:hover .ar-night-media.has-art::before,.ar-night:focus-visible .ar-night-media.has-art::before{transform:scale(1.05)}
    .ar-night:hover .ar-night-media,.ar-night:focus-visible .ar-night-media{border-color:rgba(255,255,255,.24);box-shadow:0 26px 60px -22px rgba(0,0,0,.85)}
    .ar-night:hover .ar-night-city,.ar-night:focus-visible .ar-night-city{color:#fff}
    .ar-night:focus-visible{outline:none}
    .ar-night:focus-visible .ar-night-media{outline:2px solid var(--sl-ink,#f2f2f0);outline-offset:3px}
    .ar-night-fallback{z-index:1}
    /* HOVER-PLAY, NUGS-STYLE (Alex's punch list #7): a play button surfaces at
       the lower-left of the card art on hover and starts that night without
       leaving the page — the card itself still navigates. Hidden until hover
       (and keyboard focus) so the grid stays a wall of photographs; the HERO
       keeps its embedded player and never hides controls behind a hover. */
    /* Top-right of the card (Alex, 7/29) — bottom-left sat under the card's
       own text and read as part of it; the corner keeps it clearly a control
       on the photograph. */
    .ar-card-play{position:absolute;z-index:2;right:12px;top:12px;display:grid;place-items:center;width:42px;height:42px;padding:0;border:1px solid rgba(255,255,255,.35);border-radius:50%;background:rgba(10,10,12,.62);color:#fff;cursor:pointer;opacity:0;transform:translateY(6px);transition:opacity .22s ease,transform .22s ease,background .16s;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
    .ar-card-play svg{width:13px;height:14px;margin-left:2px}
    .ar-night:hover .ar-card-play,.ar-card-play:focus-visible{opacity:1;transform:none}
    .ar-card-play:hover{background:#fff;color:#111;border-color:#fff}
    @media(hover:none){.ar-card-play{opacity:1;transform:none;width:38px;height:38px}}
    @media(prefers-reduced-motion:reduce){.ar-card-play{transition:none}}
    @media(prefers-reduced-motion:reduce){
      .ar-night-media,.ar-night-media::before{transition:none}
      .ar-night:hover .ar-night-media.has-art::before{transform:none}
    }
    /* The lead is the show hero now, and a page hero does not lift under the
       pointer — the grid cards below it carry the hover language. Its own links
       and chips still answer the pointer through their own rules. */

    /* ---- show notes: history, kept apart from tape metadata ---- */
    .ar-notes{margin-top:clamp(34px,4vw,52px);padding-top:22px;border-top:1px solid var(--sl-line,rgba(255,255,255,.1))}
    .ar-guests{margin:0;padding:0;list-style:none;display:grid;gap:7px}
    .ar-guests li{font-size:15.5px;line-height:1.5;color:var(--sl-muted)}
    .ar-guests strong{color:var(--sl-ink);font-weight:640}
    .ar-notelist{margin:14px 0 0;padding:0;list-style:none;display:grid;gap:6px}
    .ar-guests+.ar-notelist{margin-top:16px;padding-top:14px;border-top:1px solid var(--sl-line,rgba(255,255,255,.07))}
    .ar-notelist li{position:relative;padding-left:16px;font-size:14px;line-height:1.55;color:var(--sl-muted)}
    .ar-notelist li::before{content:"";position:absolute;left:0;top:.62em;width:5px;height:5px;border-radius:50%;background:var(--ar-tie);background-size:300% 100%;opacity:.75}
    .ar-notes-source{display:inline-block;margin-top:15px;color:var(--sl-faint,#6b6f78);font:500 10.5px/1 var(--sl-mono);letter-spacing:.1em;text-transform:uppercase}
    .ar-notes-source:hover{color:var(--sl-ink)}
    .ar-mark{margin-left:2px;color:var(--sl-muted);font-size:.72em;vertical-align:super;text-decoration:none;cursor:help}
    /* line-height:0 + relative offset instead of vertical-align:super: a
       superscript raised by vertical-align grows the line box it sits in, so a
       single guest credit pushed one line of a 2.05-line-height setlist apart
       from its neighbours. This lifts the digit without it counting toward the
       line box at all, so a credited song sits on exactly the same baseline as
       an uncredited one. */
    .ar-guest-sup{margin-left:2px;color:var(--sl-muted);font:600 .62em/0 var(--sl-mono);position:relative;top:-.5em;letter-spacing:.05em}
    .ar-guests .ar-guest-sup{margin-left:0;margin-right:2px}
    .ar-unitlist{margin-top:12px}
    /* The lineup closes Show Notes. It describes the whole night rather than a
       moment in it, so it sits under everything and reads as the frame the rest
       happened inside — set off by a hairline rather than by another bullet. */
    .ar-lineup-note{margin-top:14px;padding-top:12px;border-top:1px solid var(--sl-line,rgba(255,255,255,.07))}
    .ar-lineup-note li::before{display:none}
    .ar-lineup-note li{padding-left:0;color:var(--sl-ink)}

    /* ---- songs / places / eras ---- */
    .ar-listhead h1{font-size:clamp(44px,7vw,96px)}
    .ar-filter{width:min(420px,100%);margin-top:22px;padding:14px 17px;border:1px solid var(--sl-line-strong);border-radius:11px;background:rgba(255,255,255,.04);color:var(--sl-ink);font:500 16px/1 var(--sl-display)}
    .ar-filter:focus{outline:2px solid rgba(255,255,255,.5);outline-offset:2px}
    .ar-songgrid,.ar-placegrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(212px,100%),1fr));gap:8px;margin-top:clamp(30px,4vw,48px)}
    .ar-songcard,.ar-placecard{display:block;padding:16px 17px;border:1px solid var(--sl-line);border-radius:12px;color:inherit;transition:transform .28s ease,box-shadow .28s ease,border-color .28s ease,background .28s ease}
    /* Same hover as the night cards and the homepage's cross-promo pair. */
    /* Text-only cards have no image to respond, so they answer with surface and
       hairline alone — never by moving the words. */
    .ar-songcard:hover,.ar-placecard:hover,.ar-songcard:focus-visible,.ar-placecard:focus-visible{border-color:rgba(255,255,255,.28);background:rgba(255,255,255,.06);box-shadow:0 20px 44px -24px rgba(0,0,0,.8)}
    @media(prefers-reduced-motion:reduce){.ar-songcard,.ar-placecard{transition:none}}
    .ar-songcard strong,.ar-placecard strong{display:block;font:620 16px/1.25 var(--sl-display);letter-spacing:-.015em}
    .ar-songcard span,.ar-placecard span{display:block;margin-top:6px;color:var(--sl-muted);font-size:12.5px}
    .ar-placecard-n{font-family:var(--sl-mono);font-size:10.5px !important;letter-spacing:.06em;color:var(--sl-faint,#6b6f78) !important}
    .ar-lifeline-bars{display:flex;align-items:flex-end;gap:2px;height:150px}
    .ar-lifeline-bar{position:relative;flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;height:100%;color:inherit}
    .ar-lifeline-bar::before{content:"";width:100%;height:var(--h);border-radius:2px 2px 0 0;background:var(--ar-tie);background-size:180% 100%;opacity:.75;transition:opacity .16s}
    .ar-lifeline-bar.is-quiet::before{background:rgba(255,255,255,.13)}
    .ar-lifeline-bar:hover::before{opacity:1}
    .ar-lifeline-bar span{margin-top:7px;color:var(--sl-faint,#6b6f78);font:500 9px/1 var(--sl-mono)}
    /* Search results open on the count, not on a restatement of the query. The
       kicker carries the count at kicker weight, and the term follows quietly. */
    .ar-listhead.is-results{margin-bottom:clamp(18px,2.4vw,30px)}
    .ar-listhead.is-results .ar-kicker{font:600 13px/1.2 var(--sl-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--sl-ink)}
    .ar-results-for{margin-top:6px;color:var(--sl-muted);font-size:14.5px}
    .ar-results-for strong{color:var(--sl-ink);font-weight:600}
    .ar-eragrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(258px,100%),1fr));gap:12px;margin-top:clamp(30px,4vw,48px)}
    .ar-eracard{display:block;padding:26px 24px;border:1px solid var(--sl-line-strong);border-radius:16px;color:inherit;transition:transform .28s ease,box-shadow .28s ease,border-color .28s ease,background .28s ease}
    .ar-eracard:hover,.ar-eracard:focus-visible{border-color:rgba(255,255,255,.28);background:rgba(255,255,255,.06);box-shadow:0 20px 44px -24px rgba(0,0,0,.8)}
    @media(prefers-reduced-motion:reduce){.ar-eracard{transition:none}}
    .ar-eracard strong{display:block;margin:12px 0 9px;font:650 24px/1.1 var(--sl-display);letter-spacing:-.025em}
    .ar-eracard-n{display:block;margin-top:16px;padding-top:13px;border-top:1px solid var(--sl-line);color:var(--sl-faint,#6b6f78);font:500 10.5px/1 var(--sl-mono);letter-spacing:.07em;text-transform:uppercase}

    /* ---- the dock: the player follows you through the archive ---- */
    /* D1 (Alex): the page reserved a flat 96px for a dock that measures ~71px,
       leaving a dead strip between the footer and the player. --player-h is
       published by the dock itself (ResizeObserver), so the reservation now
       matches the bar exactly and the footer ends flush against it. The 96px
       fallback only applies for the frame before the first measurement. */
    body.has-dock{padding-bottom:var(--player-h,96px)}
    /* body.stagelight > * { position: relative } in the site stylesheet
       out-specifies a bare .ar-dock and silently un-fixes the player. Matching
       its specificity is what keeps the dock pinned to the viewport. */
    body.listen-archive > .ar-dock{position:fixed;z-index:60;left:0;right:0;bottom:0;border-top:1px solid rgba(255,255,255,.16);background:rgba(12,13,17,.82);-webkit-backdrop-filter:blur(26px) saturate(1.5);backdrop-filter:blur(26px) saturate(1.5)}
    /* THREE ZONES: what's playing | the transport, centred | volume.
       The homepage dock (.hero-player.is-docked, in the stagelight sheet) is
       built to these same numbers on purpose — 68px tall, 44px art at radius 8,
       a 14px/620 title over a 10.5px mono context line, the transport column
       capped at 560px, a 90px volume slider hard right. One player, two
       surfaces; if a number moves here it moves there. */
    /* One gutter for the whole app (Alex): the header's content runs
       max(28px, (100% - 1400px)/2) from each edge — the shell, the lead
       image and the dock's contents all line up to the same rails now. */
    .ar-dock-inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,560px) minmax(0,1fr);column-gap:20px;align-items:center;width:100%;min-height:68px;margin:0 auto;padding:5px max(28px,calc(50% - 700px))}
    .ar-dock-now{display:flex;align-items:center;gap:12px;min-width:0}
    .ar-dock-art{flex:none;width:44px;height:44px;padding:0;border:1px solid rgba(255,255,255,.16);border-radius:8px;overflow:hidden;background:none;cursor:pointer}
    .ar-dock-art-fill{display:block;width:100%;height:100%;background-size:cover;background-position:center;background-image:linear-gradient(150deg,hsl(var(--tone,210) 48% 30%),#0c0d11)}
    .ar-dock-id{min-width:0}
    .ar-dock-id strong{display:block;font-size:14px;font-weight:620;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .ar-dock-id span{display:block;margin-top:3px;color:var(--sl-muted);font:500 10.5px/1.3 var(--sl-mono);letter-spacing:.08em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .ar-dock-center{display:grid;justify-items:center;row-gap:4px;width:100%}
    .ar-dock-side{display:flex;align-items:center;justify-content:flex-end;gap:8px;color:rgba(255,255,255,.7)}
    .ar-vol-icon{display:block;width:16px;height:16px;flex:none}
    .ar-volume{--progress:100%;appearance:none;width:90px;height:16px;margin:0;background:transparent;cursor:pointer}
    .ar-volume::-webkit-slider-runnable-track{height:3px;border-radius:99px;background:linear-gradient(90deg,rgba(255,255,255,.85) var(--progress),rgba(255,255,255,.24) var(--progress))}
    .ar-volume::-webkit-slider-thumb{appearance:none;width:11px;height:11px;margin-top:-4px;border:0;border-radius:50%;background:#fff}
    .ar-volume::-moz-range-track{height:3px;border-radius:99px;background:rgba(255,255,255,.24)}
    .ar-volume::-moz-range-progress{height:3px;border-radius:99px;background:rgba(255,255,255,.85)}
    .ar-volume::-moz-range-thumb{width:11px;height:11px;border:0;border-radius:50%;background:#fff}
    .ar-volume:focus-visible{outline:2px solid #fff;outline-offset:3px}
    .ar-dock-controls{display:flex;align-items:center;gap:12px}
    .ar-toggle,.ar-skip{display:grid;place-items:center;padding:0;border-radius:50%;cursor:pointer}
    .ar-nb{white-space:nowrap}
    .ar-toggle{width:38px;height:38px;border:0;background:#f4f0e8;color:#111;position:relative}
    /* A thumb needs 44px+ (Apple HIG); the visual stays 38px, the tappable
       area grows underneath — part of the "pause sometimes doesn't respond"
       fix (Alex, 2026-07-28). */
    .ar-toggle::after{content:"";position:absolute;inset:-8px}
    .ar-toggle svg{width:15px;height:17px}
    .ar-skip{position:relative;width:30px;height:30px;border:1px solid rgba(255,255,255,.24);background:none;color:rgba(255,255,255,.86)}
    /* Visible ring 32px, thumb target 44px — the halo is invisible and costs no layout. */
    .ar-skip::after{content:"";position:absolute;inset:-6px;border-radius:50%}
    .ar-skip svg{width:14px;height:14px}
    .ar-skip:disabled{opacity:.3;cursor:default}
    .ar-toggle:focus-visible,.ar-skip:focus-visible,.ar-scrubber:focus-visible{outline:2px solid #fff;outline-offset:3px}
    .ar-dock-timeline{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:11px;align-items:center;width:100%}
    .ar-clock{color:rgba(255,255,255,.8);font:600 11px/1 var(--sl-mono);font-variant-numeric:tabular-nums}
    .ar-scrubber{--progress:0%;appearance:none;width:100%;height:18px;margin:0;background:transparent;cursor:pointer;touch-action:none}
    .ar-scrubber::-webkit-slider-runnable-track{height:4px;border-radius:99px;background:linear-gradient(90deg,#fff var(--progress),rgba(255,255,255,.24) var(--progress))}
    .ar-scrubber::-webkit-slider-thumb{appearance:none;width:13px;height:13px;margin-top:-4.5px;border:0;border-radius:50%;background:#fff}
    .ar-scrubber::-moz-range-track{height:4px;border-radius:99px;background:rgba(255,255,255,.24)}
    .ar-scrubber::-moz-range-progress{height:4px;border-radius:99px;background:#fff}
    .ar-scrubber::-moz-range-thumb{width:13px;height:13px;border:0;border-radius:50%;background:#fff}
    /* Only loading and failure ever reach this line — see muteIdleStatus in
       archive-app.mjs. Empty means gone, not an empty row. */
    .ar-dock-status{margin:0;color:rgba(255,255,255,.62);font:500 10.5px/1.4 var(--sl-mono);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
    .ar-dock-status:empty{display:none}

    /* The sheet's grab/dismiss chevron is a mobile-only control. Unsized, its
       SVG inflates to intrinsic size and swallows the desktop dock. */
    .dock-grab{display:none}
    .dock-grab svg{width:18px;height:18px}
    @media(max-width:820px){.ar-dock.is-sheet .dock-grab{display:grid;place-items:center}}

    /* ---- tablet ---- */
    @media(max-width:1100px){
      .ar-shell{--rail-w:190px;--rail-full:190px;--rail-gap:30px}
      .ar-show-body{grid-template-columns:1fr;gap:38px}
      .ar-show.is-split{grid-template-columns:1fr;grid-template-areas:"head" "visual" "main" "side"}
      .ar-show.is-split .ar-show-visual{position:static}
      .ar-month{grid-template-columns:96px minmax(0,1fr);gap:18px}
    }

    /* ---- mobile ----
       DELETED (Alex, 7/28): the chip rails and the standalone search block that
       used to sit on top of every /listen/ view. "Your version with all the sort
       bars and search bars just doesn't make sense." The rail is now the drawer
       behind the head's hamburger — the SAME .ar-cabinet element, restyled as a
       panel in the shared mobile-chrome block — so nothing above the content
       competes with the show. What is left here is the canvas, which now starts
       at the top of the page because the navigation is no longer stacked on it. */
    @media(max-width:820px){
      .ar-shell{display:block;width:calc(100% - 32px);padding-top:0;padding-bottom:104px}
      /* Flush. The canvas's first child carried the page's leading, which put a
         hairline of background between the head and a full-bleed photograph. */
      .ar-canvas>section:first-child,body.listen-archive .ar-canvas>section:first-child,.ar-canvas>.ar-show{margin-top:0}
      .ar-main{padding-top:0}
      .ar-canvas h1{font-size:clamp(34px,9.5vw,50px)}
      .ar-yearhead h1,.ar-listhead h1{font-size:clamp(52px,17vw,84px)}
      /* The ribbon scrolls horizontally on mobile at ~2.2x width so nodes stay
         tappable instead of shrinking to dust. */
      /* THE RIBBON IS A DESKTOP INSTRUMENT (Alex, 7/28: "it really doesn't
         work" on a phone). It was made to scroll sideways at 220% width, which
         asked a thumb to aim at labelled blocks inside a horizontally scrolling
         strip inside a vertically scrolling page — three gestures competing over
         the same square inch. The month-grouped chronology directly below it
         already carries the whole year in a form a thumb can actually use, so
         the strip simply steps aside here rather than being made worse. The
         sideways-scroll treatment is deleted with it, not left as dead CSS. */
      .ar-ribbon{display:none}
      .ar-echo{height:340px}
      .ar-row{grid-template-columns:70px minmax(0,1fr) auto;gap:6px 12px;padding:12px 4px}
      .ar-row-city{grid-column:2;grid-row:1}
      .ar-row-venue{grid-column:2;grid-row:2;font-size:12.5px}
      .ar-row time{grid-row:1/3}
      .ar-row-count{grid-column:3;grid-row:1/3;align-self:center}
      .ar-month{display:block}
      .ar-month h3{position:static;margin-bottom:10px}
      .ar-block-night{grid-template-columns:30px minmax(0,1fr) auto;gap:4px 12px;padding:10px 6px}
      .ar-block-city{grid-column:2;grid-row:1}
      .ar-block-venue{grid-column:2;grid-row:2;white-space:normal}
      .ar-block-night time{grid-row:1/3}
      .ar-block-count{grid-column:3;grid-row:1/3;align-self:center}
      /* The stage goes edge to edge — it is the night, not a card. */
      /* THE NIGHT, FULL BLEED (Alex, 7/28). Both screen edges, and flush against
         the bottom of the head — the shell's top padding is gone and the stage
         pulls up over the canvas's own leading, so there is no strip of page
         between the bar and the photograph. Its natural 16:9, not the 4/5 crop:
         a portrait letterbox of a landscape photo was showing less of the show
         and taking more of the screen. */
      /* The stage stops being a frame with words inside it and becomes two
         things stacked: the photograph, then the night. At 16:9 there is no
         longer room to lay a headline, a venue and a Play button over a picture
         only ~220px tall — crushing them onto it is how the old 4/5 crop
         happened. So the image is the image, and the identity block drops into
         the flow underneath it where it can be read. */
      /* max-width:none is load-bearing. The base rule carries max-width:100% (it
         stops aspect-ratio + min-height resolving a width WIDER than the column
         on desktop), and here that clamped this full-bleed to the column's 338px
         while the negative margin still pulled it 26px left — so the photograph
         sat flush against the left edge and stopped 52px short of the right. That
         asymmetric gap is the "dead right-hand strip". */
      .ar-show-stage{position:relative;width:100vw;max-width:none;margin-left:calc((100% - 100vw)/2);margin-top:0;border-radius:0;border:0;aspect-ratio:auto;min-height:0;max-height:none;overflow:visible;isolation:auto}
      /* NATURAL RATIO (design system: setlist photography is never cropped). The
         16:9 box turned a 759x1024 portrait into a 1.78 letterbox — most of the
         frame thrown away. The image now sets its own height. */
      .ar-stage{position:relative;inset:auto;display:block;width:100%;aspect-ratio:auto}
      .ar-stage-empty{position:relative;inset:auto;width:100%;aspect-ratio:16/9}
      /* The scrim exists to make white type legible on a photo. With the type
         off the photo it is just mud on the picture. */
      .ar-stage::after{background:linear-gradient(180deg,rgba(4,4,6,.28) 0%,rgba(4,4,6,0) 38%,rgba(4,4,6,.42) 100%)}
      .ar-show-id{position:static;padding:22px 16px 0}
      .ar-show.is-split{display:flex;flex-direction:column;align-items:stretch}
      .ar-show.is-split .ar-show-visual{order:-1}
      .ar-show.is-split .ar-show-head{padding:22px 16px 0}
      .ar-show.is-split .ar-show-head h1{margin:9px 0 4px;font-size:clamp(34px,9.5vw,52px)}
      /* THE LEAD CARD KEEPS ITS COMPOSITION AT EVERY SIZE (Alex, 2026-07-28:
         identity inside the card on the front door, below the photo on show
         pages, and the image size never changes on mobile). The static-id
         mobile pattern above is the SHOW PAGE's; the front door's lead pins
         the identity back into the photograph over a bottom-third scrim. */
      .ar-show-stage.is-lead{overflow:hidden;border-radius:0}
      .ar-show-stage.is-lead .ar-show-id{position:absolute;left:16px;right:16px;bottom:18px;padding:0;z-index:2}
      .ar-show-stage.is-lead .ar-stage::after{background:linear-gradient(180deg,rgba(4,4,6,0) 40%,rgba(4,4,6,.55) 72%,rgba(4,4,6,.92) 100%)}
      /* The song count and the lineup stop sharing a line here, so the dot that
         joined them is left hanging at the end of one. */
      .ar-show-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:12px}
      .ar-show-id h1{margin:9px 0 4px;font-size:clamp(34px,9.5vw,52px)}
      .ar-show-body{margin-top:26px}
      .ar-canvas>.ar-show{margin-top:0}
      .ar-stage figcaption{display:none}
      .ar-show-actions{gap:11px;margin-top:17px;margin-bottom:14px}
      .ar-set{grid-template-columns:1fr;gap:5px}
      .ar-set-label{padding-top:0}
      /* Thumb-sized songs. The button box is 25px of type; 8px of padding takes
         it to 41px of hit area and an equal negative margin hands the 16px back
         to the line box, so the setlist keeps its own line breaks. The line-height
         is opened to 2.4 so two padded songs on consecutive lines cannot touch.
         The underline is re-anchored to the text rather than the padding edge. */
      .ar-set-songs{font-size:18px;line-height:2.4}
      .ar-song{padding:10px 0;margin:-10px 0}
      .ar-song::after{bottom:calc(10px - .02em)}
      .ar-nights{grid-template-columns:1fr 1fr;gap:12px}
      .ar-night-city{font-size:16px}
      .ar-night-venue{font-size:12.5px}
      .ar-songgrid,.ar-placegrid{grid-template-columns:1fr 1fr;gap:7px}
      .ar-songcard,.ar-placecard{padding:13px 14px}
      .ar-songcard strong,.ar-placecard strong{font-size:14.5px}
      /* Dock: title + transport stay reachable; the scrubber becomes a hairline
         at the very top edge so nothing competes for the thumb. */
      /* Content must be able to scroll clear of the dock, or the last line of a
         setlist sits underneath it forever. */
      body.has-dock .ar-shell{padding-bottom:104px}
      body.has-dock{padding-bottom:0}
      .ar-dock-inner{grid-template-columns:minmax(0,1fr) auto;column-gap:12px;width:100%;min-height:64px;padding:9px 14px calc(9px + env(safe-area-inset-bottom,0px))}
      .ar-dock-side{display:none}
      .ar-dock-center{width:auto;row-gap:0}
      .ar-dock-timeline{position:absolute;left:0;right:0;top:0;max-width:none;grid-template-columns:minmax(0,1fr);gap:0}
      .ar-dock-timeline .ar-clock{display:none}
      .ar-scrubber{height:14px;margin-top:-7px}
      .ar-dock-controls .ar-skip{display:none}
      .ar-dock-controls .ar-skip[data-listen-next]{display:grid}
    }
    @media(max-width:400px){
      /* The stage is a plain block below 820px — the photograph inside it owns
         the 16:9, and pinning the wrapper to a ratio here clipped the identity
         block into the setlist. */
      .ar-songgrid,.ar-placegrid{grid-template-columns:1fr}
    }
    @media(prefers-reduced-motion:reduce){
      /* The leading fill still shows where the show is; it just snaps to each
         reading instead of crawling between them. */
      .ar-song,.ar-song::after,.ar-song.is-leading,.ar-invite,.ar-invite-wild::before,.ar-songcard,.ar-placecard,.ar-eracard,.ar-spine-bar::before{transition:none}
      .ar-song.is-current,.ar-invite-wild::before{animation:none}
    }
  