/* ===== Engraved Edition — music catalog page polish (desktop-only) =====
   Pairs with /assets/css/edition.25ad1e04.css (shared hardware). */

/* ---- First-load stability -------------------------------------------------
   The featured block and the collections grid are injected by JS well after
   first paint, so the page rendered near-empty and then shoved everything down
   as each arrived (measured CLS 1.00 — "good" is under 0.1). Reserving the
   space they settle at keeps the layout still while they load. Values are the
   measured settled heights at desktop widths; the blocks may exceed them with
   unusually long copy, which only costs a small shift rather than a full one. */
@media (min-width: 1025px) {
  /* 900, not 848: the audio preview no longer folds away, so the block settles
     ~47px taller than it used to. Measured at 895px — the spare 5px is for copy
     that runs a line longer, since being slightly over costs nothing and being
     under costs a shift. */
  #catalog-new-releases-host { min-height: 900px; }
  #collections-bg-shell { min-height: 420px; }
  /* The placeholder appeared abruptly, then collapsed from ~400px to ~64px a
     few hundred ms before the real content replaced it — read as a flash.
     Fading it in and holding it at the height the content settles at makes the
     wait one steady state instead of three. */
  @keyframes ee-placeholder-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
  #catalog-new-releases-host #news-new-release-scaffold {
    min-height: 452px;
    animation: ee-placeholder-in 0.28s ease both;
  }
  #catalog-new-releases-host #news-new-release-scaffold .scaffold-image {
    flex: 0 0 320px;
    max-width: 320px;
  }
  /* Match the settled cover width so the swap doesn't jump sideways either */
  #catalog-new-releases-host #news-new-release-scaffold .composition-image {
    flex: 0 0 320px !important;
    max-width: 320px !important;
  }

  /* Thumbnails sized from their own content sat at min-width until the image
     arrived, then grew toward max-width and nudged their neighbours along the
     rail. A fixed basis holds every tile still through image load. */
  #catalog-new-releases-host .nr-thumb {
    flex: 0 0 220px !important;
    width: 220px !important;
    min-width: 220px !important;
    max-width: 220px !important;
  }
  /* Once a collection is expanded the shell is hidden and the panel sets its
     own height — don't hold empty space open underneath it. */
  #catalog-collections-section.expanded-panel-open #collections-bg-shell { min-height: 0; }
}
/* Music catalog — page-specific polish.
   Depends on /assets/css/edition.25ad1e04.css for the shared tokens and hover tiers.

   The page reads as a printed catalogue: covers are plates that sit flat and
   lift when you reach for them, sheets carry a hairline and a square cast, and
   labels are small-caps stamps. Desktop only — layout, sticky behaviour,
   carousel mechanics and the centred cover overlay are all left as they were.

   Three earlier ideas were tried and removed, so they do not get reintroduced:
   a serif display face (Fraunces), a "final barline" rule under the headings,
   and a gold accent. The headings keep the site's original stroke treatment. */
    @media (min-width: 1025px) {
      :root {
        --ee-ink: hsl(221, 39%, 13%);
      }

      /* ---------- 1 · Featured work: the frontispiece ---------- */
      #catalog-new-releases-host .composition-title {
        font-size: clamp(1.55rem, 1.15rem + 0.8vw, 2rem) !important;
        font-weight: 900 !important;
        letter-spacing: -0.022em !important;
        line-height: 1.1 !important;
        color: var(--gray-950, var(--ee-ink)) !important;
      }
      #catalog-new-releases-host .composition-instrumentation {
        font-style: italic;
        font-size: 1.02rem !important;
        color: var(--gray-700) !important;
      }

      /* "Featured" = solid blue, everywhere. One color identity for the mark. */
      #catalog-new-releases-host .card-badge {
        font-size: 0.66rem !important;
        font-weight: 800 !important;
        text-transform: uppercase !important;
        letter-spacing: 0.14em !important;
        color: #ffffff !important;
        background: var(--primary-600) !important;
        border: 1px solid var(--primary-700, hsl(220, 50%, 40%)) !important;
        box-shadow: none !important;
        border-radius: 4px !important;
        padding: 0.45rem 0.8rem !important;
      }



      /* Featured cover: a printed plate — real border (clean corners, no outline
         mismatch against the artwork), larger presence in the panel */
      #catalog-new-releases-host .composition-image {
        flex: 0 0 320px !important;
        max-width: 320px !important;
      }
      #catalog-new-releases-host .composition-image img,
      #catalog-new-releases-host .composition-image .composition-img {
        border-radius: 10px !important;
        border: 0 !important;
        outline: none !important;
        box-shadow: none !important;   /* the wrapper casts, never the image */
      }
      #catalog-new-releases-host .nr-cover-overlay { border-radius: 10px !important; }

      /* The panel is a sheet: it rests with a hairline and its own cast. It does
         not respond to hover — that belongs to the cover card inside it. */
      #catalog-new-releases-host #news-new-release-content {
        border-radius: 10px !important;
        box-shadow: 0 0 0 1px var(--ee-edge), var(--ee-lift-lg) !important;
      }

      /* Clickable things answer the same way: a 1px lift into a deeper offset,
         or a cream fill for the small square controls. Marks that aren't
         interactive (the FEATURED stamp, headings) deliberately stay still. */
      /* The cast belongs on .composition-image — the card surface itself, the
         element the markup already marks as "shadow-pop" — not on the <img>
         inside it. The image is absolutely positioned, so lifting *it* slid the
         artwork out from under the centred Learn More overlay, which stays put.
         Moving the wrapper carries artwork and overlay together. */
      #catalog-new-releases-host .composition-image.has-image {
        transition: transform 0.15s ease, box-shadow 0.15s ease;
        border-radius: 10px;
      }
      /* .raise-in leaves a filled animation transform on this wrapper, which
         silently beat the lift — the cast applied but the card never moved. */
      #catalog-new-releases-host .composition-image.has-image:hover {
        transform: translate(-1px, -1px) !important;
        box-shadow: var(--ee-lift-lg) !important;
      }
      /* the image keeps its own corners but never its own cast */
      #catalog-new-releases-host .composition-image.has-image:hover img,
      #catalog-new-releases-host .composition-image.has-image:hover .composition-img {
        transform: none !important;
        box-shadow: none !important;
      }
      /* The Audio Preview toggle is the control; View Score beside it keeps its
         own hover, so the bar itself stays put rather than moving under both. */
      #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle {
        border-radius: 8px;
        transition: background 0.15s ease;
      }
      #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle:hover {
        background: var(--secondary-100) !important;
      }
      #catalog-collections-section .collections-card-header:hover .collections-toggle {
        background: var(--secondary-100) !important;
      }

      /* Base-sheet casts that sat *underneath* the ones this system draws.
         The cover was the worst: a soft blurred drop on the wrapper showing
         beneath the square cast on the image itself, which read as a smudge
         under a crisp edge. Only one element in a stack should cast. */
      #catalog-new-releases-host .composition-image,
      #catalog-new-releases-host .composition-image.raise-in {
        box-shadow: none !important;
      }
      #catalog-new-releases-host .news-nr-audio-accordion .acc-head-row {
        box-shadow: none !important;
      }
      /* Badges are flat stamps pressed into the page, not sheets lying on it. */
      .meta-badge,
      #catalog-new-releases-host .card-badge {
        box-shadow: none !important;
      }
      /* The search panel gets the shared cast rather than a deep soft halo. */
      #catalog-filters .filter-controls,
      #catalog-filters .filter-content {
        box-shadow: var(--ee-lift-lg) !important;
      }

      /* The glass was 22% opaque, so the results scrolling underneath ghosted
         straight through it — blurred text riding up the panel, which reads as
         dirt rather than as glass, and left every hover cast sitting in a haze
         instead of on a surface. At 66% it is still glass and still tinted by
         what is behind it, but it is a surface you can put something on. */
      #catalog-filters .filter-panel,
      #catalog-filters .filter-content,
      #catalog-filters .filter-controls {
        background-color: rgba(16, 41, 54, 0.74) !important;
      }

      /* Chips lift crisply off that surface. On the old murky panel an ink cast
         at 28% dissolved into the backdrop; against a real surface it wants a
         defined edge and a more opaque cast, or the lift reads as a smudge. */
      #catalog-filters .button-group button:hover,
      #catalog-filters .btn-group button:hover,
      #catalog-filters .btn.u-btn:hover,
      #catalog-filters .u-btn--pill:hover,
      .filter-controls .multi-select-button:hover {
        border-color: rgba(2, 6, 23, 0.5) !important;
        box-shadow: 3px 3px 0 rgba(2, 6, 23, 0.45) !important;
      }

      /* The active tab carries the same colour as the featured work, so the
         filter bar belongs to the page it is filtering rather than sitting on
         top of it. Falls back to ink before any cover has been read. */
      #catalog-filters .button-group button.active,
      #catalog-filters .btn-group button.active {
        box-shadow: 3px 3px 0 hsl(var(--field-accent, 221 39% 13%) / 0.55) !important;
      }

      /* ---------- 2 · Carousel: sharpen the press sheets ---------- */
      /* Remove the soft blur/dimming — inactive covers stay legible, just quieted */
      #catalog-new-releases-host .nr-thumb img {
        filter: saturate(0.85) brightness(0.9) contrast(1) !important;
      }
      #catalog-new-releases-host .nr-thumb.active img {
        filter: saturate(1.05) brightness(1.02) contrast(1.02) !important;
      }
      /* Rail: crisp press-bed rules instead of a gray box, and real breathing room
         between covers so frames, hover lifts and offset shadows never collide */
      #catalog-new-releases-host .nr-thumb-carousel .rail {
        gap: 0.95rem !important;
        border: 0 !important;
        border-top: 1px solid rgba(2, 6, 23, 0.28) !important;
        border-bottom: 2px solid var(--ee-ink) !important;
        padding-top: 1.2rem !important;
        padding-bottom: 1.5rem !important;
      }

      /* ---------- 3 · Section headings ---------- */
      /* "New Releases" and "Search Music Catalog" keep the site's ORIGINAL white
         stroke + soft shadow treatment — deliberately not overridden here. */
      .collections-section-title {
        font-weight: 900 !important;
        letter-spacing: -0.015em !important;
        line-height: 1.1 !important;
        font-size: clamp(1.7rem, 1.3rem + 1vw, 2.25rem) !important;
        color: var(--gray-950, var(--ee-ink)) !important;
        text-shadow: none !important;
      }

      /* ---------- 4 · Popular covers on the blue plate: stacked print ----------
         These answer exactly as the carousel tiles do. They are the same object
         — a cover you click to open a work — and they sat next to each other
         behaving differently: the tiles lifted 1px into a cast tinted by the
         work's own artwork, these lifted 2px into house grey.

         Flat at rest rather than pre-lifted, because the alternative is worse
         than either: keeping the resting --ee-lift-lg while hovering to the
         tiles' smaller --ee-lift-md-hover would make the shadow SHRINK on
         hover, which reads as the card sinking. */
      /* The extra .related-works-carousel is load-bearing, not decoration.
         popular-compositions.html carries its own `:hover { transform:
         translateY(-3px) !important }` in a component <style> that is injected
         after every linked sheet — so at equal specificity it wins on order no
         matter how many !importants this file uses. One more class outranks it
         without reaching into shared component behaviour. */
      #popular-compositions .related-works-carousel .related-composition-card {
        border-radius: 6px !important;
        box-shadow: 0 0 0 1.5px rgba(2, 6, 23, 0.55) !important;
      }
      #popular-compositions .related-works-carousel .related-composition-card:hover,
      #popular-compositions .related-works-carousel .related-composition-card:active {
        transform: translate(-1px, -1px) !important;
        box-shadow:
          0 0 0 1.5px rgba(2, 6, 23, 0.7),
          var(--ee-lift-md-hover) !important;
      }
      /* The cast takes the artwork's colour, but it has to stay a shadow.
         The tiles sit on cream, where the accent at 0.4 is always darker than
         the ground. These sit on a blue plate — linear-gradient(rgb(98,128,188),
         rgb(61,102,184)), hue 220 — and two works in the catalogue are blue:
         WindSprints at 203 and the Figaro overture at 209, 17 and 11 degrees
         off the plate. Their cast was blue on blue, so those two cards had no
         visible hover at all while the other four did.

         Fallback first: a neutral ink cast, which is never invisible. */
      #popular-compositions .related-works-carousel .related-composition-card.has-chroma:hover,
      #popular-compositions .related-works-carousel .related-composition-card.has-chroma:active {
        box-shadow:
          0 0 0 1.5px rgba(2, 6, 23, 0.7),
          7px 7px 0 rgba(2, 6, 23, 0.45) !important;
      }
      /* Then force the lightness below the plate's — but in OKLCH, not HSL.
         Pinning HSL lightness to 26% fixed the two blues and broke the green:
         O Christmas Tree at hue 101 measured 1.15x against the plate, because
         HSL lightness is not perceptual and green carries roughly 72% of
         luminance where blue carries 7%. The same number is a much brighter
         colour in green than in blue.

         OKLCH lightness is perceptual, so one value darkens every hue by the
         same visible amount. Chroma and hue pass through untouched, so a blue
         work still casts a blue shadow — it is just reliably a shadow. */
      @supports (color: oklch(from white l c h)) {
        #popular-compositions .related-works-carousel .related-composition-card.has-chroma:hover,
        #popular-compositions .related-works-carousel .related-composition-card.has-chroma:active {
          box-shadow:
            0 0 0 1.5px rgba(2, 6, 23, 0.7),
            7px 7px 0 oklch(from hsl(var(--work-accent)) 0.34 c h / 0.62) !important;
        }
      }
      /* Crisp plate separations between the color blocks */
      #popular-compositions {
        border-bottom: 3px solid var(--ee-ink) !important;
      }

      /* ---------- 6 · Current Collections: printed folios, not floating tray ---------- */
      /* Drop the translucent white tray — cards sit directly on the ground */
      #catalog-collections-section #collections-bg-shell,
      #catalog-collections-section #collections-container,
      #catalog-collections-section .collections-container {
        background: transparent !important;
        border: 0 !important;
        padding: 0.25rem !important;
        box-shadow: none !important;
      }
      #catalog-collections-section .collections-container { gap: 1.5rem 1.75rem !important; }
      /* Each collection: a bound folio — flat deep navy, gold spine, stacked-print shadow */
      #catalog-collections-section .collections-card-header {
        background: hsl(221, 45%, 22%) !important;
        border-radius: 8px !important;
        border-left: 5px solid var(--secondary-400) !important;
        padding: 1.35rem 1.35rem !important;
        box-shadow:
          0 0 0 1px rgba(2, 6, 23, 0.45),
          var(--ee-lift-lg) !important;
        transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;
      }
      #catalog-collections-section .collections-card-header:hover {
        background: hsl(221, 45%, 18%) !important;
        transform: translate(-2px, -2px);
        box-shadow:
          0 0 0 1px rgba(2, 6, 23, 0.6),
          var(--ee-lift-lg-hover) !important;
      }
      #catalog-collections-section .collections-card:hover { transform: none !important; }
      #catalog-collections-section .collection-name {
        font-size: 1.18rem !important;
        font-weight: 800 !important;
        letter-spacing: -0.015em !important;
      }
      #catalog-collections-section .catalog-collection-subtitle {
        color: rgba(255, 255, 255, 0.82) !important;
        font-size: 0.92rem !important;
      }
      #catalog-collections-section .collections-toggle {
        width: 34px !important;
        height: 34px !important;
        background: #ffffff !important;
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 6px !important;
        box-shadow: var(--ee-lift-sm) !important;
      }
      #catalog-collections-section .toggle-arrow { color: var(--ee-ink) !important; }

      /* ---------- 7 · The catalog: a printed ledger ---------- */
      /* Sheet edges: crisp hairline + offset, not a soft floating card */
      .results-section .compositions-container {
        border-radius: 6px !important;
        box-shadow: 0 0 0 1px rgba(2, 6, 23, 0.55), 8px 8px 0 rgba(0, 0, 0, 0.22) !important;
        overflow: hidden;
      }
      .table-header { border-bottom: 2px solid var(--ee-ink) !important; }
      .table-header-cell {
        color: var(--gray-700) !important;
        font-weight: 800 !important;
        font-size: 0.7rem !important;
        letter-spacing: 0.12em !important;
      }
      .compositions-table tbody tr.composition-row {
        border-bottom: 1px solid rgba(2, 6, 23, 0.12) !important;
      }
      /* Row hover: warm press-room cream instead of blue, calmer lift */
      .composition-row:hover {
        background: var(--secondary-100) !important;
        transform: translateY(-1px) !important;
      }
      .composition-row::before { background: var(--secondary-500) !important; }
      /* Covers in the ledger: tiny printed plates */
      .composition-row .composition-cover img,
      .composition-cover .composition-cover-placeholder {
        border-radius: 4px !important;
        outline: 1px solid rgba(2, 6, 23, 0.4);
        outline-offset: -1px;
      }
      /* Badges: one identity system — category tints, gold for Featured */
      .meta-badge {
        text-transform: uppercase !important;
        letter-spacing: 0.07em !important;
        font-size: 0.67rem !important;
        font-weight: 800 !important;
        border-radius: 4px !important;
        padding: 0.22rem 0.55rem !important;
        border: 1px solid transparent;
      }
      .meta-badge.composition {
        background: var(--primary-100) !important;
        color: var(--primary-700) !important;
        border-color: hsl(220, 30%, 78%) !important;
      }
      .meta-badge.arrangement {
        background: hsl(0, 45%, 94%) !important;
        color: hsl(0, 55%, 38%) !important;
        border-color: hsl(0, 40%, 80%) !important;
      }
      /* Featured pill in the table (inline-styled by JS) → solid blue, same as the hero stamp */
      .meta-badge[style*="primary-100"] {
        background: var(--primary-600) !important;
        color: #ffffff !important;
        border-color: var(--primary-700, hsl(220, 50%, 40%)) !important;
      }

      /* ---------- 8 · Audio Preview + View Score: same crisp print hardware ---------- */
      #catalog-new-releases-host .news-nr-audio-accordion {
        background: rgba(255, 255, 255, 0.55) !important;
        border: 1px solid rgba(2, 6, 23, 0.35) !important;
        border-radius: 8px !important;
        box-shadow: var(--ee-lift-md) !important;
      }
      #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle .caret {
        border: 1.5px solid var(--ee-ink) !important;
        box-shadow: var(--ee-lift-sm) !important;
      }
      #catalog-new-releases-host #news-new-release-score-btn,
      #catalog-new-releases-host .btn-primary.learn-more-btn {
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 8px !important;
        font-weight: 800 !important;
        box-shadow: 0 1px 0 var(--ee-cast) !important;
        transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
      }
      #catalog-new-releases-host #news-new-release-score-btn:hover,
      #catalog-new-releases-host .btn-primary.learn-more-btn:hover {
        background: #ffffff !important;
        transform: translate(-1px, -1px);
        box-shadow: var(--ee-lift-sm-hover) !important;
      }

      /* ---------- 8b · Audio player internals + carousel arrows: same hardware ---------- */
      #catalog-new-releases-host .news-nr-audio-player audio,
      #catalog-new-releases-host .new-release-audio-players audio {
        border-radius: 8px !important;
        border: 1px solid rgba(2, 6, 23, 0.4);
        box-shadow: var(--ee-lift-sm-hover);
      }
      /* The movement title in the work's own colour.
         It was --primary-700, the site blue, which is the one colour on this
         panel that belongs to no work in particular — a heading in a hue the
         piece does not own, sitting directly above artwork that does. Taking
         --field-accent ties it to the cover the way the field and the plate
         casts already are.

         Mixed 62% toward ink rather than used neat: the accents are normalised
         to 46% lightness for use as casts and washes, which is too light to set
         a heading in. The mix keeps the hue and buys back the contrast, the
         same move the composition page makes for its frosted glyphs. */
      #catalog-new-releases-host .composition-audio-title,
      #catalog-new-releases-host #news-nr-audio-title {
        /* Ink until the browser can do better — see the @supports below. */
        color: var(--ee-ink) !important;
        font-size: 1.02rem !important;
        font-weight: 800 !important;
        letter-spacing: -0.012em !important;
        /* The row owns the gap now, so the title carries none of its own. */
        margin: 0 !important;
      }

      /* Take the work's hue, not a blend with the work's hue.
         Mixing the accent toward navy ink was the wrong operation: Resolutions'
         olive against a blue ink averages to mud, and every low-saturation
         cover did the same. Keeping the hue and the saturation exactly and
         forcing only the lightness down gives a deep version of the work's own
         colour instead of a compromise between two colours. */
      @supports (color: hsl(from white h s l)) {
        #catalog-new-releases-host .composition-audio-title,
        #catalog-new-releases-host #news-nr-audio-title {
          /* Hue and saturation untouched, lightness forced down. A saturation
             floor via max(s, 62%) was tried to stop drab covers producing drab
             headings; max() does not parse inside relative colour syntax here,
             the whole declaration was dropped, and every title silently fell
             back to ink. Left as the plain form, which works. */
          color: hsl(from hsl(var(--field-accent, 221 39% 13%)) h s 30%) !important;
        }
      }

      /* The featured card is glass laid on the field, not a sheet of paper.
         Its inline background is rgba(255,255,255,0.23) — nearly transparent,
         which was invisible while the field behind it was also invisible. Once
         the staff and the notes were drawn, 23% white let the whole thing run
         straight across the words, so it went to 88% and the field was shut
         out: 83% of the backdrop was measured as sitting behind something
         opaque, drawn and never seen.

         What was actually wrong at 23% was not the transparency, it was the
         detail. Type fails over a busy backdrop because the backdrop carries
         edges at the same frequency as the letterforms. Blur removes exactly
         that and keeps everything else — so the colour, the tint change and the
         motion all still read through, while nothing behind the card has an
         edge sharp enough to compete with a word. That is why translucency is
         safe here and was not before.

         The opaque rule stays as the base. A browser with no backdrop-filter
         gets the sheet, not unreadable type over a moving waveform: the whole
         justification for going translucent is a blur that browser does not
         have. --nr-glass is the one number to turn if it wants to be heavier or
         lighter; below about 0.4 the description text starts to fight the
         waveform even blurred. */
      #catalog-new-releases-host #news-new-release-content {
        background: rgba(255, 255, 255, 0.88) !important;
      }
      @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
        #catalog-new-releases-host #news-new-release-content {
          background: rgba(255, 255, 255, var(--nr-glass, 0.38)) !important;
          /* 10px, and the number is not a taste call.
             The blur only has to destroy detail at the frequency letterforms
             work at — strokes around 2px, counters around 4px — because that is
             the only detail that can compete with a word. The waveform's bars
             are 2.4px on a 3.8px pitch, so 10px already averages them into a
             wash; its envelope varies over 50-200px and survives intact. That
             is the whole trick: the thing that would hurt the type is gone and
             the thing worth seeing is not.

             It was 22px first, which is over twice what is needed. A 22px
             kernel spans five bars AND flattens the envelope, so the card went
             milky and the music stopped reading through it at all.

             Saturate above 1 because blurring a tinted field averages its
             colour back toward the cream and drains the work's hue out; this
             puts back what the blur takes. */
          -webkit-backdrop-filter: blur(3px) saturate(1.28);
          backdrop-filter: blur(3px) saturate(1.28);
        }
      }

      /* The movement controls as hardware, not as links.
         Two square plates and a counter, sized to the title's line rather than
         to a toolbar: one press moves one movement, so they read as a pair of
         controls belonging to the heading beside them. The 1px lift into a
         square cast is the same motion every other control on the site makes —
         it is the tier, not a new idea. */
      #catalog-new-releases-host .audio-nav-btn {
        width: 30px;
        height: 30px;
        padding: 0 !important;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        font-size: 17px;
        font-weight: 800;
        line-height: 1;
        color: var(--ee-ink) !important;
        background: #ffffff !important;
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 6px !important;
        box-shadow: 2px 2px 0 rgba(2, 6, 23, 0.22) !important;
        transition: transform 0.15s ease, box-shadow 0.15s ease;
      }
      #catalog-new-releases-host .audio-nav-btn:hover:not(:disabled) {
        transform: translate(-1px, -1px);
        box-shadow: 3px 3px 0 rgba(2, 6, 23, 0.28) !important;
      }
      /* At the ends of the work there is nowhere to go: the plate stays, the
         cast drops away, so it reads as inert rather than missing. */
      #catalog-new-releases-host .audio-nav-btn:disabled {
        opacity: 0.4;
        box-shadow: none !important;
        cursor: default;
      }
      #catalog-new-releases-host .audio-nav-info {
        font-style: normal !important;
        text-transform: uppercase;
        letter-spacing: 0.1em;
        font-size: 0.68rem;
        font-weight: 600;
        white-space: nowrap;
        color: color-mix(in oklab, var(--ee-ink) 62%, #ffffff) !important;
      }

      /* Performer credit: a name, set as a name.
         Two takes came before this. Italic grey read as small print nobody is
         meant to read. Uppercase at 0.72rem borrowed the masthead's colophon
         voice, but that voice is for roles — COMPOSER, TRUMPETER — and running
         a person's name through it turns "Valley Trio" into a category rather
         than a performer.

         So: sentence case, near-body size, medium weight, quiet ink. It sits
         under the transport as a caption with enough presence to be read, and
         stays neutral because the movement title above it is already carrying
         the work's colour — two coloured lines in one small panel would fight. */
      #catalog-new-releases-host .audio-performer {
        font-style: normal !important;
        text-transform: none;
        letter-spacing: 0.004em;
        font-size: 0.88rem;
        font-weight: 500;
        line-height: 1.5;
        color: color-mix(in oklab, var(--ee-ink) 76%, #ffffff) !important;
      }
      #catalog-new-releases-host .news-nr-audio-accordion .audio-tags .chip {
        text-transform: uppercase !important;
        letter-spacing: 0.07em !important;
        font-size: 0.65rem !important;
        font-weight: 800 !important;
        border-radius: 4px !important;
        padding: 0.24rem 0.55rem !important;
        background: #ffffff !important;
        color: var(--gray-700) !important;
        border: 1px solid rgba(2, 6, 23, 0.3) !important;
      }
      #catalog-new-releases-host .news-nr-audio-accordion .audio-tags .chip.tag-cat {
        background: var(--primary-100) !important;
        color: var(--primary-700) !important;
        border-color: hsl(220, 30%, 78%) !important;
      }
      /* Carousel arrows: white plates with ink edges instead of dark glass circles */
      #catalog-new-releases-host .nr-thumb-carousel .related-works-nav-btn {
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        border: 1px solid rgba(2, 6, 23, 0.5) !important;
        border-radius: 6px !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        box-shadow: var(--ee-lift-sm) !important;
        opacity: 1 !important;
      }
      #catalog-new-releases-host .nr-thumb-carousel .related-works-nav-btn:hover {
        background: var(--secondary-100) !important;
        transform: translateY(-50%) scale(1.03) !important;
      }
      #catalog-new-releases-host .nr-thumb-carousel .related-works-nav-btn .rw-icon {
        color: var(--ee-ink) !important;
        text-shadow: none !important;
      }
      #catalog-new-releases-host .nr-thumb-carousel .related-works-nav-btn svg path {
        fill: currentColor !important;
      }

      /* ---------- 9 · Expanded collection panel: the opened folio ---------- */
      .collection-expanded-panel {
        border-radius: 8px !important;
        overflow: hidden;
        border-left: 5px solid var(--secondary-400) !important;
        box-shadow:
          0 0 0 1px rgba(2, 6, 23, 0.45),
          var(--ee-lift-lg) !important;
      }
      .expanded-hero {
        background: hsl(221, 45%, 22%) !important;
        padding: 1.35rem 1.25rem !important;
      }
      .expanded-title { font-size: 1.45rem !important; font-weight: 800 !important; letter-spacing: -0.015em !important; }
      .expanded-sub { color: rgba(255, 255, 255, 0.82) !important; }
      .expanded-close {
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 6px !important;
        box-shadow: var(--ee-lift-sm) !important;
      }
      .expanded-close:hover { background: var(--secondary-100) !important; }
      .expanded-actions .learn-more-btn {
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 8px !important;
        font-weight: 800 !important;
      }
      .expanded-actions .learn-more-btn:hover {
        transform: translate(-1px, -1px);
        box-shadow: var(--ee-lift-sm-hover) !important;
      }
      .expanded-compositions,
      .expanded-list-block {
        background: var(--secondary-100) !important;
        border: 1px solid rgba(2, 6, 23, 0.25) !important;
        border-radius: 8px !important;
      }
      .expanded-list-title-left { font-weight: 800 !important; color: var(--ee-ink) !important; }
      .expanded-item {
        background: #ffffff !important;
        border: 1px solid rgba(2, 6, 23, 0.3) !important;
        border-radius: 6px !important;
        box-shadow: none !important;
        transition: transform 0.14s ease, box-shadow 0.14s ease;
      }
      .expanded-item:hover {
        transform: translate(-1px, -1px);
        box-shadow: var(--ee-lift-sm-hover) !important;
      }
      .expanded-item .p { font-weight: 800; color: var(--ee-ink); }

    }

/* ---- Filter panel -----------------------------------------------------------
   Search sits on the top row with the categories instead of behind the
   "More filters" toggle — finding a title is the most common thing to do here
   and it was invisible until you opened the panel. Its expanding behaviour is
   unchanged. A Featured checkbox sits beside it, and Sort now names its
   default ("Featured first") rather than just saying "Sort". */
@media (min-width: 1025px) {
  #catalog-filters .r1-right {
    display: flex !important;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: nowrap;
  }
  #catalog-filters .featured-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex: 0 0 auto;
    padding: 0.4rem 0.65rem;
    border-radius: 8px;
    border: 1px solid rgba(2, 6, 23, 0.45);
    background: #ffffff;
    color: var(--ee-ink);
    font-weight: 800;
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    box-shadow: 0 1px 0 var(--ee-cast);
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  }
  #catalog-filters .featured-toggle:hover {
    transform: translate(-1px, -1px);
    box-shadow: var(--ee-lift-sm-hover);
  }
  #catalog-filters .featured-toggle input {
    appearance: none;
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    margin: 0;
    border: 1.5px solid rgba(2, 6, 23, 0.5);
    border-radius: 3px;
    background: #ffffff;
    display: grid;
    place-content: center;
    cursor: pointer;
  }
  #catalog-filters .featured-toggle input:checked::after {
    content: "";
    width: 4px;
    height: 8px;
    border: solid var(--primary-700, hsl(220, 50%, 40%));
    border-width: 0 2px 2px 0;
    transform: rotate(45deg) translate(-1px, -1px);
  }
  #catalog-filters .featured-toggle:has(input:checked) {
    background: var(--primary-600);
    border-color: var(--primary-700, hsl(220, 50%, 40%));
    color: #ffffff;
  }
  /* Sort names its state instead of wrapping onto two lines. */
  #catalog-filters .sort-button,
  #catalog-filters .sort-text { white-space: nowrap !important; }
}

/* ---- Audio Preview: a cue strip, not a floating widget -----------------------
   It kept the old language — a pill-shaped caret, a 3px white border, a soft
   double shadow, a sentence-case label — so it read as a control borrowed from
   somewhere else. It stays a toggle (that part works); it just speaks the same
   way as everything around it now: hairline ink edge, small-caps label, a
   square press-button for the caret, and a cream body when open so the
   expanded state is legible at a glance. */
@media (min-width: 1025px) {
  #catalog-new-releases-host .news-nr-audio-accordion {
    background: #ffffff !important;
    border: 1px solid var(--ee-edge) !important;
    border-radius: 8px !important;
    box-shadow: none !important;
    overflow: hidden !important;
    transition: box-shadow 0.15s ease;
  }
  #catalog-new-releases-host .news-nr-audio-accordion:hover {
    box-shadow: var(--ee-lift-md) !important;
  }
  #catalog-new-releases-host .news-nr-audio-accordion .acc-head-row {
    padding: 0.15rem 0.5rem 0.15rem 0.15rem;
  }
  /* Label as a section mark rather than a heading */
  #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle {
    padding: 0.7rem 0.8rem !important;
    font-size: 0.78rem !important;
    font-weight: 800 !important;
    letter-spacing: 0.12em !important;
    text-transform: uppercase !important;
    color: var(--ee-ink) !important;
    border-radius: 6px !important;
  }
  /* Square press-button, matching the collection and side-dot controls.
     The base rule rotates this 180deg when open, which reads as a flip on a
     circle but as a wobble on a square — so the square only changes fill, and
     the glyph inside does the turning. */
  #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle .caret {
    width: 24px !important;
    height: 24px !important;
    border-radius: 5px !important;
    border: 1.5px solid var(--ee-ink) !important;
    background: #ffffff !important;
    color: var(--ee-ink) !important;
    font-size: 13px !important;
    box-shadow: var(--ee-lift-sm) !important;
    transform: none !important;
    animation: none !important;
    transition: background 0.16s ease, color 0.16s ease, box-shadow 0.16s ease;
  }
  #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle .caret::before {
    content: "";
    display: block;
    width: 6px;
    height: 6px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
    transition: transform 0.18s ease;
  }
  /* hide the literal ▾ glyph; the drawn chevron replaces it */
  #catalog-new-releases-host .news-nr-audio-accordion .accordion-toggle .caret {
    font-size: 0 !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
  }
  #catalog-new-releases-host .news-nr-audio-accordion[aria-expanded="true"] .accordion-toggle .caret {
    background: var(--ee-ink) !important;
    color: #ffffff !important;
    border-color: var(--ee-ink) !important;
    transform: none !important;
  }
  #catalog-new-releases-host .news-nr-audio-accordion[aria-expanded="true"] .accordion-toggle .caret::before {
    transform: rotate(225deg) translate(-1px, -1px);
  }
  /* Open state: a ruled-off cream tray, like the body of a printed entry */
  #catalog-new-releases-host .news-nr-audio-accordion[aria-expanded="true"] .accordion-body {
    background: var(--secondary-100) !important;
    border-top: 1px solid var(--ee-edge) !important;
  }
  #catalog-new-releases-host .news-nr-audio-accordion .accordion-body { border-radius: 0 !important; }
}


/* ---- Cover hover: lighter veil, button in the system's language -------------
   The veil was 74% ink, which buried the artwork you are hovering to look at.
   The button carries its own contrast now — a white plate with an ink edge,
   the same as Learn More and View Score — so the veil only has to knock the
   art back, not black it out. */
@media (min-width: 1025px) {
  /* 0.52, not 0.34. The veil is what the button is legible against, and at a
     third the sunset covers stayed bright enough that white-on-nothing had
     almost no contrast on exactly the works most likely to be featured. */
  #catalog-new-releases-host .nr-cover-overlay {
    background: rgba(2, 6, 23, 0.52) !important;
    box-shadow: none !important;
  }
  /* On a dark ground the system uses a ghost control, the way the score
     overlay's secondary button does — a white plate here read as a page
     control that had landed on top of the artwork rather than part of it.

     Still a ghost, but no longer a hollow one: an outline alone left the label
     sitting on whatever happened to be behind it, so it was clear over the dark
     third of a cover and invisible over the bright third. A dark fill of its
     own gives it the same contrast on every work while keeping it made of the
     image rather than dropped on top of it. */
  #catalog-new-releases-host .nr-cover-learn {
    background: rgba(2, 6, 23, 0.55) !important;
    color: #ffffff !important;
    border: 2px solid #ffffff !important;
    border-radius: 6px !important;
    font-weight: 800 !important;
    font-size: 0.78rem !important;
    text-transform: uppercase !important;
    letter-spacing: 0.14em !important;
    padding: 0.62rem 1.1rem !important;
    text-shadow: none !important;
    box-shadow: none !important;
    transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease;
  }
  /* It is centred with translate(-50%,-50%), so the lift has to compose with
     that rather than replace it — otherwise the button jumps to the corner. */
  #catalog-new-releases-host .nr-cover-learn:hover,
  #catalog-new-releases-host .nr-cover-learn:active {
    transform: translate(calc(-50% - 1px), calc(-50% - 1px)) !important;
    background: rgba(2, 6, 23, 0.78) !important;
    border-color: #ffffff !important;
    box-shadow: none !important;
  }
}

/* ---- Clearance for the cover's cast -----------------------------------------
   The cover sat 10px from the description text, so an 8px cast landed 2px from
   the copy and read as touching it. The column gutter widens to 2rem, which
   gives the cast clear air on hover and is easier to read besides. */
@media (min-width: 1025px) {
  #catalog-new-releases-host .composition-featured {
    gap: 2rem !important;
  }
}

/* ---- Collection panel: make "there are others" obvious ----------------------
   The strip of names at the foot of the panel gave no clue what it was or that
   it scrolled — titles just ran off the edge mid-word. It is labelled now,
   states your position ("3 of 7"), and is flanked by step controls, so moving
   between collections is a visible affordance rather than something you have
   to discover. */
@media (min-width: 1025px) {
  .expanded-related-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0 0 0.55rem;
  }
  .expanded-related-label {
    font-weight: 800;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--gray-700);
  }
  .expanded-related-count {
    font-weight: 800;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    color: var(--gray-600);
  }
  .expanded-related-nav {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
  .expanded-related-step {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #ffffff;
    color: var(--ee-ink);
    border: 1px solid rgba(2, 6, 23, 0.45);
    border-radius: 6px;
    font-size: 16px;
    font-weight: 800;
    line-height: 1;
    cursor: pointer;
    box-shadow: var(--ee-lift-sm);
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  }
  .expanded-related-step:hover:not(:disabled) {
    background: var(--secondary-100);
    transform: translate(-1px, -1px);
    box-shadow: var(--ee-lift-sm-hover);
  }
  .expanded-related-step:disabled {
    opacity: 0.35;
    cursor: default;
    box-shadow: none;
  }
  /* The rail keeps scrolling, but a fade at the trailing edge says so instead
     of letting a title look truncated by accident. */
  .expanded-related-nav .expanded-related-rail {
    flex: 1 1 auto;
    display: flex;
    gap: 0.4rem;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 2px;
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent 100%);
  }
  .expanded-related-nav .expanded-related-rail::-webkit-scrollbar { display: none; }
  .expanded-related-link {
    flex: 0 0 auto;
    padding: 0.4rem 0.7rem;
    border-radius: 6px;
    border: 1px solid rgba(2, 6, 23, 0.28);
    background: #ffffff;
    color: var(--gray-800);
    font-weight: 700;
    font-size: 0.8rem;
    white-space: nowrap;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  }
  .expanded-related-link:hover {
    background: var(--secondary-100);
    transform: translate(-1px, -1px);
    box-shadow: var(--ee-lift-sm);
  }
  .expanded-related-link.active {
    background: hsl(221, 45%, 22%);
    border-color: hsl(221, 45%, 22%);
    color: #ffffff;
    box-shadow: none;
    transform: none;
  }
}

/* ---- Carousel tiles: same behaviour as the cover card -----------------------
   The tiles are the same object as the big cover, so they should answer the
   same way: flat at rest, a lift into a cast on hover, a light veil rather
   than a blackout, and the same white ink-edged label. */
@media (min-width: 1025px) {
  #catalog-new-releases-host .nr-thumb {
    box-shadow: 0 0 0 1.5px rgba(2, 6, 23, 0.45) !important;
  }
  #catalog-new-releases-host .nr-thumb:hover,
  #catalog-new-releases-host .nr-thumb:active {
    box-shadow: 0 0 0 1.5px rgba(2, 6, 23, 0.7), var(--ee-lift-md-hover) !important;
    transform: translate(-1px, -1px) !important;
  }
  /* Selection is carried by the frame, so the selected tile stays flat too */
  #catalog-new-releases-host .nr-thumb.active {
    box-shadow:
      0 0 0 3px #ffffff,
      0 0 0 5px var(--ee-ink) !important;
    transform: none !important;
  }
  #catalog-new-releases-host .nr-thumb.active:hover {
    box-shadow:
      0 0 0 3px #ffffff,
      0 0 0 5px var(--ee-ink),
      var(--ee-lift-md-hover) !important;
    transform: translate(-1px, -1px) !important;
  }

  /* The selected tile frames itself in its own colour.
     Selection was an ink ring identical for all 67 works, which said "this one"
     but nothing about which one. Reading the ring from the artwork makes the
     selected tile, the featured plate and the field all agree without adding a
     single new mark. Ink stays as the fallback for works with no cover. */
  #catalog-new-releases-host .nr-thumb.active.has-chroma {
    box-shadow:
      0 0 0 3px #ffffff,
      0 0 0 5px hsl(var(--work-accent)) !important;
  }
  #catalog-new-releases-host .nr-thumb.active.has-chroma:hover {
    box-shadow:
      0 0 0 3px #ffffff,
      0 0 0 5px hsl(var(--work-accent)),
      7px 7px 0 hsl(var(--work-accent) / 0.4) !important;
  }
  /* Unselected tiles keep their hairline and cast in colour — the earlier rule
     replaced the whole box-shadow and dropped the edge, so a hovered tile lost
     its outline. */
  #catalog-new-releases-host .nr-thumb.has-chroma:hover {
    box-shadow:
      0 0 0 1.5px rgba(2, 6, 23, 0.7),
      7px 7px 0 hsl(var(--work-accent) / 0.4) !important;
  }
  /* Veil matches the cover: knock the art back, don't black it out */
  #catalog-new-releases-host .nr-thumb::after {
    background: rgba(2, 6, 23, 0.34) !important;
    box-shadow: none !important;
  }
  /* Label matches the cover's Learn More plate */
  #catalog-new-releases-host .nr-learn-label {
    background: transparent !important;
    color: #ffffff !important;
    border: 1.5px solid rgba(255, 255, 255, 0.85) !important;
    border-radius: 6px !important;
    font-weight: 800 !important;
    font-size: 0.64rem !important;
    text-transform: uppercase !important;
    letter-spacing: 0.13em !important;
    padding: 0.5rem 0.8rem !important;
    text-shadow: none !important;
    box-shadow: none !important;
  }
  #catalog-new-releases-host .nr-learn-label:hover {
    transform: translate(-50%, -50%) !important;
    background: rgba(255, 255, 255, 0.16) !important;
    border-color: #ffffff !important;
    box-shadow: none !important;
  }
}

/* ---- Category tabs carry their own counts ----------------------------------
   A lone "70 items" told you the size of the pile but nothing about its shape.
   Each tab now shows how many it holds under the current search and filters, so
   the bar answers "where are the results" instead of just "how many". The
   active tab's count is the visible total, which makes the separate label
   redundant — it is gone. */
@media (min-width: 1025px) {
  #catalog-filters .button-group button {
    display: inline-flex;
    align-items: center;
    gap: 0.42rem;
  }
  #catalog-filters .button-group .cat-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.35em;
    padding: 0.08rem 0.3rem;
    border-radius: 4px;
    background: rgba(2, 6, 23, 0.08);
    color: var(--gray-700);
    font-size: 0.72rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1.5;
    transition: background 0.15s ease, color 0.15s ease;
  }
  /* on the selected tab the count sits on ink, so it inverts */
  #catalog-filters .button-group button.active .cat-count {
    background: rgba(255, 255, 255, 0.22);
    color: #ffffff;
  }
  #catalog-filters .button-group button.is-empty {
    opacity: 0.42;
  }
  /* the lone total is replaced by the counts on the tabs */
  #catalog-filters #resultCount { display: none !important; }
}


/* ---- Keep the filter bar on one row ----------------------------------------
   The glyphs added width and tipped the row into wrapping, which defeats the
   point of adding them. The categories may shrink (their counts and labels stay
   legible well below their natural width) while the control cluster holds its
   size, so the bar stays a single line down to narrow desktops. */
@media (min-width: 1025px) {
  #catalog-filters .filters-r1 {
    flex-wrap: nowrap !important;
    gap: 0.75rem;
    align-items: center;
  }
  #catalog-filters .category-group {
    flex: 1 1 auto;
    min-width: 0;
  }
  #catalog-filters .button-group {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
  }
  #catalog-filters .r1-right {
    flex: 0 0 auto;
    gap: 0.5rem;
  }
  /* trim the cluster: the glyph now carries part of the meaning, so the
     padding that was doing that job can come back down */
  #catalog-filters .r1-right .btn.u-btn,
  #catalog-filters #filterToggle,
  #catalog-filters .featured-toggle {
    padding-left: 0.62rem !important;
    padding-right: 0.62rem !important;
  }
  #catalog-filters .r1-right .featured-toggle span { letter-spacing: 0.05em; }
}

@media (min-width: 1025px) {
  /* Counts and glyphs both add width, so the tabs give some back: the labels
     stay full-size, the padding around them tightens. All five categories and
     the control cluster then share one line at desktop widths. */
  #catalog-filters .button-group button {
    padding: 0.48rem 0.68rem !important;
    gap: 0.34rem;
  }
  #catalog-filters .button-group { gap: 0.34rem; }
  #catalog-filters .button-group .cat-count {
    padding: 0.06rem 0.24rem;
    font-size: 0.68rem;
  }
  #catalog-filters .r1-right { gap: 0.42rem; }
}

/* ---- Filters and Featured become icon-only ---------------------------------
   A glyph beside a word is the worst of both: it costs the width of an icon and
   saves none of the text. These two are unambiguous on their own, so they drop
   to square controls and give the row back ~150px — which is what stops the
   tabs wrapping.

   The labels stay in the DOM and stay in the accessibility tree; they are only
   hidden from sight, so the buttons still announce themselves. */
@media (min-width: 1025px) {
  #catalog-filters #filterToggle {
    width: 38px;
    height: 38px;
    padding: 0 !important;
    justify-content: center;
    font-size: 0 !important;          /* hides the label, keeps the a11y name */
  }
  #catalog-filters #filterToggle::before {
    width: 17px;
    height: 17px;
    margin: 0 !important;
  }

  #catalog-filters .featured-toggle {
    width: 38px;
    height: 38px;
    padding: 0 !important;
    justify-content: center;
    gap: 0;
  }
  #catalog-filters .featured-toggle::before {
    width: 17px;
    height: 17px;
    margin: 0 !important;
  }
  /* the star is the state, so the checkbox and the word both go */
  #catalog-filters .featured-toggle input,
  #catalog-filters .featured-toggle span {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }
  /* on = filled star on ink, off = outline. No label needed to tell them apart. */
  #catalog-filters .featured-toggle:has(input:checked) {
    background: hsl(221, 45%, 22%);
    border-color: hsl(221, 45%, 22%);
    color: #ffffff;
  }
  #catalog-filters .featured-toggle:has(input:checked)::before { opacity: 1; }
}

/* ---- Values set as values --------------------------------------------------
   Durations, years and prices are data, so they are typeset as data — the mono
   stack, tabular figures. No pretence of an opus catalogue; just the habit of
   a mind that builds databases, applied to a page. */
@media (min-width: 1025px) {
  /* Values in mono, prose left alone. */
  .compositions-table .composition-row td:nth-child(2),
  .compositions-table .composition-row td:nth-child(3),
  .composition-row .composition-duration,
  .composition-row .composition-year {
    font-family: "SF Mono", "Fira Code", "JetBrains Mono", Consolas, ui-monospace, monospace;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
  }
  .buy-now-btn:not(.free):not(.free-download-btn):not(.contact-btn),
  .composition-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn) {
    font-variant-numeric: tabular-nums;
  }
}

/* ---- Catalogue rows answer in the work's own colour ------------------------
   The tint goes on the <tr>, and the separator moves to the cells.

   Putting the tint on the cells was wrong: the table is border-collapse:
   separate, so the cells do not touch, and the fill painted as disconnected
   patches behind the text instead of as a row. The row element is the only box
   that spans the whole width.

   The reason it was on the cells was that the separator lives on the <tr> as a
   border-bottom, and a row background paints over it. So the separator moves
   down to the cells, where the row fill cannot reach it — full-width highlight
   and an intact rule between rows.

   26%, not 13%. At 13% it was a tint you had to look for; the point of a hover
   is that you do not have to. */
@media (min-width: 1025px) {
  .results-section .composition-row {
    border-bottom: 0 !important;
    transition: background-color 0.14s ease;
  }
  /* The separator is drawn on the row, as a background-image.
     Two earlier attempts failed for the same underlying reason: the cells in
     this table never touch (border-collapse: separate, and zeroing
     border-spacing did not close the gaps), so a per-cell border can only ever
     render as dashes under each column. And a border on the <tr> is painted
     under the row's background-color, so the hover tint erased it.

     A background-image is painted ABOVE background-color on the same element.
     One gradient, one pixel tall, pinned to the bottom of the row: full width,
     continuous, and the tint cannot cover it. */
  .results-section .composition-row {
    background-image: linear-gradient(to top, rgba(2, 6, 23, 0.12) 1px, transparent 1px) !important;
    transition: background-color 0.18s ease !important;
  }
  .results-section .composition-row td {
    border-bottom: 0 !important;
    background-color: transparent !important;
  }
  .results-section .composition-row.has-chroma:hover {
    background-color: color-mix(in oklab, hsl(var(--work-accent)) 26%, #ffffff) !important;
  }
  .results-section .composition-row:not(.has-chroma):hover {
    background-color: #ece2cd !important;
  }

  /* The accent bar, drawn down the margin. */
  .results-section .composition-row td:first-child { position: relative; }
  .results-section .composition-row td:first-child::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 5px;
    background: hsl(var(--work-accent, 221 39% 13%));
    /* No growth and no travel. Scaling the bar down from the top made it look
       like the row was unrolling, which is a bigger gesture than a hover wants
       and drew the eye to the corner instead of the row. It fades. */
    opacity: 0;
    transition: opacity 0.14s ease;
  }
  .results-section .composition-row:hover td:first-child::before { opacity: 1; }
  @media (prefers-reduced-motion: reduce) {
    .results-section .composition-row td:first-child::before { transition: none; }
  }
}

/* ---- Filter bar: controls that look like the rest of the hardware ----------
   Four changes, all of them about the bar reading as one row of instruments
   rather than three unrelated widgets.

   Sort moved up out of the collapse. It is not a filter — it reorders what you
   already have — so hiding it behind "Show Filters" put a permanent control
   inside a temporary drawer. It is an icon now because its label was its own
   current value ("Featured first"), which is a status, not a name. */
@media (min-width: 1025px) {
  /* The two dropdowns sit at the end of the drawer, under the button that
     opened it, rather than stranded at the far left of an empty row. */
  #catalog-filters .filters-r2 {
    justify-content: flex-end !important;
  }
  #catalog-filters .filters-r2 .l {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-left: auto;
  }
  #catalog-filters .filters-r2 .r:empty { display: none; }

  /* Square plates, ink hairline, hard cast: the same control the movement
     arrows and the transport buttons already are. */
  #catalog-filters .sort-button,
  #catalog-filters #filterToggle,
  #catalog-filters #clear-all-filters-top {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    height: 34px;
    color: var(--ee-ink) !important;
    background: #ffffff !important;
    border: 1px solid rgba(2, 6, 23, 0.45) !important;
    border-radius: 6px !important;
    box-shadow: 2px 2px 0 rgba(2, 6, 23, 0.22) !important;
    font-weight: 700 !important;
    letter-spacing: 0.02em;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  }
  #catalog-filters .sort-button:hover,
  #catalog-filters #filterToggle:hover,
  #catalog-filters #clear-all-filters-top:hover {
    transform: translate(-1px, -1px);
    box-shadow: 3px 3px 0 rgba(2, 6, 23, 0.3) !important;
  }
  /* Pressed reads as pressed: the plate sits down into its own cast. */
  #catalog-filters #filterToggle[aria-pressed="true"] {
    background: var(--secondary-100, #f4efe2) !important;
    transform: translate(1px, 1px);
    box-shadow: 0 0 0 1px rgba(2, 6, 23, 0.45) inset !important;
  }

  /* Sort is icon-only. The label still exists for the script that writes the
     current sort into it, and for screen readers — it is just not drawn. */
  /* Square, and it has to be said forcefully: the base sheet gives sort
     buttons a min-width sized for their old text label. */
  #catalog-filters .sort-button {
    width: 34px !important;
    min-width: 34px !important;
    max-width: 34px !important;
    padding: 0 !important;
  }
  #catalog-filters .sort-button .sort-text,
  #catalog-filters .sort-button > svg:last-child { display: none !important; }
  #catalog-filters .sort-button .u-ico { display: block; }

  #catalog-filters #clear-all-filters-top { padding: 0 0.7rem !important; }
  #catalog-filters .u-ico { flex: 0 0 auto; }
}

/* ---- Clear all: an icon, and only when there is something to clear ---------
   It was a permanent button reading "✕ ↺ Clear all" — two glyphs and a label
   for a control that does one thing, sitting lit up on a page with no filters
   applied. Now it is the reset glyph alone, the same square plate as the
   controls beside it, and it is not in the row at all until a chip other than
   All is active. Nothing to clear, nothing to look at. */
@media (min-width: 1025px) {
  #catalog-filters #clear-all-filters-top {
    display: none !important;
    width: 34px !important;
    min-width: 34px !important;
    padding: 0 !important;
    font-size: 0 !important;          /* kills the stray ✕ text node */
  }
  #catalog-filters #clear-all-filters-top .u-ico {
    font-size: initial;
    display: block;
  }
  /* Appears the moment the selection is anything but All. */
  #catalog-filters:has(.button-group button.active:not([data-value="all"])) #clear-all-filters-top,
  #catalog-filters:has(.multi-select-button.has-selection) #clear-all-filters-top,
  #catalog-filters:has(#searchInput:not(:placeholder-shown)) #clear-all-filters-top {
    display: inline-flex !important;
  }

  /* One instrument rail: equal plates, one gap, hard against the right edge. */
  #catalog-filters .r1-right {
    display: flex !important;
    align-items: center;
    gap: 0.5rem !important;
    margin-left: auto;
  }
  #catalog-filters .r1-right > * { flex: 0 0 auto; }
  #catalog-filters .r1-right .search-compact { margin-right: 0.15rem; }
}

/* ---- No cell rules, ever; and the cover answers only to itself -------------
   The dashes came back on hover because the base sheet draws them on the cells
   in the hover state as well as the rest state — killing them at rest only was
   half the job. The row's own gradient is the single separator.

   And the cover: it was reacting to the whole row, so pointing anywhere in a
   row made a 60px thumbnail move. It now responds only when the pointer is
   actually on it. No scale — the covers are not a consistent shape, so growing
   them by a percentage moves each one a different distance and reads as
   several different animations. A ring in the work's own colour is
   dimension-independent: same effect on a square cover and a tall one. */
@media (min-width: 1025px) {
  .results-section .composition-row td,
  .results-section .composition-row:hover td {
    border-bottom: 0 !important;
    box-shadow: none !important;
  }

  .results-section .composition-row:hover img,
  .results-section .composition-row:hover picture {
    transform: none !important;
  }
  /* No ring on the cover. It was colour arriving on hover for a thumbnail that
     is not the thing being hovered, and it competed with the wipe crossing the
     row underneath it. The cover stays still. */
  .results-section .composition-row td:first-child img,
  .results-section .composition-row td:first-child img:hover {
    box-shadow: none !important;
  }
}

/* ---- The two things actually drawing those lines --------------------------
   Found in p-70e81fad45.css, not in anything I wrote:

     .composition-row:hover { transform: translateY(-3px) }
     .composition-row::before { linear-gradient(#5B86F9,#7C3AED); width 0 -> 3px }

   The lift is the bug. A hovered row rising 3px slides off its own separator
   and uncovers the one belonging to the row below, so you get a line that
   looks like it belongs to a cell — and it only appears on hover, which is why
   killing borders at rest never touched it. Rows cannot lift anyway: the whole
   reason the accent bar draws instead is that a row has nowhere to go without
   shoving its neighbours.

   The ::before is a second accent bar in house purple, from before any of this
   had per-work colour. Mine is on the first cell, so this one just goes. */
@media (min-width: 1025px) {
  .results-section .composition-row:hover,
  .results-section .composition-row:focus-within {
    transform: none !important;
  }
  .results-section .composition-row::before,
  .results-section .composition-row:hover::before {
    display: none !important;
    width: 0 !important;
  }
}

/* The row's own border-bottom, from p-70e81fad45.css:796. With
   border-collapse: separate a <tr> border is drawn per cell, so it renders as
   the short segments under Duration and Year rather than as a line — the bits
   still showing after the cell borders were cleared. The gradient above is the
   separator; this one has nothing left to do. */
@media (min-width: 1025px) {
  .results-section .compositions-table tbody tr.composition-row {
    border-bottom: 0 !important;
  }
}

/* ---- The row pops out without moving --------------------------------------
   The carousel covers can lift because each is an independent block with space
   around it to cast into. A table row has neither: translateY(-3px) is exactly
   what slid it off its own separator and produced the stray lines.

   So the row takes the elevation and not the movement — a hairline plus the
   edition's square cast, which is the same hardware every plate on the page
   uses, and z-index so the cast draws over its neighbours instead of under the
   next row. It reads as the row coming off the sheet; nothing shifts, nothing
   reflows, and the separator stays exactly where it was.

   box-shadow on a <tr> only paints because this table is border-collapse:
   separate — in collapse mode the row is not a paint container and the shadow
   is dropped. That is the one thing to check if the table model ever changes. */
@media (min-width: 1025px) {
  .results-section .composition-row {
    position: relative;
    z-index: 0;
    transition: background-color 0.18s ease, box-shadow 0.18s ease !important;
  }
  .results-section .composition-row:hover {
    z-index: 2;
    box-shadow:
      0 0 0 1px rgba(2, 6, 23, 0.3),
      7px 7px 0 rgba(2, 6, 23, 0.16) !important;
  }
  /* The work's own colour in the cast, same as every cover surface. */
  .results-section .composition-row.has-chroma:hover {
    box-shadow:
      0 0 0 1px rgba(2, 6, 23, 0.3),
      7px 7px 0 hsl(var(--work-accent) / 0.4) !important;
  }
  @media (prefers-reduced-motion: reduce) {
    .results-section .composition-row { transition: none !important; }
  }
}

/* ---- Polish --------------------------------------------------------------
   The last of the segments: p-70e81fad45.css sets
   `.composition-row:hover > td { background: inherit }`, and `inherit` copies
   the whole background — including the row's background-image, which is the
   1px separator gradient. So on hover every cell drew its own copy of the
   separator along its own bottom edge, which is why they appeared as marks
   under Duration and Year and stopped at the cell boundaries. The cells carry
   no background of their own; the row does. */
@media (min-width: 1025px) {
  .results-section .composition-row > td,
  .results-section .composition-row:hover > td {
    background: transparent !important;
  }

  /* 21%, down from 26%. With the cast and the hairline now carrying the state,
     the fill only has to say "this row" — at 26% the red works read as a
     warning rather than a highlight. */
  .results-section .composition-row.has-chroma:hover {
    background-color: color-mix(in oklab, hsl(var(--work-accent)) 21%, #ffffff) !important;
  }
  /* The cast sits closer in and a touch lighter, so it reads as a lift rather
     than an outline around the row. */
  .results-section .composition-row.has-chroma:hover {
    box-shadow:
      0 0 0 1px rgba(2, 6, 23, 0.26),
      5px 5px 0 hsl(var(--work-accent) / 0.34) !important;
  }
  .results-section .composition-row:hover {
    box-shadow:
      0 0 0 1px rgba(2, 6, 23, 0.26),
      5px 5px 0 rgba(2, 6, 23, 0.14) !important;
  }
}

/* ---- And now it can actually lift -----------------------------------------
   translateY(-3px) was unsafe before for one specific reason: the separator
   was a border-bottom on the row, so lifting the row left the line behind and
   uncovered the neighbour's. Both of those are now gone — the row's border is
   zeroed and the separator is a background-image on the row itself, which
   travels with it. Nothing is left behind to expose.

   translate(-1px, -1px), not -3px: it is the same gesture every plate, tile and
   control on this page makes, and the cast at 5px is what sells the height. A
   3px jump on a 90px row reads as the list twitching. */
@media (min-width: 1025px) {
  .results-section .composition-row {
    transition: background-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease !important;
  }
  .results-section .composition-row:hover {
    transform: translate(-1px, -1px) !important;
  }
  @media (prefers-reduced-motion: reduce) {
    .results-section .composition-row:hover { transform: none !important; }
  }
}

/* ---- Every icon control is the same plate ---------------------------------
   The bar had three different kinds of control sitting in a row: bare glyphs
   (search, sort) with no surface at all, a <label> wrapping a checkbox
   (Featured) sized by its own text, and two real buttons on plates. Same job,
   same size, same hardware — one rail of instruments rather than three
   unrelated widgets that happen to be adjacent. */
@media (min-width: 1025px) {
  #catalog-filters #searchIcon,
  #catalog-filters .featured-toggle,
  #catalog-filters #clear-all-filters-top,
  #catalog-filters #filterToggle,
  #catalog-filters .sort-button {
    box-sizing: border-box !important;
    width: 34px !important;
    min-width: 34px !important;
    max-width: 34px !important;
    height: 34px !important;
    padding: 0 !important;
    margin: 0 !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    flex: 0 0 auto !important;
    color: var(--ee-ink) !important;
    background: #ffffff !important;
    border: 1px solid rgba(2, 6, 23, 0.45) !important;
    border-radius: 6px !important;
    box-shadow: 2px 2px 0 rgba(2, 6, 23, 0.22) !important;
    font-size: 0 !important;            /* no stray labels inside the plates */
    line-height: 1 !important;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  }
  #catalog-filters #searchIcon:hover,
  #catalog-filters .featured-toggle:hover,
  #catalog-filters #clear-all-filters-top:hover,
  #catalog-filters #filterToggle:hover,
  #catalog-filters .sort-button:hover {
    transform: translate(-1px, -1px);
    box-shadow: 3px 3px 0 rgba(2, 6, 23, 0.3) !important;
  }
  /* The checkbox inside the Featured label is the state, not the picture. */
  #catalog-filters .featured-toggle input { position: absolute; opacity: 0; pointer-events: none; }
  #catalog-filters .featured-toggle:has(input:checked) {
    background: var(--secondary-100, #f4efe2) !important;
    box-shadow: 0 0 0 1px rgba(2, 6, 23, 0.45) inset !important;
  }
  #catalog-filters svg { display: block; }

  /* One rail, one gap, hard right — and the drawer's control lines up under it. */
  #catalog-filters .r1-right { display: flex !important; align-items: center !important; gap: 0.5rem !important; }
  #catalog-filters .filters-r2 { justify-content: flex-end !important; align-items: center !important; gap: 0.5rem !important; }
}
