/* ===== Edition system — shared print hardware =====
   Extracted from the music-catalog concept so all main pages share one
   visual language: ink masthead, navy Buy Now, plate dots, glass overlay.

   The component rules below are desktop-scoped, because hover tiers, plate
   sizes and sticky behaviour are built for a pointer and a wide field. The
   tokens are not — they are the vocabulary, and a phone needs them to say the
   same things in a smaller voice. They used to live inside the desktop query,
   which meant --ee-ink and the whole cast scale were simply undefined on
   mobile and every rule referencing them silently did nothing. */
:root {
  --ee-ink: hsl(221, 39%, 13%);

  --ee-edge: rgba(2, 6, 23, 0.35);
  --ee-cast: rgba(2, 6, 23, 0.20);
  --ee-cast-deep: rgba(2, 6, 23, 0.28);
  --ee-cast-broad: rgba(2, 6, 23, 0.16);
  --ee-cast-broad-deep: rgba(2, 6, 23, 0.22);

  --ee-lift-sm: 2px 2px 0 var(--ee-cast);
  --ee-lift-sm-hover: 3px 3px 0 var(--ee-cast-deep);
  --ee-lift-md: 4px 4px 0 var(--ee-cast-broad);
  --ee-lift-md-hover: 6px 6px 0 var(--ee-cast-broad-deep);
  --ee-lift-lg: 8px 8px 0 var(--ee-cast-broad);
  --ee-lift-lg-hover: 11px 11px 0 var(--ee-cast-broad-deep);
  --ee-lift-plate: 10px 10px 0 var(--ee-cast-broad);
}

/* A cast is a plate lying above the page, and how far it lifts should scale
   with how much room the page has. An 8px offset that reads as considered on a
   1440px field reads as clumsy on a 390px one, where it eats real estate the
   content needs. Same scale, shorter throw. */
@media (max-width: 1024px) {
  :root {
    --ee-lift-sm: 1px 1px 0 var(--ee-cast);
    --ee-lift-sm-hover: 2px 2px 0 var(--ee-cast-deep);
    --ee-lift-md: 2px 2px 0 var(--ee-cast-broad);
    --ee-lift-md-hover: 3px 3px 0 var(--ee-cast-broad-deep);
    --ee-lift-lg: 3px 3px 0 var(--ee-cast-broad);
    --ee-lift-lg-hover: 4px 4px 0 var(--ee-cast-broad-deep);
    --ee-lift-plate: 4px 4px 0 var(--ee-cast-broad);
  }
}

@media (min-width: 1025px) {
  :root {
    --ee-ink: hsl(221, 39%, 13%);

    /* One cast-shadow scale. Every offset is square and unblurred — the whole
       system is printed sheets stacked on a page, and a blurred or lopsided
       cast breaks that read. Small elements carry more alpha because they
       cast over a much smaller area. Hover always steps up exactly one rung. */
    --ee-edge: rgba(2, 6, 23, 0.35);
    --ee-cast: rgba(2, 6, 23, 0.20);
    --ee-cast-deep: rgba(2, 6, 23, 0.28);
    --ee-cast-broad: rgba(2, 6, 23, 0.16);
    --ee-cast-broad-deep: rgba(2, 6, 23, 0.22);

    --ee-lift-sm: 2px 2px 0 var(--ee-cast);
    --ee-lift-sm-hover: 3px 3px 0 var(--ee-cast-deep);
    --ee-lift-md: 4px 4px 0 var(--ee-cast-broad);
    --ee-lift-md-hover: 6px 6px 0 var(--ee-cast-broad-deep);
    --ee-lift-lg: 8px 8px 0 var(--ee-cast-broad);
    --ee-lift-lg-hover: 11px 11px 0 var(--ee-cast-broad-deep);
    --ee-lift-plate: 10px 10px 0 var(--ee-cast-broad);
  }

      /* The masthead sits on its ink rule; a soft halo under it belongs to the
         old elevation language and fights that edge. */
      .header-base,
      .example-1 {
        box-shadow: none !important;
      }

      /* ===== Hover tiers ====================================================
         One motion for everything that responds: a 1px lift toward the light
         into a square unblurred cast. Only the depth of the cast changes, by
         how big the thing is. Use the class on new markup; the selector lists
         beside each class adopt the existing components.

           .ee-hover-control  buttons and small square controls   3px
           .ee-hover-tile     tiles, comp cards, result cards     6px
           .ee-hover-sheet    panels, folios, large cards         8px
           .ee-hover-plate    cover art and other big plates     10px

         Rest states are set per component (a seated button keeps its 1px seat,
         a cover card sits flat); the tier only owns the hover. Containers that
         merely hold controls are deliberately NOT given a tier — a backdrop
         that moves when you cross it reads as a glitch, and nesting two lifts
         makes both wobble. */

      .ee-hover-control,
      .ee-hover-tile,
      .ee-hover-sheet,
      .ee-hover-plate {
        transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
      }

      /* Components adopting the control tier. These were the stragglers: the
         filter chips and Clear all still used blurred glows (0 4px 6px and
         0 6px 20px), and the carousel arrows changed colour without deepening
         their cast. */
      #catalog-filters .button-group button,
      #catalog-filters .btn-group button,
      #catalog-filters .btn.u-btn,
      #catalog-filters .u-btn--pill,
      .filter-controls .multi-select-button,
      .nr-thumb-carousel .related-works-nav-btn,
      .video-carousel .related-works-nav-btn,
      .news-nr-audio-accordion .accordion-toggle,
      .collections-toggle {
        transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
      }
      #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,
      .nr-thumb-carousel .related-works-nav-btn:hover,
      .video-carousel .related-works-nav-btn:hover,
      .news-nr-audio-accordion .accordion-toggle:hover {
        transform: translate(-1px, -1px) !important;
        box-shadow: var(--ee-lift-sm-hover) !important;
      }
      /* the arrows are absolutely positioned and already carry a centring
         transform, so they take the cast without the translate */
      .nr-thumb-carousel .related-works-nav-btn:hover,
      .video-carousel .related-works-nav-btn:hover {
        transform: none !important;
      }

      .ee-hover-control:hover { transform: translate(-1px, -1px); box-shadow: var(--ee-lift-sm-hover) !important; }
      .ee-hover-tile:hover    { transform: translate(-1px, -1px); box-shadow: var(--ee-lift-md-hover) !important; }
      .ee-hover-sheet:hover   { transform: translate(-1px, -1px); box-shadow: var(--ee-lift-lg) !important; }
      .ee-hover-plate:hover   { transform: translate(-1px, -1px); box-shadow: var(--ee-lift-plate) !important; }

      @media (prefers-reduced-motion: reduce) {
        .ee-hover-control:hover,
        .ee-hover-tile:hover,
        .ee-hover-sheet:hover,
        .ee-hover-plate:hover { transform: none !important; }
      }

      /* ---------- 11 · Masthead: press-bed rule + ink link states ---------- */
      /* Nav wordmark: same ink voice as the rest of the edition — genuinely thick */
      .brand-title {
        font-weight: 900 !important;
        -webkit-text-stroke: 0.8px currentColor;
        letter-spacing: -0.015em !important;
        color: var(--gray-950, var(--ee-ink)) !important;
      }
      .brand-roles .role-link,
      .brand-roles .role-sep {
        text-transform: uppercase;
        font-size: 11px !important;
        letter-spacing: 0.1em !important;
        font-weight: 600;
      }

      /* Crisp ink rule under the header — the page's plates hang from it */
      .header-base {
        border-bottom: 2px solid rgba(2, 6, 23, 0.85) !important;
        box-shadow: none !important;
      }
      /* Active page: ink text with a crisp underline rule (no pill, no glow) */
      .main-nav a.active {
        color: var(--gray-950, var(--ee-ink)) !important;
        font-weight: 700 !important;
        text-decoration: underline !important;
        text-underline-offset: 9px;
        text-decoration-thickness: 2px;
        text-decoration-color: var(--ee-ink);
      }
      .main-nav a:not(.active):hover {
        color: var(--gray-950, var(--ee-ink)) !important;
      }
      /* Dropdowns: white plates with ink edges and offset shadows, cream hover */
      .main-nav .dropdown-menu {
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 8px !important;
        box-shadow: var(--ee-lift-md) !important;
        padding: 6px !important;
      }
      .main-nav .dropdown-menu a {
        border-radius: 5px !important;
      }
      .main-nav .dropdown-menu a:hover {
        background: var(--secondary-100) !important;
        color: var(--gray-950, var(--ee-ink)) !important;
      }

      /* ---------- 10a · Side section dots: tiny plates, same hardware ---------- */
      .side-dot-nav .dot {
        width: 11px !important;
        height: 11px !important;
        border-radius: 3px !important;
        border: 1.5px solid rgba(2, 6, 23, 0.55) !important;
        background: #ffffff !important;
        box-shadow: var(--ee-lift-sm) !important;
      }
      .side-dot-nav .dot:hover {
        background: var(--secondary-100) !important;
        border-color: var(--ee-ink) !important;
        transform: scale(1.1) !important;
      }
      .side-dot-nav .dot.active {
        background: var(--primary-600) !important;
        border-color: var(--ee-ink) !important;
        box-shadow: 0 0 0 2px #ffffff, 1.5px 1.5px 0 2px rgba(2, 6, 23, 0.3) !important;
      }
      .side-dot-nav .dot-label {
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 5px !important;
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        font-weight: 800 !important;
        font-size: 0.72rem !important;
        text-transform: uppercase !important;
        letter-spacing: 0.07em !important;
        box-shadow: var(--ee-lift-sm) !important;
      }

      /* Free / contact / toggle variants keep their own colour — that colour
         carries meaning — but the cast is material, not meaning, so they use
         the same square offset as everything else instead of a coloured glow. */
      .buy-now-btn.free,
      .buy-now-btn.free-download-btn,
      .buy-now-btn.contact-btn,
      .composition-buy-btn.free,
      .composition-buy-btn.free-download-btn,
      .composition-buy-btn.contact-btn,
      .u-toggle {
        box-shadow: 0 1px 0 var(--ee-cast) !important;
        transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
      }
      .buy-now-btn.free:hover,
      .buy-now-btn.free-download-btn:hover,
      .buy-now-btn.contact-btn:hover,
      .composition-buy-btn.free:hover,
      .composition-buy-btn.free-download-btn:hover,
      .composition-buy-btn.contact-btn:hover,
      .u-toggle:hover {
        transform: translate(-1px, -1px) !important;
        box-shadow: var(--ee-lift-sm-hover) !important;
      }

      /* ---------- 5 · Buy Now: solid ink, no more purple gradient ---------- */
      /* One confident palette-native CTA. Free-download and contact variants keep
         their own colors. */
      .buy-now-btn:not(.free):not(.free-download-btn):not(.contact-btn),
      .btn-buy:not(.free):not(.free-download-btn):not(.contact-btn),
      .buy-button:not(.free):not(.free-download-btn):not(.contact-btn),
      .composition-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn),
      .enhanced-score-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn),
      .new-releases-section .primary-actions-container .btn-buy.buy-now-btn:not(.free):not(.contact-btn) {
        background: hsl(221, 45%, 22%) !important;
        color: #ffffff !important;
        border: 0 !important;
        border-radius: 8px !important;
        font-weight: 800 !important;
        letter-spacing: 0.01em;
        box-shadow: 0 1px 0 var(--ee-cast) !important;
      }
      .buy-now-btn:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .btn-buy:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .buy-button:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .composition-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .enhanced-score-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .new-releases-section .primary-actions-container .btn-buy.buy-now-btn:not(.free):not(.contact-btn):hover {
        background: hsl(221, 45%, 17%) !important;
        filter: none !important;
        transform: translate(-1px, -1px) !important;
        box-shadow: var(--ee-lift-sm-hover) !important;
      }
      .buy-now-btn:not(.free):not(.free-download-btn):not(.contact-btn):active,
      .btn-buy:not(.free):not(.free-download-btn):not(.contact-btn):active {
        transform: translate(0, 0) !important;
        box-shadow: 0 1px 0 var(--ee-cast) !important;
      }

      /* ---------- 10 · Score overlay: keep the glass, speak the same language ---------- */
      .enhanced-score-overlay-content {
        border-radius: 12px !important;
        border: 1px solid rgba(255, 255, 255, 0.22) !important;
        /* The one deliberate exception to the square-cast rule: this is a modal
           floating over a dimmed page, not a sheet stacked on it, so it keeps
           an ambient shadow. */
        box-shadow: 0 0 0 1px rgba(2, 6, 23, 0.65), 0 24px 64px rgba(0, 0, 0, 0.45) !important;
      }
      /* Header: flat folio navy instead of a gradient */
      .enhanced-score-overlay-header {
        background: hsl(221, 45%, 17%) !important;
        border-radius: 12px 12px 0 0 !important;
        border-bottom: 1px solid rgba(255, 255, 255, 0.14) !important;
      }
      .enhanced-score-overlay-main-title {
        font-weight: 900 !important;
        letter-spacing: -0.02em !important;
      }
      .enhanced-score-overlay-instrumentation {
        font-style: italic !important;
        color: rgba(255, 255, 255, 0.8) !important;
      }
      .enhanced-score-overlay-close {
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        border: 1px solid rgba(2, 6, 23, 0.45) !important;
        border-radius: 6px !important;
        font-size: 1.1rem !important;
        box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35) !important;
      }
      .enhanced-score-overlay-close:hover { background: var(--secondary-100) !important; }
      /* Header actions on navy: Buy Now flips to white/ink (navy-on-navy would vanish),
         Learn More becomes a ghost button — same hardware, dark ground */
      .enhanced-score-overlay-actions .buy-now-btn:not(.free):not(.free-download-btn):not(.contact-btn),
      .enhanced-score-overlay-actions .composition-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn),
      .enhanced-score-overlay-actions .buy-button:not(.free):not(.free-download-btn):not(.contact-btn),
      .enhanced-score-overlay-actions .enhanced-score-buy-btn:not(.free):not(.free-download-btn):not(.contact-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 rgba(0, 0, 0, 0.3) !important;
      }
      .enhanced-score-overlay-actions .buy-now-btn:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .enhanced-score-overlay-actions .composition-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .enhanced-score-overlay-actions .buy-button:not(.free):not(.free-download-btn):not(.contact-btn):hover,
      .enhanced-score-overlay-actions .enhanced-score-buy-btn:not(.free):not(.free-download-btn):not(.contact-btn):hover {
        background: var(--secondary-100) !important;
        transform: translate(-1px, -1px) !important;
        box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.35) !important;
      }
      .enhanced-score-overlay-actions .learn-more-btn,
      .enhanced-score-overlay-actions .enhanced-score-learn-more-btn,
      .enhanced-score-overlay-actions .btn:not(.buy-now-btn):not(.composition-buy-btn):not(.buy-button) {
        background: transparent !important;
        color: #ffffff !important;
        border: 1px solid rgba(255, 255, 255, 0.45) !important;
        border-radius: 8px !important;
        font-weight: 800 !important;
      }
      .enhanced-score-overlay-actions .learn-more-btn:hover,
      .enhanced-score-overlay-actions .enhanced-score-learn-more-btn:hover,
      .enhanced-score-overlay-actions .btn:not(.buy-now-btn):not(.composition-buy-btn):not(.buy-button):hover {
        background: rgba(255, 255, 255, 0.12) !important;
        border-color: rgba(255, 255, 255, 0.7) !important;
      }
      /* Tabs: ghost segments on the glass; active tab is the white plate */
      .enhanced-score-overlay .score-media-toggle {
        padding: 10px 15px !important;
        border-bottom: 1px solid rgba(255, 255, 255, 0.16) !important;
      }
      .enhanced-score-overlay .media-toggle-btn {
        background: transparent !important;
        color: rgba(255, 255, 255, 0.88) !important;
        border: 1px solid rgba(255, 255, 255, 0.32) !important;
        border-radius: 6px !important;
        font-weight: 700 !important;
      }
      .enhanced-score-overlay .media-toggle-btn:hover {
        background: rgba(255, 255, 255, 0.12) !important;
        filter: none !important;
      }
      .enhanced-score-overlay .media-toggle-btn.active {
        background: #ffffff !important;
        color: var(--ee-ink) !important;
        border-color: #ffffff !important;
        box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35) !important;
      }
}

/* ===== One loading-placeholder treatment ==================================
   The site had grown eight different shimmer keyframes across components
   (loading-shimmer, nrSk, pc-skeleton, sk-shimmer, skeleton, skeleton-shimmer,
   news-loading-shimmer, rc-shimmer) at four durations, two easings, both
   sweep directions, and five colour recipes — two of which were inverted
   relative to each other, so placeholders on the same page shimmered in
   opposite polarity at different speeds. Several also used cool slate greys
   on the warm cream surfaces, where they read as muddy and barely moved.

   This is one treatment for all of them. The fill is translucent ink rather
   than a fixed grey, so it tints whatever surface it sits on — cream stays
   cream, white stays white — and the contrast is high enough to actually read
   as "loading" without shouting. Deliberately outside the desktop-only media
   query: loading states matter at every width. */

/* Percentage background-position aligns X% of the image with X% of the box,
   so with a 200%-wide gradient only 0%..100% keeps the box fully covered —
   sweeping outside that range leaves an uncovered band with a hard edge. */
@keyframes ee-skeleton-sweep {
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}

.nr-sk,
.loading-gradient,
.streaming-skeleton,
.ld-line,
.ld-chip,
.sk,
.sk-thumb,
.nr-thumb.scaffold-thumb > div:first-child,
#featuredPrimaryPlayer > div[style],
.video-thumb[aria-hidden="true"] > div[style],
.table-header-cell[style*="shimmer"],
[style*="loading-shimmer"] {
  background-image: linear-gradient(
    100deg,
    rgba(2, 6, 23, 0.085) 20%,
    rgba(2, 6, 23, 0.035) 45%,
    rgba(2, 6, 23, 0.085) 70%
  ) !important;
  background-color: transparent !important;
  background-size: 200% 100% !important;
  background-repeat: no-repeat !important;
  animation: ee-skeleton-sweep 1.4s ease-in-out infinite !important;
  border-radius: 6px !important;
}

/* A cover plate whose image has not arrived.
   The scaffold covers the gap before the real cards render, but once they do,
   an <img> that has not loaded is just an empty box with its alt text sitting
   in it — which is what a slow connection actually shows, and it reads as
   broken rather than as loading. The plate holds the same sweep as every other
   placeholder until the image paints, and the alt text is hidden while it does,
   so the swap is plate-for-plate.

   Deliberately outside the desktop-only query: a slow connection is not a
   desktop problem. */
.nr-thumb:not(.ee-img-ready),
.composition-image:not(.ee-img-ready),
.nr-thumb:not(.ee-img-ready) img,
.composition-image:not(.ee-img-ready) img {
  color: transparent !important;
}
.nr-thumb:not(.ee-img-ready),
.composition-image:not(.ee-img-ready) {
  background-image: linear-gradient(
    100deg,
    rgba(2, 6, 23, 0.085) 20%,
    rgba(2, 6, 23, 0.035) 45%,
    rgba(2, 6, 23, 0.085) 70%
  ) !important;
  background-size: 200% 100% !important;
  background-repeat: no-repeat !important;
  animation: ee-skeleton-sweep 1.4s ease-in-out infinite !important;
}
@media (prefers-reduced-motion: reduce) {
  .nr-thumb:not(.ee-img-ready),
  .composition-image:not(.ee-img-ready) {
    animation: none !important;
  }
}

/* Blocks that stand in for a cover or a player read better with the same
   hairline the real plate will have, so the swap is edge-for-edge. */
.nr-thumb.scaffold-thumb > div:first-child,
#featuredPrimaryPlayer > div[style],
.video-thumb[aria-hidden="true"] > div[style],
.sk-thumb {
  box-shadow: inset 0 0 0 1px rgba(2, 6, 23, 0.16) !important;
  border-radius: 8px !important;
}

/* Text stand-ins keep a text-like height and a tighter radius. */
.ld-line,
.nr-sk-line,
.nr-sk-title {
  border-radius: 4px !important;
}

/* A sweeping gradient is exactly the kind of motion vestibular sensitivity
   guidance asks you to drop; hold a steady fill instead of removing the cue. */
@media (prefers-reduced-motion: reduce) {
  .nr-sk,
  .loading-gradient,
  .streaming-skeleton,
  .ld-line,
  .ld-chip,
  .sk,
  .sk-thumb,
  .nr-thumb.scaffold-thumb > div:first-child,
  #featuredPrimaryPlayer > div[style],
  .video-thumb[aria-hidden="true"] > div[style],
  [style*="loading-shimmer"] {
    animation: none !important;
    background-image: none !important;
    background-color: rgba(2, 6, 23, 0.06) !important;
  }
}

/* With the wrapper neutralised, the inner button sets the size — and it inherits
   a compact 32px rule while Learn More beside it is 44px. Match them: measured
   Learn More at 112x44, padding 7.68/12.8, 14.4px text. */
@media (min-width: 1025px) {
  #news-new-release-buy > button,
  #news-new-release-buy > a,
  .primary-actions-container .btn-buy.buy-now-btn > button,
  .primary-actions-container .buy-now-btn > button.buy-now-btn,
  .primary-actions-container .buy-now-btn > .composition-buy-btn {
    min-height: 44px !important;
    padding: 7.68px 12.8px !important;
    font-size: 0.9rem !important;
    line-height: 1.1 !important;
    border-radius: 8px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    box-sizing: border-box !important;
  }
}

/* Placed last on purpose, and deliberately specific: the navy button rule that
   paints these carries six classes, so a plain `.buy-now-btn:has(...)` (two)
   lost to it on specificity even though it matched. */
@media (min-width: 1025px) {
  /* PurchaseButton renders its <button> INTO a wrapper that already carries the
     same classes, so wrapper and button were both painted as plates — a button
     inside a button, with two casts stacking on hover. When a buy control
     contains another control, the outer is only a container. */
  #news-new-release-buy:has(button),
  #news-new-release-buy:has(a),
  .primary-actions-container .btn-buy.buy-now-btn:has(button):not(.free):not(.contact-btn):not(.free-download-btn),
  .primary-actions-container .buy-now-btn:has(.composition-buy-btn):not(.free):not(.contact-btn):not(.free-download-btn),
  .expanded-actions .buy-now-btn:has(button):not(.free):not(.contact-btn):not(.free-download-btn),
  .collection-actions-flex .buy-now-btn:has(button):not(.free):not(.contact-btn):not(.free-download-btn) {
    background: none !important;
    background-color: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    min-height: 0 !important;
    border-radius: 0 !important;
    transform: none !important;
  }
  #news-new-release-buy:has(button):hover,
  .primary-actions-container .btn-buy.buy-now-btn:has(button):not(.free):not(.contact-btn):not(.free-download-btn):hover,
  .primary-actions-container .buy-now-btn:has(.composition-buy-btn):not(.free):not(.contact-btn):not(.free-download-btn):hover,
  .expanded-actions .buy-now-btn:has(button):not(.free):not(.contact-btn):not(.free-download-btn):hover,
  .collection-actions-flex .buy-now-btn:has(button):not(.free):not(.contact-btn):not(.free-download-btn):hover {
    background: none !important;
    background-color: transparent !important;
    box-shadow: none !important;
    transform: none !important;
  }
}

/* ===== Audio transport ======================================================
   The native <audio> element is browser furniture — the same grey pill on every
   site on the internet, which is a strange thing to hand someone on a
   composer's page. This replaces it with a precision timeline: a graduated rule
   with major and minor divisions, the elapsed span inked in, a hairline cursor,
   and tabular timecode with time remaining. The <audio> element is still the
   engine underneath, so with the script blocked you get native controls back.

   Not inside a desktop-only query — a player has to work at every width. */

.ee-transport {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  padding: 0.7rem 0.85rem;
  background: #ffffff;
  border: 1px solid rgba(2, 6, 23, 0.3);
  border-radius: 8px;
  box-sizing: border-box;
}

.ee-transport .ee-tp-btn {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: #ffffff;
  color: hsl(221, 39%, 13%);
  border: 1px solid rgba(2, 6, 23, 0.45);
  border-radius: 6px;
  cursor: pointer;
  box-shadow: 2px 2px 0 rgba(2, 6, 23, 0.2);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.ee-transport .ee-tp-btn svg { width: 16px; height: 16px; display: block; }
.ee-transport .ee-tp-btn:hover {
  background: hsl(45, 42%, 96%);
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 rgba(2, 6, 23, 0.28);
}
/* Playing is a held state, so the primary control stays pressed in rather than
   raised — you can see at a glance which take is running. */
.ee-transport.is-playing .ee-tp-play {
  background: hsl(221, 45%, 22%);
  border-color: hsl(221, 45%, 22%);
  color: #ffffff;
  box-shadow: none;
  transform: none;
}
.ee-transport .ee-tp-restart,
.ee-transport .ee-tp-vol { width: 30px; height: 30px; }
.ee-transport .ee-tp-restart svg,
.ee-transport .ee-tp-vol svg { width: 14px; height: 14px; }
.ee-transport.is-muted .ee-tp-vol { color: hsl(0, 55%, 42%); }

/* ---- the timeline ------------------------------------------------------ */
/* A graduated rule with major and minor divisions and a hairline cursor —
   the idiom editing tools use. An earlier version drew a notehead riding the
   line; it was a literal metaphor and read as decorative rather than precise. */
.ee-transport .ee-tp-stave {
  position: relative;
  flex: 1 1 auto;
  height: 50px;
  min-width: 80px;
  cursor: pointer;
  touch-action: none;
}
.ee-transport .ee-tp-stave:focus-visible {
  outline: 2px solid hsl(221, 45%, 22%);
  outline-offset: 3px;
  border-radius: 3px;
}
/* the baseline */
.ee-transport .ee-tp-rule {
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  margin-top: -0.5px;
  background: rgba(2, 6, 23, 0.22);
}
/* graduations: minor every 1/20, major every 1/4 */
.ee-transport .ee-tp-ticks {
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 14px;
  margin-top: -7px;
  pointer-events: none;
  background-image:
    linear-gradient(90deg, rgba(2, 6, 23, 0.3) 0 1px, transparent 1px),
    linear-gradient(90deg, rgba(2, 6, 23, 0.16) 0 1px, transparent 1px);
  background-size: 25% 100%, 5% 100%;
  background-position: 0 0, 0 0;
  background-repeat: repeat-x, repeat-x;
  -webkit-mask-image:
    linear-gradient(180deg, transparent 0 18%, #000 18% 82%, transparent 82%),
    linear-gradient(180deg, transparent 0 36%, #000 36% 64%, transparent 64%);
  -webkit-mask-composite: source-over;
  mask-image:
    linear-gradient(180deg, transparent 0 18%, #000 18% 82%, transparent 82%),
    linear-gradient(180deg, transparent 0 36%, #000 36% 64%, transparent 64%);
  mask-composite: add;
}
/* elapsed span */
.ee-transport .ee-tp-ink {
  position: absolute;
  left: 0; top: 50%;
  height: 2px;
  margin-top: -1px;
  width: 0;
  background: hsl(221, 45%, 22%);
  pointer-events: none;
}
/* playhead: a hairline cursor spanning the rule, with a fine cap top and bottom */
.ee-transport .ee-tp-cursor {
  position: absolute;
  top: 50%;
  left: 0;
  width: 1.5px;
  height: 20px;
  margin-top: -10px;
  margin-left: -0.75px;
  background: hsl(221, 45%, 22%);
  pointer-events: none;
  box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.9);
}

/* ---- clock ------------------------------------------------------------- */
.ee-transport .ee-tp-clock {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 0.28rem;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-weight: 800;
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  color: hsl(221, 39%, 13%);
  white-space: nowrap;
}
.ee-transport .ee-tp-sep { opacity: 0.4; }
.ee-transport .ee-tp-dur { opacity: 0.62; }
/* time remaining, the way an editing tool shows it */
.ee-transport .ee-tp-rem {
  margin-left: 0.5rem;
  padding-left: 0.5rem;
  border-left: 1px solid rgba(2, 6, 23, 0.18);
  opacity: 0.55;
  font-size: 0.72rem;
}

@media (prefers-reduced-motion: reduce) {
  .ee-transport .ee-tp-btn { transition: none; }
  .ee-transport .ee-tp-btn:hover { transform: none; }
}

/* ---- waveform ----------------------------------------------------------
   Real peaks decoded from the file, not a decorative pattern — it is the shape
   of the actual take, so every piece looks like itself. It replaces the ruled
   timeline once decoded; if decoding is blocked or unsupported the rule stays
   and nothing is lost. */
.ee-transport .ee-tp-wave {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 32px;
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}
.ee-transport.has-wave .ee-tp-wave { opacity: 1; }
/* once the waveform is up, the fallback rule and graduations step aside */
.ee-transport.has-wave .ee-tp-rule,
.ee-transport.has-wave .ee-tp-ticks,
.ee-transport.has-wave .ee-tp-ink { opacity: 0; }

.ee-transport .ee-tp-wave canvas {
  display: block;
  width: 100%;
  height: 100%;
}
/* the played span is the same waveform in ink, revealed by a clip that grows */
.ee-transport .ee-tp-wave-fill {
  position: absolute;
  left: 0; top: 0;
  height: 32px;
  width: 0;
  overflow: hidden;
  pointer-events: none;
}
.ee-transport .ee-tp-wave-fill canvas {
  height: 100%;
  max-width: none;
}

/* ---- timeline ruler + hover readout ------------------------------------
   The waveform says what the take sounds like; the ruler says where you are in
   it. Editors show both for exactly that reason, so this pairs them: peaks
   above, graduated rule with timestamps below, one cursor spanning the two. */
.ee-transport .ee-tp-ruler {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 17px;
  display: none;
  pointer-events: none;
}
.ee-transport.has-wave .ee-tp-ruler { display: block; }
/* with the ruler carrying the graduations, the fallback ticks retire */
.ee-transport.has-wave .ee-tp-rule,
.ee-transport.has-wave .ee-tp-ticks { display: none; }

/* the cursor spans the waveform band only, so it does not cut the labels */
.ee-transport.has-wave .ee-tp-cursor {
  top: 0;
  height: 32px;
  margin-top: 0;
}

/* Ghost cursor under the pointer, with the time it would seek to. */
.ee-transport {
  /* Its own leading, not the host's. The composition page wraps its player in a
     div carrying an inline line-height:0 — the usual trick for killing the
     descender gap under a raw <audio> element — and that inherited straight
     through to the scrub badge, whose text box collapsed to nothing and left a
     3px sliver of padding hanging in the stave. The transport should not depend
     on what a host does to its own leading. */
  line-height: var(--leading-normal, 1.5);
}

.ee-transport .ee-tp-hover {
  position: absolute;
  top: 0;
  height: 32px;
  width: 1px;
  margin-left: -0.5px;
  background: rgba(2, 6, 23, 0.35);
  opacity: 0;
  transition: opacity 0.12s ease;
  pointer-events: none;
}
.ee-transport.is-hovering .ee-tp-hover { opacity: 1; }
/* Seated inside the track rather than floating above it: above, it was clipped
   wherever the player sits in a container with its own bounds. */
.ee-transport .ee-tp-hover-time {
  position: absolute;
  top: 1px;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.1rem 0.32rem;
  border-radius: 3px;
  background: hsl(221, 45%, 22%);
  color: #ffffff;
  font-size: 0.62rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

/* ---- transport on a dark ground ----------------------------------------
   The score overlay is a dark glass panel. Dropping a white card into it would
   read as a page control that had fallen in, so the transport inverts: the
   plate becomes a hairline on the glass and the ink becomes light. */
.ee-transport.on-dark {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.22);
}
.ee-transport.on-dark .ee-tp-btn {
  background: transparent;
  color: #ffffff;
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow: none;
}
.ee-transport.on-dark .ee-tp-btn:hover {
  background: rgba(255, 255, 255, 0.14);
  transform: none;
  box-shadow: none;
}
.ee-transport.on-dark.is-playing .ee-tp-play {
  background: #ffffff;
  border-color: #ffffff;
  color: hsl(221, 45%, 22%);
}
.ee-transport.on-dark .ee-tp-clock { color: rgba(255, 255, 255, 0.92); }
.ee-transport.on-dark .ee-tp-rem { border-left-color: rgba(255, 255, 255, 0.25); }
.ee-transport.on-dark .ee-tp-rule { background: rgba(255, 255, 255, 0.25); }
.ee-transport.on-dark .ee-tp-ink { background: #ffffff; }
.ee-transport.on-dark .ee-tp-cursor {
  background: #ffffff;
  box-shadow: 0 0 0 1.5px rgba(2, 6, 23, 0.5);
}
.ee-transport.on-dark .ee-tp-hover { background: rgba(255, 255, 255, 0.5); }
.ee-transport.on-dark .ee-tp-hover-time { background: #ffffff; color: hsl(221, 45%, 22%); }


/* ===== Icons =============================================================
   Lucide (ISC), inlined as masked SVG: each takes currentColor and costs no
   request. Applied via ::before on existing controls, so adding one never
   means touching markup.

   The SVG is single-quoted deliberately. Double quotes inside would close
   the CSS url("...") on the spot, which fails silently with no icon. */

.ee-icon-search::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='11'%20cy='11'%20r='8'/%3E%3Cpath%20d='m21%2021-4.3-4.3'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='11'%20cy='11'%20r='8'/%3E%3Cpath%20d='m21%2021-4.3-4.3'/%3E%3C/svg%3E"); }
.ee-icon-sliders::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cline%20x1='21'%20x2='14'%20y1='4'%20y2='4'/%3E%3Cline%20x1='10'%20x2='3'%20y1='4'%20y2='4'/%3E%3Cline%20x1='21'%20x2='12'%20y1='12'%20y2='12'/%3E%3Cline%20x1='8'%20x2='3'%20y1='12'%20y2='12'/%3E%3Cline%20x1='21'%20x2='16'%20y1='20'%20y2='20'/%3E%3Cline%20x1='12'%20x2='3'%20y1='20'%20y2='20'/%3E%3Cline%20x1='14'%20x2='14'%20y1='2'%20y2='6'/%3E%3Cline%20x1='8'%20x2='8'%20y1='10'%20y2='14'/%3E%3Cline%20x1='16'%20x2='16'%20y1='18'%20y2='22'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cline%20x1='21'%20x2='14'%20y1='4'%20y2='4'/%3E%3Cline%20x1='10'%20x2='3'%20y1='4'%20y2='4'/%3E%3Cline%20x1='21'%20x2='12'%20y1='12'%20y2='12'/%3E%3Cline%20x1='8'%20x2='3'%20y1='12'%20y2='12'/%3E%3Cline%20x1='21'%20x2='16'%20y1='20'%20y2='20'/%3E%3Cline%20x1='12'%20x2='3'%20y1='20'%20y2='20'/%3E%3Cline%20x1='14'%20x2='14'%20y1='2'%20y2='6'/%3E%3Cline%20x1='8'%20x2='8'%20y1='10'%20y2='14'/%3E%3Cline%20x1='16'%20x2='16'%20y1='18'%20y2='22'/%3E%3C/svg%3E"); }
.ee-icon-x::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M18%206%206%2018'/%3E%3Cpath%20d='m6%206%2012%2012'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M18%206%206%2018'/%3E%3Cpath%20d='m6%206%2012%2012'/%3E%3C/svg%3E"); }
.ee-icon-sort::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m21%2016-4%204-4-4'/%3E%3Cpath%20d='M17%2020V4'/%3E%3Cpath%20d='m3%208%204-4%204%204'/%3E%3Cpath%20d='M7%204v16'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m21%2016-4%204-4-4'/%3E%3Cpath%20d='M17%2020V4'/%3E%3Cpath%20d='m3%208%204-4%204%204'/%3E%3Cpath%20d='M7%204v16'/%3E%3C/svg%3E"); }
.ee-icon-star::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M11.5%202.7a.7.7%200%200%201%201%200l2.4%205%205.4.8a.7.7%200%200%201%20.4%201.2l-4%203.8.9%205.4a.7.7%200%200%201-1%20.7l-4.8-2.5-4.8%202.5a.7.7%200%200%201-1-.7l.9-5.4-4-3.8a.7.7%200%200%201%20.4-1.2l5.4-.8z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M11.5%202.7a.7.7%200%200%201%201%200l2.4%205%205.4.8a.7.7%200%200%201%20.4%201.2l-4%203.8.9%205.4a.7.7%200%200%201-1%20.7l-4.8-2.5-4.8%202.5a.7.7%200%200%201-1-.7l.9-5.4-4-3.8a.7.7%200%200%201%20.4-1.2l5.4-.8z'/%3E%3C/svg%3E"); }
.ee-icon-score::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V8z'/%3E%3Cpath%20d='M14%202v6h6'/%3E%3Ccircle%20cx='10'%20cy='16'%20r='2'/%3E%3Cpath%20d='M12%2016V9l4%201'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V8z'/%3E%3Cpath%20d='M14%202v6h6'/%3E%3Ccircle%20cx='10'%20cy='16'%20r='2'/%3E%3Cpath%20d='M12%2016V9l4%201'/%3E%3C/svg%3E"); }
.ee-icon-music::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M9%2018V5l12-2v13'/%3E%3Ccircle%20cx='6'%20cy='18'%20r='3'/%3E%3Ccircle%20cx='18'%20cy='16'%20r='3'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M9%2018V5l12-2v13'/%3E%3Ccircle%20cx='6'%20cy='18'%20r='3'/%3E%3Ccircle%20cx='18'%20cy='16'%20r='3'/%3E%3C/svg%3E"); }
.ee-icon-wave::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M2%2013a2%202%200%200%200%202-2V7a2%202%200%200%201%204%200v13a2%202%200%200%200%204%200V4a2%202%200%200%201%204%200v13a2%202%200%200%200%204%200v-4a2%202%200%200%201%202-2'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M2%2013a2%202%200%200%200%202-2V7a2%202%200%200%201%204%200v13a2%202%200%200%200%204%200V4a2%202%200%200%201%204%200v13a2%202%200%200%200%204%200v-4a2%202%200%200%201%202-2'/%3E%3C/svg%3E"); }
.ee-icon-cap::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%2010v6'/%3E%3Cpath%20d='M6%2012.5V16a6%203%200%200%200%2012%200v-3.5'/%3E%3Cpath%20d='m2%2010%2010-5%2010%205-10%205z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%2010v6'/%3E%3Cpath%20d='M6%2012.5V16a6%203%200%200%200%2012%200v-3.5'/%3E%3Cpath%20d='m2%2010%2010-5%2010%205-10%205z'/%3E%3C/svg%3E"); }
.ee-icon-code::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m16%2018%206-6-6-6'/%3E%3Cpath%20d='m8%206-6%206%206%206'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m16%2018%206-6-6-6'/%3E%3Cpath%20d='m8%206-6%206%206%206'/%3E%3C/svg%3E"); }

/* lucide: circle-play — the one glyph the set was missing, for "Watch" */
.ee-icon-play::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='10'/%3E%3Cpath%20d='m10%208%206%204-6%204z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='10'/%3E%3Cpath%20d='m10%208%206%204-6%204z'/%3E%3C/svg%3E"); }

/* lucide: maximize — the state expands the score to fill the view, so the
   control says expand. "Watch" promised a video and there is no video. */
.ee-icon-expand::before { -webkit-mask-image: url("data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'><path%20d='M8%203H5a2%202%200%200%200-2%202v3'/><path%20d='M21%208V5a2%202%200%200%200-2-2h-3'/><path%20d='M3%2016v3a2%202%200%200%200%202%202h3'/><path%20d='M16%2021h3a2%202%200%200%200%202-2v-3'/></svg>"); mask-image: url("data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'><path%20d='M8%203H5a2%202%200%200%200-2%202v3'/><path%20d='M21%208V5a2%202%200%200%200-2-2h-3'/><path%20d='M3%2016v3a2%202%200%200%200%202%202h3'/><path%20d='M16%2021h3a2%202%200%200%200%202-2v-3'/></svg>"); }

/* shared geometry for every glyph */
[class*="ee-icon-"]::before,
#catalog-filters #filterToggle::before,
#catalog-filters #clear-all-filters-top::before,
#catalog-filters .sort-button::before,
#catalog-filters .featured-toggle::before,
[data-ee-unused-role-marks]::before {
  content: "";
  display: inline-block;
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}

@media (min-width: 1025px) {
  #catalog-filters #filterToggle { display: inline-flex !important; align-items: center; }
  #catalog-filters #filterToggle::before { margin-right: 0.42rem; -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cline%20x1='21'%20x2='14'%20y1='4'%20y2='4'/%3E%3Cline%20x1='10'%20x2='3'%20y1='4'%20y2='4'/%3E%3Cline%20x1='21'%20x2='12'%20y1='12'%20y2='12'/%3E%3Cline%20x1='8'%20x2='3'%20y1='12'%20y2='12'/%3E%3Cline%20x1='21'%20x2='16'%20y1='20'%20y2='20'/%3E%3Cline%20x1='12'%20x2='3'%20y1='20'%20y2='20'/%3E%3Cline%20x1='14'%20x2='14'%20y1='2'%20y2='6'/%3E%3Cline%20x1='8'%20x2='8'%20y1='10'%20y2='14'/%3E%3Cline%20x1='16'%20x2='16'%20y1='18'%20y2='22'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cline%20x1='21'%20x2='14'%20y1='4'%20y2='4'/%3E%3Cline%20x1='10'%20x2='3'%20y1='4'%20y2='4'/%3E%3Cline%20x1='21'%20x2='12'%20y1='12'%20y2='12'/%3E%3Cline%20x1='8'%20x2='3'%20y1='12'%20y2='12'/%3E%3Cline%20x1='21'%20x2='16'%20y1='20'%20y2='20'/%3E%3Cline%20x1='12'%20x2='3'%20y1='20'%20y2='20'/%3E%3Cline%20x1='14'%20x2='14'%20y1='2'%20y2='6'/%3E%3Cline%20x1='8'%20x2='8'%20y1='10'%20y2='14'/%3E%3Cline%20x1='16'%20x2='16'%20y1='18'%20y2='22'/%3E%3C/svg%3E"); }
  #catalog-filters #clear-all-filters-top { display: inline-flex !important; align-items: center; }
  #catalog-filters #clear-all-filters-top::before { margin-right: 0.42rem; -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M18%206%206%2018'/%3E%3Cpath%20d='m6%206%2012%2012'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M18%206%206%2018'/%3E%3Cpath%20d='m6%206%2012%2012'/%3E%3C/svg%3E"); }
  #catalog-filters .sort-button { display: inline-flex !important; align-items: center; }
  #catalog-filters .sort-button::before { margin-right: 0.42rem; -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m21%2016-4%204-4-4'/%3E%3Cpath%20d='M17%2020V4'/%3E%3Cpath%20d='m3%208%204-4%204%204'/%3E%3Cpath%20d='M7%204v16'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m21%2016-4%204-4-4'/%3E%3Cpath%20d='M17%2020V4'/%3E%3Cpath%20d='m3%208%204-4%204%204'/%3E%3Cpath%20d='M7%204v16'/%3E%3C/svg%3E"); }
  #catalog-filters .featured-toggle { display: inline-flex !important; align-items: center; }
  #catalog-filters .featured-toggle::before { margin-right: 0.42rem; -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M11.5%202.7a.7.7%200%200%201%201%200l2.4%205%205.4.8a.7.7%200%200%201%20.4%201.2l-4%203.8.9%205.4a.7.7%200%200%201-1%20.7l-4.8-2.5-4.8%202.5a.7.7%200%200%201-1-.7l.9-5.4-4-3.8a.7.7%200%200%201%20.4-1.2l5.4-.8z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M11.5%202.7a.7.7%200%200%201%201%200l2.4%205%205.4.8a.7.7%200%200%201%20.4%201.2l-4%203.8.9%205.4a.7.7%200%200%201-1%20.7l-4.8-2.5-4.8%202.5a.7.7%200%200%201-1-.7l.9-5.4-4-3.8a.7.7%200%200%201%20.4-1.2l5.4-.8z'/%3E%3C/svg%3E"); }
  #catalog-filters #filterToggle::after { display: none !important; }
  #catalog-filters .featured-toggle::before { opacity: 0.55; }
  #catalog-filters .featured-toggle:has(input:checked)::before { opacity: 1; }

  /* Teaching Books is the educator's shelf, so it carries the same mark */

}

/* ===== Material and motion ==================================================
   Nothing here depicts anything: no notes, no horns, no symbols. Every attempt
   to state the identity read as costume. What is left is the two things a
   physical object has that a hex value does not — a surface that catches light
   unevenly, and weight when it moves.

   The test every candidate has to pass: if a visitor can name it, it is
   already too loud. It should change how the page feels without ever
   presenting itself as a thing that was added.

   Two things deliberately NOT done, having tried them:
     - No entrance animation on the featured panel or the expanded collection.
       Both already run their own JS-driven reveals, and a second animation
       fights the first.
     - No new stacking contexts. The grain rides the full-bleed background layer
       that already exists, rather than a fresh positioned pseudo-element, which
       would put a z-index over the sticky panel and the expanded overlay. */

/* ---- substrate: three candidates, gated for comparison -------------------
   Grain was tried and pulled. Simulated noise on a screen does not read as
   paper; it reads as a compression artefact, and the field agrees — it is a
   known shortcut for making flat work feel "full" without earning it.

   The tiled hairline grid was ruled out for the opposite reason: it is so
   overused it has a name ("that Vercel grid"), and an arbitrary 24px tile is
   exactly the generic SaaS wallpaper this design set out to avoid.

   Ruled lines of every kind are ruled out, and this was learned the expensive
   way. Column rules on the works table, margin rules down each field, and a
   five-line staff behind the waveform were each built and each rejected on
   sight: drawn lines read as school stationery, not as engraving, however
   accurately they are aligned to real structure. Alignment does not rescue a
   line. Do not propose ruling anything again.

   What survives is tone, not line. */

/* Tonal press bed, on the open field.
   No pattern: each field is fractionally denser at its outer edges than at its
   centre, the way light actually falls across a sheet lying on a bed. There is
   no tile, no motif and no repeat, so there is nothing to recognise — it only
   stops the surface reading as a dead flat fill. */
#popular-works,
#catalog-collections-section,
#news-nr-thumb-rail {
  background-image:
    linear-gradient(
      to right,
      rgba(2, 6, 23, 0.05) 0%,
      rgba(2, 6, 23, 0) 22%,
      rgba(2, 6, 23, 0) 78%,
      rgba(2, 6, 23, 0.05) 100%
    );
}

/* ---- chroma: each work casts in its own colour ---------------------------
   Taken from the covers, which are the brand. What they share as a set is not
   a motif, a texture or a typeface — it is that every work owns a saturated
   colorway of its own. That is the publishing idea (each edition has a
   colorway) and the database idea (a computed attribute per record) turning
   out to be the same idea, so it is the one that belongs here.

   The accent is read out of the artwork offline (sync/build-cover-colors.mjs)
   and arrives as --work-accent. A plate then casts a shadow tinted by its own
   cover, the way coloured light bounces off a real printed sheet — which is
   why it lands on the cast rather than on a border or a fill. Nothing is
   drawn, nothing is depicted, and no line is added.

   Works with no cover art never get .has-chroma and keep the neutral cast. */
@media (min-width: 1025px) {
  #catalog-new-releases-host .nr-thumb.has-chroma:hover,
  .expanded-item.has-chroma:hover {
    box-shadow: 6px 6px 0 hsl(var(--work-accent) / 0.4) !important;
  }
  #catalog-new-releases-host .composition-image.has-chroma:hover {
    box-shadow: 10px 10px 0 hsl(var(--work-accent) / 0.42) !important;
  }

}

/* ===== The field =========================================================
   The area behind the featured work takes that work's colour: a few percent of
   its accent mixed into the cream, and above that a plate of the cover itself
   blurred past recognition, drifting.

   Not an abstract shape — a drifting blob is the stock move and would read as
   exactly the generic styling this design avoids. This is generated from the
   artwork, so it is the work's own colour in the work's own proportions, and it
   is different for all 67 of them.

   At every width, unlike everything above. The old version was desktop-only for
   one stated reason — "a large layer under a 48px blur, animating indefinitely,
   is the wrong thing to hand a phone's battery" — and that blur is gone (see
   .ee-field-art), so the reason went with it. */

/* Both the section and its ::before, and both !important. The page CSS sets
   `background: var(--secondary-200)` on each — a shorthand, so a plain
   `background-color` here loses to it — and ::before is a 100vw full-bleed
   band, so missing it leaves the tint showing only in the narrow gutters.

   Held to single digits deliberately. At 16% a cool accent turns the cream
   grey-green and the field stops being cream at all, which trades a known good
   colour for a gimmick. At 8% the worst case (a blue cover against warm cream)
   still reads as cream, just cooler. */
/* The media page's featured band is the same shape of problem — its ::before
   carries `background: var(--secondary-200)` as a shorthand and runs full
   bleed — so it takes the same rule rather than a second one that would drift
   away from this one. --field-accent is set there by edition-ring.js from the
   featured work, so the band follows whichever video is loaded. */
#popular-works,
#popular-works::before,
.media-rail.media-videos-rail::before,
.composition-page .composition-main,
.composition-page .composition-main::before {
  background-color: color-mix(in oklab, hsl(var(--field-accent, 40 20% 50%)) 8%, #f4efe2) !important;
  /* Slower than a UI transition and eased at both ends, because this is the
     light in the room changing rather than a control answering a click. */
  transition: background-color 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

/* The panel waits for its contents. See composition.html: the markup ships
   empty and the work is fetched, so without this the plate is on screen as a
   set of blank boxes and then snaps full. It fades in over a beat instead, once
   there is a title in it. The band underneath is already the work's colour, so
   what you see first is the right room with the plate arriving into it. */
.composition-page.is-loading .composition-content-container {
  opacity: 0;
}
.composition-page .composition-content-container {
  transition: opacity 0.34s ease;
}

/* Except on a work's own page, where there is nothing to transition between.
   The catalogue cross-fades because the featured work changes underneath a
   band that stays put, and the fade is the light in the room changing. A
   composition page shows one work and never swaps it, so the only thing the
   transition can do is run once on load — cream fallback fading up to the
   work's colour — which reads as the page correcting itself rather than as
   anything deliberate. It arrives already coloured now. */
.composition-page .composition-main,
.composition-page .composition-main::before,
.composition-page .composition-top-frame {
  transition: none !important;
}

/* The change has to be legible, not just present.
   At 5% two works with neighbouring hues — Be Thou My Vision at 29° and
   Resolutions at 46° — resolved to the same cream, so changing between them
   looked exactly like nothing happening. Measured: the field never actually
   failed to update (10/10 on load, 0/6 stale when clicking every 250ms); it
   just could not be seen doing it.

   So the resting state moves 5% -> 8%, still inside the band where the cream
   stays cream, and the moment of change briefly overshoots to 15% before
   settling back. The overshoot is what you notice; the resting value is what
   you live with. Raising the resting tint alone to the point of being obvious
   would have cost the cream, which is the thing worth keeping. */
#popular-works.is-shifting,
#popular-works.is-shifting::before,
.composition-page .composition-main.is-shifting,
.composition-page .composition-main.is-shifting::before {
  background-color: color-mix(in oklab, hsl(var(--field-accent, 40 20% 50%)) 15%, #f4efe2) !important;
  transition-duration: 0.35s;
}

/* ---- more colour, without spending the cream -----------------------------
   Everything above is the fallback now. The note about 16% turning the cream
   grey-green is correct, but it diagnoses the wrong cause: mixing accent into
   cream drops the lightness as well as adding chroma, and it is the lightness
   going that reads as grey. Chroma was never the problem.

   So take the chroma and the hue from a much stronger mix and put the
   lightness straight back to the cream's own. Measured across all 59 covers:

     mix    lightness   median ΔE between neighbouring works   worst L*
     8%     free        3.7  (today — "just noticeable")        89
     16%    free        7.4  (the version that went grey)       84
     20%    locked      9.0                                     92
     32%    locked     11.8                                     90

   Two and a half times today's separation, and *lighter* than today at its
   worst rather than four points darker. There was no tradeoff to make; there
   was a wrong operation.

   Relative colour syntax, guarded, exactly as the catalogue's heading colour
   already does it — a browser without it keeps the 8/15% mix above, which is
   what shipped and is fine. */
@supports (color: oklch(from white l c h)) {
  #popular-works,
  #popular-works::before,
  .composition-page .composition-main,
  .composition-page .composition-main::before {
    background-color: oklch(
      from color-mix(in oklab, hsl(var(--field-accent, 40 20% 50%)) 20%, #f4efe2) 0.952 c h
    ) !important;
  }
  #popular-works.is-shifting,
  #popular-works.is-shifting::before,
  .composition-page .composition-main.is-shifting,
  .composition-page .composition-main.is-shifting::before {
    background-color: oklch(
      from color-mix(in oklab, hsl(var(--field-accent, 40 20% 50%)) 32%, #f4efe2) 0.952 c h
    ) !important;
  }
}

/* ---- the foot of the band ---------------------------------------------------
   The field ended on a bare colour change: tinted cream meeting the section
   below it with nothing between them, which reads as two backgrounds abutting
   rather than as one plate ending.

   The rule is the one the rail already uses — a hairline over a heavier ink
   line, a plate seated in a press bed — so the bottom of the band closes the
   same way the carousel inside it does. Full width, because the band is.

   On the element rather than its ::before: the ::before is a 100vw full-bleed
   layer sitting behind the content, and a border there would be painted under
   everything and clipped by the section's own overflow. */
#popular-works {
  border-bottom: 2px solid var(--ee-ink, hsl(221, 39%, 13%));
  box-shadow: inset 0 -3px 0 rgba(2, 6, 23, 0.06);
}

/* A single hairline where the band meets the section below it. The catalogue's
   full press bed — 2px of ink over an inset hairline — was tried here and is
   too much: that weight suits a band ending the page's whole run of works, and
   over-marks a seam between two sections of one page. One line, dark enough to
   be a deliberate join rather than two colours happening to meet. */
.composition-page .composition-main {
  border-bottom: 1px solid rgba(2, 6, 23, 0.28);
}

/* The section below brings its own --gray-300 rule, which would sit a second,
   paler line directly under the ink one. */
.composition-page .program-video-section {
  border-top: 0 !important;
}

/* The band ran out 48px short of the section below it, and the body's cream
   showed through as a stripe across the page — the work's colour stopping, a
   band of something else, then the next section.

   The space is wanted; the stripe is not. So the 3rem margin below the band
   moves onto the band as padding: the gap is exactly as deep as it was, and it
   is the work's colour rather than a seam between two backgrounds. */
.composition-page .program-video-section {
  margin-top: 0 !important;
}
.composition-page .composition-main {
  padding-bottom: 3rem !important;
  /* And the same at the head. A 24px top margin left a stripe of cream between
     the masthead and the band, so it moves onto the band too: the content sits
     where it sat, and the space above it belongs to the work rather than to
     the page behind it. */
  margin-top: 0 !important;
  padding-top: 24px !important;
}

/* ---- the plates below the fold ----------------------------------------------
   The bands themselves keep the colours they had. Recolouring them to paper and
   the work's tint was tried and pulled: the page reads better with those two
   bands staying as they were, and the hero band is the one that carries the
   record's colour.

   The plates standing on them are a different matter. They cast at the medium
   tier, 4px, while the panel at the top of the same page casts at 8px — the
   same object at two heights on one screen, which is what makes it look like
   two different systems rather than one. They cast the same now. */
.composition-page .program-notes-column {
  box-shadow: 0 0 0 1px var(--ee-edge), var(--ee-lift-lg) !important;
}

/* The video is out of its plate. A video is already a rectangle of picture with
   its own hard edge, so a plate around it was a frame around a frame — and the
   thumbnail carries the work's title and artwork, which is the job the plate
   was doing. The cast moves onto the video, so it sits on the page the way the
   cover does rather than floating on the band with nothing holding it. */
.composition-page .videos-column {
  background: transparent !important;
  box-shadow: none !important;
  border: 0 !important;
  border-radius: 0 !important;
}
.composition-page .youtube-embed-container {
  border-radius: 10px !important;
  overflow: hidden !important;
  /* An edge, not a cast. The lift was added when the video came out of its
     plate, on the reasoning that it needed something to hold it — but the other
     embedded cards on the page carry a hairline and nothing else, and a video
     already reads as an object without being propped up. */
  box-shadow: 0 0 0 1px var(--ee-edge) !important;
}

/* The multi-video controls, built as the catalogue's movement controls are:
   two square plates and a counter, sized to the line of text beside them rather
   than to a toolbar. One press moves one video, so they read as a pair of
   controls belonging to that heading — where "Previous" and "Next" at 36px in a
   grey gradient read as a form, and were the only gradient left on the page.

   Values taken from #catalog-new-releases-host .audio-nav-btn so the two behave
   identically: the same plate, the same 1px lift into a squarer cast, and the
   same treatment at the ends of the set — the plate stays, the cast drops away,
   so it reads as inert rather than missing. */
.composition-page .video-nav-btn {
  width: 30px !important;
  height: 30px !important;
  min-height: 0 !important;
  padding: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  font-size: 17px !important;
  font-weight: 800 !important;
  line-height: 1 !important;
  /* Bare, like the play control. These sit under a video and beside a tracked
     counter, none of which is on a plate, so putting two plates there made the
     only hardware in a row of marks. */
  color: var(--ee-ink, hsl(221, 39%, 13%)) !important;
  background: transparent !important;
  background-image: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transition: opacity 0.15s ease !important;
}
.composition-page .video-nav-btn:hover:not(:disabled) {
  transform: none !important;
  box-shadow: none !important;
  opacity: 0.65 !important;
}
.composition-page .video-nav-btn:disabled {
  opacity: 0.28 !important;
  box-shadow: none !important;
  transform: none !important;
  cursor: default !important;
}
.composition-page .video-nav-info {
  font-style: normal !important;
  text-transform: uppercase !important;
  letter-spacing: 0.1em !important;
  font-size: 0.68rem !important;
  font-weight: 600 !important;
  white-space: nowrap !important;
  color: color-mix(in oklab, var(--ee-ink) 62%, #ffffff) !important;
}
/* A cluster at the end of the title's line, not a bar spanning the column. */
.composition-page .video-nav-container {
  display: flex !important;
  align-items: center !important;
  gap: 0.6rem !important;
  flex: 0 0 auto !important;
}
/* The buttons start on the page's left margin. Both rows sat 8px in from the
   title, the scoring and the audio plate — which all line up at the same x —
   because each button carries an 8px margin, and on the first button of a row
   that margin is an indent rather than spacing. The featured card has no such
   step, and it is the kind of misalignment you cannot unsee once noticed.

   The horizontal margin moves to a gap on the row, so the space between two
   buttons is unchanged (8px + 8px = 16px) while the first one starts where
   everything above it starts. Vertical margins stay: they are what set the 8px
   from the scoring to the buy button and from that row to the next. */
.composition-page .composition-top-frame .composition-buy-btn {
  margin-left: 0 !important;
}
.composition-page .composition-top-frame .layout-builder-nav {
  gap: 16px !important;
}
.composition-page .composition-top-frame .layout-nav-btn {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* "Duration: 20 min" set the label in bold with a colon, which is how a form
   labels a field. The site labels things with a small tracked stamp — the year
   under the cover, the News tag, the video counter — so this uses that, and the
   colon goes with it: a stamp does not need punctuation to separate it from
   what it labels, the change of voice already does that. The value keeps the
   meta column's own size and weight. */
.composition-page .composition-meta {
  font-size: 0.66rem !important;
  font-weight: 800 !important;
  text-transform: uppercase !important;
  letter-spacing: 0.12em !important;
  color: var(--gray-600) !important;
}
/* The value is set as the label is, so the line is one stamp rather than a
   stamp with body copy hanging off it — the mismatch was the whole problem with
   the first attempt. Only the space between them separates the two. */
.composition-page .composition-meta-label {
  margin-right: 0.4rem !important;
}

/* The video's top edge lines up with the notes card's. It carried a 24px top
   margin — inherited from when it sat inside a plate, where the margin was the
   plate's inside gap — and now that the video is its own edge that margin
   pushed it a visible step below the card beside it. The two columns start at
   the same y, so their contents should too. */
.composition-page .composition-video-player {
  margin-top: 0 !important;
}

/* The credit takes the line under the title, on the same margin — it names the
   performers of the video the title names, so the two belong in a column
   together. Right-aligned it sat under the track counter instead, reading as a
   note about the controls.

   And the whole group sits up against the video. It was 14px off, which on a
   caption is enough to read as a separate block rather than as the label of the
   thing above it. */
.composition-page .video-metadata-section {
  margin-top: 0.15rem !important;
  /* Centred, not baseline-aligned: on a baseline the 30px arrows hang below
     the title's descender and stretch the row to 46px for 23px of text. */
  align-items: center !important;
}
.composition-page .video-credit-row {
  display: flex !important;
  justify-content: flex-start !important;
  margin-top: 0 !important;
}
/* The arrows stop padding the row out. They are 30px marks in a line of 23px
   text, so they set the row's height unless told not to. */
.composition-page .video-nav-container {
  min-height: 0 !important;
  line-height: 1 !important;
}
.composition-page .video-nav-btn {
  margin: 0 !important;
  height: 24px !important;
  width: 24px !important;
}
.composition-page .youtube-embed-container iframe {
  border-radius: 10px !important;
  display: block !important;
}
/* The gap under the video is set once, above, with the rest of the caption's
   spacing. This rule set it a second time at 0.85rem and, being later, quietly
   won — the earlier value was the right one for a video that still had a cast
   under it to clear, and it outlived the cast. */

/* The View Score button in the notes column was the right size and the wrong
   material: weight 600 against the page's 800, a --gray-300 border where every
   other button is edged in ink, no fill, and a soft 0 6px 18px drop shadow —
   light diffusing around an object — where the rest of the page casts a hard
   2px offset, which is a plate sitting on paper. Same button as the pair above
   it now, because it is the same button. */
.composition-page .view-score-btn {
  background: #ffffff !important;
  border: 1px solid rgba(2, 6, 23, 0.45) !important;
  box-shadow: rgba(2, 6, 23, 0.2) 2px 2px 0 0 !important;
  font-weight: 800 !important;
  padding: 7.68px 12.8px !important;
  color: var(--ee-ink, hsl(221, 39%, 13%)) !important;
}

/* The stage is deliberately larger than the field so the drift never exposes an
   edge, which once made the page 171px wider than the viewport and scrollable
   sideways onto a bare block of colour.

   `clip` rather than `hidden`: clip does not create a scroll container, so it
   cannot trap scrolling or break a position:sticky descendant the way hidden
   would. The full-bleed ::before loses at most a pixel or two of a flat colour
   band at each edge, which is invisible. */
#popular-works,
.composition-page .composition-main {
  /* Same two things #popular-works needs: somewhere for an absolutely placed
     backdrop to sit, and its own stacking context so a z-index:-1 child lands
     above the section's background rather than behind it. Without the
     isolation the field is painted into a gap nobody can see — which is
     exactly what happened the first time this was tried. */
  position: relative;
  isolation: isolate;
  overflow: clip;
  /* The clip box stops at the padding edge, and the panel and the cover both
     sit flush with the top of the band while drawing a 1px ring just outside
     their own border box. That ring landed on the wrong side of the boundary
     and was cut, so both plates appeared to have no top edge at all — the
     sides and the foot drew, the head did not.

     2px of margin is enough for the ring and not enough to show any of the
     oversized stage this clip is here to contain. overflow-clip-margin only
     moves where painting stops; it creates no scrollable overflow, so the
     sideways-scroll problem that made this clip necessary cannot come back. */
  overflow-clip-margin: 2px;
}

/* The detail panel's glass lives in edition-composition.css, which loads after
   this file and owns the page's own treatment. Setting it here as well only
   created two rules fighting over the same surface. */
.composition-top-frame {
  overflow: clip;
  /* Without this the whole field is invisible, and was.
     The section is position:relative with z-index:auto, so it establishes no
     stacking context — which means a z-index:-1 child does not sit behind the
     section's *content*, it sits behind the section's own opaque background and
     is never seen. Every version of this backdrop, including the blurred cover
     that shipped, painted into that gap. What tinted the band was always just
     the background-color; the artwork was never on screen.

     isolation:isolate makes the section its own stacking context, so -1 lands
     where it reads: above the cream, below the type. The standing warning
     against new stacking contexts is about layers that would ride OVER the
     sticky filter panel and the score overlay — both of which live outside this
     section, so isolating it cannot reach them. Verified: panel still pins.

     All of which applied when this panel hosted the field itself. It does not
     any more — the field moved to .composition-main, which carries its own
     isolation above — and the rule left behind here did active harm: an element
     that isolates becomes its own backdrop root, so its backdrop-filter has
     nothing behind it to sample and blurs nothing at all. Verified by raising
     the blur to 40px and seeing the render not change by a pixel. */
}

/* The stage holds the layers still. It used to drift, back when the picture was
   a plate of the cover; with the plate off and the paper ruled, moving the whole
   field only slides horizontal lines along their own length, which changes no
   pixel. What moves now moves inside it. */
.ee-field-stage {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

/* The circular visualiser on the media page. Absolute, and offset onto the
   viewport from script: `fixed` would be the honest declaration, but the
   section above it carries a leftover transform from its slide-in animation and
   a transformed ancestor makes fixed resolve against that ancestor, so the ring
   scrolled away with the section. -1 keeps it under the card and the prose but
   over the section's cream, and it never takes a click. */
.ee-ring {
  position: absolute;
  z-index: -1;
  pointer-events: none;
}

/* Other arrangements, told apart from the page's own actions.
   Run in as six identical buttons — Watch, View Score, Related Works, Brass
   Ensemble, Piano Reduction, Wind Ensemble — the last three read as more things
   to do to this page rather than as other scorings of the same piece. Pushed to
   the end of the row and given a quiet label, they read as what they are.
   margin-left auto rather than justify-content, so the group still sits at the
   end when the row wraps. */
.composition-page .layout-nav-arrangements {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-left: auto;
}

/* The site's own label voice: small, letterspaced, quiet — the same register as
   the RELEASES and NEWS kickers further down the frame. */
.composition-page .layout-nav-arr-label {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: hsl(221 12% 46%);
  white-space: nowrap;
}

/* At narrow widths the row is already wrapping and an auto margin only pushes
   the group onto a line of its own with a ragged gap above it. Let it sit where
   it falls and lead with its label instead. */
@media (max-width: 900px) {
  .composition-page .layout-nav-arrangements {
    margin-left: 0;
    width: 100%;
  }
}

/* ---- theatre, on a composition page ----------------------------------
 *
 * The same state, on the same audio component, with two names changed: the
 * catalogue calls its panel #news-new-release-content and its player
 * #news-nr-audio-accordion, and a composition page calls them
 * .composition-top-frame and #audio-player-placeholder. Everything inside
 * them — the transport, the play control, the credit row, the volume — is
 * literally the same component, so the inner rules already fit and only the
 * ancestors needed saying twice.
 *
 * Generated by mirroring the block above rather than written out by hand, so
 * the two cannot drift: change the catalogue rule and this is regenerated
 * from it. 26 rules.
 */

/* Theatre keeps one thing from the panel: the player.
   Putting the card away and leaving no transport meant a suite of five
   movements could only be watched from whichever one happened to be loaded.
   So the card is stripped back to nothing rather than faded out — no plate,
no
   glass,
no cover,
no copy — and the player is all that is left of it.

   Not moved in the DOM. An <audio> element taken out of the document and put
   back is required to pause,
and the whole point of the state is that it keeps
   playing; it is translated into place instead.

   !important because the panel's own reveal script writes opacity straight
   onto the element,
and an inline value beats any selector however specific. */
.composition-page .composition-main.ee-theatre .composition-top-frame {
  opacity: 1 !important;
  background: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  pointer-events: none;
}
.composition-page .composition-main.ee-theatre .composition-top-frame > .composition-image,
.composition-page .composition-main.ee-theatre .composition-details > *:not(.news-nr-under-actions),
.composition-page .composition-main.ee-theatre .news-nr-under-actions > *:not(#audio-player-placeholder) {
  opacity: 0 !important;
  pointer-events: none !important;
}
/* The transport itself: glass,
so the score runs behind it,
and the only thing
   on the field that answers a click besides the background. */
/* In theatre the player is the visualiser and nothing else. It used to keep its
   glass plate,
its border and its cast,
plus the performer credit,
the View
   Score button,
the play control,
the clock and the volume — a panel roughly a
   third of the field,
standing in front of the one thing the state exists to
   show. Everything the canvas or the top cluster already provides is dropped,
and what is left is the waveform on the field itself. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder {
  pointer-events: auto;
  position: relative;
  z-index: 4;
  background: transparent !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  /* No width here. placePlayer sets one inline to fit the gap between the title
     and the actions, and an !important rule silently beat it — the block sized
     itself to its content instead, came out 962px against the 795px the
     centring had been calculated from, and so overlapped the title at one end
     while the maths still believed it was centred. */
  transition: transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Held invisible while it is being placed after a work change,
and moved with
   no transition so it cannot be caught gliding into position. */
.composition-page .composition-main.ee-theatre.ee-th-placing #audio-player-placeholder {
  opacity: 0 !important;
  transition: none !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .accordion-body,
.composition-page .composition-main.ee-theatre #audio-player-placeholder .ee-transport {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
}
/* Everything that is not the waveform. The clock is on the canvas,
play/pause
   is the background,
and the credit and View Score are the card's — which is
   the thing being put away. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder .audio-credit-row,
.composition-page .composition-main.ee-theatre #audio-player-placeholder .ee-tp-vol,
.composition-page .composition-main.ee-theatre #audio-player-placeholder .accordion-toggle {
  display: none !important;
}
/* The play control stays,
because the background being the transport is a
   thing you have to try before you know it. It gives up its plate: on the
   field it is a mark rather than a button,
the same as everything else here. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder .ee-tp-play {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  color: var(--ee-ink, hsl(221, 39%, 13%)) !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .ee-tp-play:hover {
  transform: none !important;
  opacity: 0.72;
}
/* One row: movement name,
waveform,
track selector. On the card these stack —
   a header line above the transport — and stacked here the header pushed the
   waveform a row down the field and left the space beside the work's title
   empty. Laid out in a line they fit in that space,
and the state reads across
   the top as one sentence: what is playing,
the picture of it,
which movement.

   display:contents on the header rather than re-parenting in script: it drops
   the wrapper out of the box tree so its two children become items of this row
   directly,
which is exactly what re-parenting would achieve and nothing has to
   be moved to get it. Order puts the transport between them. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder .accordion-body {
  display: flex !important;
  /* Hung from the top rather than centred. Centred, everything in the row took
     its line from the tallest thing in it — the waveform — so raising the
     movement name to the title's line dragged the waveform up with it. From the
     top, the movement name and the track selector sit on the title's line and
     the waveform simply extends further down, which is where it belongs. */
  align-items: flex-start !important;
  gap: 0.85rem !important;
}
/* The text in the row still reads as text on that line,
not as something
   stuck to the top of a 50px box. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder .composition-audio-title {
  margin-top: 6px !important;
}
/* The selector centres on the movement name's line rather than on its own
   height. Its buttons are 22px against 16px of text,
so left to size itself it
   set a 38px box and sat with the waveform instead of with the words it
   belongs to. Given the text's height,
the buttons overflow it evenly and the
   whole cluster reads as part of that line. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder .new-release-audio-nav {
  /* No top margin: the movement name needs 6px to drop onto the title's line
     from the top of the row, and this is already there once it stops sizing
     itself to its buttons. */
  margin-top: 0 !important;
  height: 16px !important;
  align-items: center !important;
  overflow: visible !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .audio-movement-row {
  display: contents !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .composition-audio-title {
  order: 1;
  flex: 0 0 auto;
  font-size: 0.82rem !important;
  line-height: 1.2 !important;
  margin: 0 !important;
  white-space: nowrap;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .new-release-audio-container {
  order: 2;
  flex: 1 1 auto;
  min-width: 0;
  margin: 0 !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .new-release-audio-nav {
  order: 3;
  flex: 0 0 auto;
  min-height: 0 !important;
  padding: 0 !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .audio-nav-btn {
  width: 22px !important;
  height: 22px !important;
}
/* The movement arrows lose their plates too,
for the reason the play control
   did: on the field these are marks,
not hardware. They keep the catalogue's
   shape everywhere else. */
.composition-page .composition-main.ee-theatre #audio-player-placeholder .audio-nav-btn {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  color: hsl(var(--field-accent, 221 39% 13%) / 0.85) !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .audio-nav-btn:hover:not(:disabled) {
  transform: none !important;
  opacity: 0.7;
}
/* No Show. Back leaves the state,
so a second control that does the same thing
   is one more object standing on the picture. Watch still brings it up — the
   button is only redundant once you are in. */
.composition-page .composition-main.ee-theatre .ee-th-toggle {
  display: none !important;
}
.composition-page .composition-main.ee-theatre #audio-player-placeholder .ee-tp-stave {
  flex: 1 1 auto !important;
}
/* The rail keeps its colour. It was dimmed to 0.72 on the reasoning that
   anything not the score should recede,
but the covers are the way to change
   what is playing from inside the state — the one thing here you might still
   want to do — and greying them made them look disabled rather than quiet. */
/* Says the field is the control,
without drawing anything that says so. */
.composition-page .composition-main.ee-theatre { cursor: pointer; }
.composition-page .composition-main.ee-theatre .ee-th-hint { display: block; }
.composition-page .composition-main.ee-theatre.ee-th-hinting .ee-th-hint { opacity: 1; }
/* Playing: two bars,
so the sign says what the press will do rather than what
   is happening. */
.composition-page .composition-main.ee-theatre.ee-th-playing .ee-th-hint::before {
  width: 4px;
  height: 15px;
  border: 0;
  background: hsl(var(--field-accent, 221 39% 13%) / 0.78);
  box-shadow: 8px 0 0 hsl(var(--field-accent, 221 39% 13%) / 0.78);
  transform: translate(-90%, -50%);
}
.composition-page .composition-main.ee-theatre .ee-th-acts {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(0);
}
.composition-page .composition-main.ee-theatre .ee-th-title {
  opacity: 1;
  transform: none;
}

/* What a composition page actually puts away.
 *
 * The mirrored rules above carry the player's own styling across correctly —
 * that is the same component on both pages — but they hide by the catalogue's
 * names, and this hero has none of them: its cover is a sibling of the frame
 * rather than a child, and the frame holds a title, a dedication, a row of
 * links and the player. So the hiding is stated here in this page's own terms,
 * as everything in the frame except the player, plus the cover beside it. */
.composition-page .composition-main.ee-theatre #comp-sec-cover,
.composition-page .composition-main.ee-theatre .composition-top-frame > *:not(#audio-player-placeholder) {
  opacity: 0 !important;
  pointer-events: none !important;
}

/* The frame and the box around it stop being objects: in theatre the field is
   the page and the transport floats on it, exactly as on the catalogue. */
.composition-page .composition-main.ee-theatre .composition-content-container,
.composition-page .composition-main.ee-theatre .composition-top-frame {
  background: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}



/* No filter. The plate arrives already blurred: it is a 12x16 image
   (sync/build-cover-colors.mjs) and the browser's own smoothing does the rest,
   so the softening that used to cost blur(48px) over a ~2.1MP layer on every
   invalidation now costs one 609-byte fetch. Saturate and brightness are baked
   into the plate for the same reason.

   That recipe is unchanged and still load-bearing. Two others were tried and
   rejected against a near-black cover (Coming Home) and a cool one
   (WindSprints), both of which turned the cream to flat grey:
     - normal blend at 0.28 — dark art simply darkened the field;
     - mix-blend-mode: color — takes hue *and saturation* from the source, so a
       desaturated cover stripped the cream's own warmth.
   Brightening first means a dark cover cannot darken, saturating first means
   only genuinely chromatic art registers. The cream can be tinted, never
   greyed. */
.ee-field-art {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  /* Matches the tint cross-fade above, so colour and picture move as one change
     rather than as two. */
  transition: opacity 0.55s ease;
}
/* Off. The cover plate was judged the wrong move — correctly, but from a page
   where the stacking bug above meant it had never once been drawn. Now that it
   can be seen, the call can be made on sight instead of on a description, so
   the layer stays built and costs one 609-byte fetch. Set --plate-strength to
   0.10 to bring it back; 0.22 is what it was written at and reads too strong
   against the manuscript. */
.ee-field-art.is-shown {
  opacity: var(--plate-strength, 0);
}

/* ---- the score ------------------------------------------------------------
   Staves and notes are drawn on one canvas now (edition-chroma.js). What used
   to be here — a tiled five-line gradient and a pool of rounded <span> heads —
   could not do what the field needs to do: draw the scoring of the work. A
   solo with piano is two systems, a brass quintet is five, a wind ensemble is
   a dense stack of hairlines, and a concerto is one prominent system riding
   above the band. That is a different geometry per work and hundreds of marks
   a frame at the top end, which is canvas work, not DOM work. It also means a
   notehead can be a tilted ellipse with a stem instead of a lozenge.

   Nothing here positions anything: the canvas is sized in device pixels by the
   renderer and everything inside it is drawn. This rule only places the layer
   and fades it in. */
.ee-field-score {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  /* Atmosphere that snaps on reads as a flash, so it arrives a beat late — the
     same reason the ruled staff it replaces did. */
  transition: opacity 0.5s ease;
}
.ee-field-score.is-shown {
  opacity: 1;
}
/* Turning to another work: out quickly, rebuilt unseen, back at reading pace.
   Out faster than in, because a page leaving should not be dwelt on and a page
   arriving should. */
.ee-field-score.is-turning {
  opacity: 0;
  transition-duration: 0.22s;
}

/* ---- the work's own sound ------------------------------------------------
   While a track is playing, its waveform rises behind the page and scrolls with
   the playback position, so the background is doing the one thing that is
   actually happening. Silent the rest of the time — motion that has to be
   earned by an event rather than a timer, which is the whole lesson of the
   drift this replaces.

   Sized at 200% and translated by progress, so a full listen walks the shape
   across the field once. A waveform varies vertically, so horizontal movement
   is visible — unlike the staff, and unlike the plate. */
.ee-field-wave {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.8s ease;
  /* Ink laid into the paper rather than onto it: densest along the centre line
     of the waveform and gone by the extremes of its own travel, so the tall
     peaks fade out at their tips instead of ending on a hard edge. --fw-axis
     and --fw-amp are written by edition-chroma.js from the measured band, so
     the falloff tracks the shape rather than the section. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) calc(var(--fw-axis, 50%) - var(--fw-amp, 30%)),
    rgba(0, 0, 0, 0.72) calc(var(--fw-axis, 50%) - var(--fw-amp, 30%) * 0.62),
    rgba(0, 0, 0, 1) calc(var(--fw-axis, 50%) - var(--fw-amp, 30%) * 0.18),
    rgba(0, 0, 0, 1) calc(var(--fw-axis, 50%) + var(--fw-amp, 30%) * 0.18),
    rgba(0, 0, 0, 0.72) calc(var(--fw-axis, 50%) + var(--fw-amp, 30%) * 0.62),
    rgba(0, 0, 0, 0) calc(var(--fw-axis, 50%) + var(--fw-amp, 30%))
  );
  mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) calc(var(--fw-axis, 50%) - var(--fw-amp, 30%)),
    rgba(0, 0, 0, 0.72) calc(var(--fw-axis, 50%) - var(--fw-amp, 30%) * 0.62),
    rgba(0, 0, 0, 1) calc(var(--fw-axis, 50%) - var(--fw-amp, 30%) * 0.18),
    rgba(0, 0, 0, 1) calc(var(--fw-axis, 50%) + var(--fw-amp, 30%) * 0.18),
    rgba(0, 0, 0, 0.72) calc(var(--fw-axis, 50%) + var(--fw-amp, 30%) * 0.62),
    rgba(0, 0, 0, 0) calc(var(--fw-axis, 50%) + var(--fw-amp, 30%))
  );
}
.ee-field-wave.is-shown {
  opacity: 1;
}
/* Breathing. The drawn shape is the recording — fixed, and the identity of the
   piece. This scales it about its own centre line by how loud the moment
   actually is, so the same shape reads as being played rather than displayed.
   The width axis is where you are in the work; the height axis is what is
   happening now, and the field answers both.

   scaleY only, on the compositor, about the waveform's own axis rather than the
   element's middle — scaling about the middle would slide the whole band
   downward as it grew instead of opening it out from the centre. */
.ee-fw-sheet {
  position: absolute;
  inset: 0;
  transform-origin: 50% var(--fw-axis, 50%);
  transform: scaleY(calc(0.62 + var(--wave-live, 0) * 0.8));
  /* Just enough to carry between the 30Hz updates without adding lag you can
     feel on an attack. */
  transition: transform 0.07s linear;
}
.ee-fw-sheet svg {
  width: 100%;
  height: 100%;
  display: block;
}
.ee-fw-sheet path {
  fill: hsl(var(--field-accent, 40 20% 50%));
}
/* The whole work, faint: what you have not heard yet is an impression in the
   paper rather than an absence. */
.ee-fw-ghost {
  opacity: 0.34;
}
/* The part you have heard, inked. Read through 58% white and a 22px blur, so
   it has to be carried far heavier than it would need to be in the open — a
   22px blur averages a 4px bar against its neighbours almost completely, and
   at the 0.14 the single old layer used the glass took it to nothing.
   A clip rather than a transform: the shape stays where the work put it. */
.ee-fw-ink {
  opacity: 0.95;
  clip-path: inset(0 calc(100% - var(--wave-progress, 0) * 100%) 0 0);
  /* Wet at the playhead, dry behind it. The clip alone gave a flat slab of ink
     with a hard edge at the current position, which reads as a progress bar —
     the one thing this must not look like. Grading the last stretch to full
     and letting everything older settle back makes the leading edge the thing
     you notice, and gives the field something to show at 2% of a four-minute
     take, when the inked region is otherwise a strip too narrow to see. */
  -webkit-mask-image: linear-gradient(
    to right,
    rgba(0, 0, 0, 0.45) 0,
    rgba(0, 0, 0, 0.45) calc(var(--wave-progress, 0) * 100% - 14%),
    rgba(0, 0, 0, 1) calc(var(--wave-progress, 0) * 100%)
  );
  mask-image: linear-gradient(
    to right,
    rgba(0, 0, 0, 0.45) 0,
    rgba(0, 0, 0, 0.45) calc(var(--wave-progress, 0) * 100% - 14%),
    rgba(0, 0, 0, 1) calc(var(--wave-progress, 0) * 100%)
  );
}

/* Nothing should animate for a reader who is not looking at it. Set by the
   IntersectionObserver and visibilitychange handlers in edition-chroma.js —
   paused rather than removed, so returning to it does not restart the cycle. */
.ee-field-stage.is-paused .ee-note {
  animation-play-state: paused;
}

/* Hold it still rather than take it away: the plate is the work's colour, which
   is information, and only the drift is motion. Same call as the loading
   skeletons above. */
/* The staff stays — it is the paper, and paper is not motion. The notes are
   motion and nothing else, so they go entirely rather than freezing mid-flight
   where they would read as debris scattered over the field. */
@media (prefers-reduced-motion: reduce) {
  .ee-field-score { display: none; }
  .ee-field-wave { transition: none; }
  #popular-works { transition: none; }
  /* The waveform keeps its recorded shape and stops breathing. The shape is
     information about the work; the breathing is only motion. */
  .ee-fw-sheet { transform: none; transition: none; }
}

/* ---- weight --------------------------------------------------------------
   One easing curve, and a touch more travel time than a UI default. A plate
   that takes 220ms to lift reads as having mass; the same plate at 120ms reads
   as a rectangle changing state. This is the whole of the motion work — no new
   animations, just the existing ones given weight. */
@media (min-width: 1025px) and (prefers-reduced-motion: no-preference) {
  #catalog-new-releases-host .composition-image.has-image,
  #catalog-new-releases-host .nr-thumb,
  #catalog-collections-section .collections-card-header,
  .results .card,
  .expanded-item {
    transition-duration: 0.22s !important;
    transition-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1) !important;
  }

  /* The waveform is the one place a genuine entrance belongs: it arrives with
     real data, so letting it rise once acknowledges that something was read
     rather than drawn. Self-contained, so it fights nothing. */
  .ee-transport .ee-tp-wave {
    transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
    transform: scaleY(0.72);
    transform-origin: center;
  }
  .ee-transport.has-wave .ee-tp-wave { transform: none; }
}

/* ===== Core identity, at every width ======================================
   Everything above is deliberately desktop-only: the brief was a desktop
   concept, and the hover tiers, plate casts and sticky behaviours are sized for
   a pointer and a wide field.

   But four things are not layout — they are the brand — and scoping them to
   desktop meant a phone still showed the old site. Most seriously it still
   showed the purple gradient Buy Now, which was rejected early on and has been
   gone from desktop for months. Someone on a phone has been looking at a
   design that no longer exists anywhere else.

   These carry no layout, no hover and no motion, so they are safe at any width:
   the call to action, the FEATURED stamp, the masthead roles and the press-bed
   rule the page hangs from. */

/* The call to action: one navy plate, no gradient, everywhere. */
.btn-buy.buy-now-btn,
.buy-now-btn,
.buy-button,
.composition-buy-btn {
  background-image: none !important;
  background-color: hsl(221, 45%, 22%) !important;
  color: #ffffff !important;
  border: 1px solid hsl(221, 45%, 18%) !important;
  border-radius: 8px !important;
  font-weight: 800 !important;
  box-shadow: 2px 2px 0 rgba(2, 6, 23, 0.2) !important;
}

/* FEATURED is a stamp pressed into the page, not a glowing pill. */
.card-badge {
  background-image: none !important;
  background-color: hsl(221, 62%, 47%) !important;
  color: #ffffff !important;
  border: 1px solid hsl(221, 62%, 38%) !important;
  border-radius: 4px !important;
  box-shadow: none !important;
  font-weight: 800 !important;
  text-transform: uppercase !important;
  letter-spacing: 0.14em !important;
}

/* The roles line is set as a colophon, not a sentence. */
.brand-roles .role-link,
.brand-roles .role-sep {
  text-transform: uppercase !important;
  letter-spacing: 0.1em !important;
  font-weight: 600 !important;
}

/* The masthead sits on its ink rule at every width. */
.header-base {
  border-bottom: 2px solid rgba(2, 6, 23, 0.85) !important;
}

/* Fixed masthead layers were measuring wider than the viewport, which gave the
   phone 55px of sideways scroll on every page. They are position:fixed, so
   clamping them to the viewport is enough and cannot disturb the flow. */
@media (max-width: 1024px) {
  .example-1,
  .header-base,
  .primary-nav,
  .menu-backdrop {
    max-width: 100vw;
  }
  html, body { overflow-x: hidden; }
}

/* ---- The composition page carries the waveform and nothing else -----------
   The staff and the travelling notes belong to the catalogue's featured band,
   where they sit behind one opaque card on a cream field. A composition page is
   built the other way round: every block on it — title, dedication, links,
   related news — has a transparent background, so a z-index:-1 layer does not
   sit behind the page, it shows through the middle of it. The notes were
   crossing the work's own title and transport.

   So here the field is the waveform, and only while something is playing.
   Nothing in the background when the page is silent. */
/* The composition page gets the same field as the catalogue. It was suppressed
   here while the field was a tiled staff and a scatter of note heads, which had
   nothing to say about the one work the page is about. Now that it draws the
   scoring, it says exactly what that page is for. */

/* ---- The timecode is one control, and it is anchored to the elapsed time ---
   Measured: .ee-tp-dur carried background rgb(98,128,188) and cursor:pointer at
   65x35, while .ee-tp-now — the number that actually moves — was 27x18,
   transparent and not clickable. The affordance was on the one value in the
   transport that never changes.

   The plate now wraps the pair, so the target covers elapsed and duration
   together, and the duration loses its own box. Written with :has() on both
   children, so if the two are ever not siblings the rule simply does not match
   and nothing moves — a miss here should be inert, not misplaced. */
.ee-transport :has(> .ee-tp-now):has(> .ee-tp-dur) {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25rem;
  padding: 0.18rem 0.5rem;
  border-radius: 6px;
  background: rgb(98, 128, 188);
  color: #ffffff;
  cursor: pointer;
}
.ee-transport .ee-tp-dur {
  background: transparent !important;
  padding: 0 !important;
  cursor: inherit !important;
}
.ee-transport .ee-tp-now {
  cursor: inherit;
  font-variant-numeric: tabular-nums;
}

/* ---- The timecode is text, not a control surface ---------------------------
   The plate was wrong: a filled box around the timecode reads as a button, and
   the transport already has real buttons either side of it. It is a readout —
   one you can click, but a readout. So: no fill, no radius, no padding.

   The two halves are weighted by what they do. The elapsed time is the value
   that moves, so it carries the weight and the full ink; the duration never
   changes for the length of a track, so it steps back. Both share one pointer
   and one target — clicking either does the same thing, which is what the
   wrapper was for in the first place. */
.ee-transport .ee-tp-clock {
  background: transparent !important;
  padding: 0 !important;
  border-radius: 0 !important;
  color: inherit !important;
  cursor: pointer;
}
.ee-transport .ee-tp-now {
  font-weight: 800 !important;
  color: var(--ee-ink) !important;
  font-variant-numeric: tabular-nums;
}
.ee-transport .ee-tp-dur {
  font-weight: 500 !important;
  color: color-mix(in oklab, var(--ee-ink) 52%, #ffffff) !important;
  font-variant-numeric: tabular-nums;
}

/* The second value is the duration, not the countdown.
   The transport renders both a duration (.ee-tp-dur, "4:24", fixed) and a
   remaining time (.ee-tp-rem, "-0:25", counting down). The countdown was the
   one on screen after the slash, so both halves of the readout were moving —
   and the half that is supposed to be the anchor was the one changing fastest.
   The duration stays; the countdown is hidden, and the elapsed time on the
   left is the only thing that moves. */
.ee-transport .ee-tp-rem {
  display: none !important;
}
.ee-transport .ee-tp-dur {
  display: inline !important;
}


/* ---- theatre --------------------------------------------------------------
   The card put away so the score can be watched. What is left is a way back,
   the two things worth doing next, the clock and the volume — and the field
   itself, which starts and stops what is playing when you click it.

   The card is faded, not removed: taking a 900px section out of flow to hide
   one panel would drag the whole page up the screen. */
/* A mark, not a plate. It sits over the field rather than in a row of
   controls, and a plate there reads as a button dropped onto the picture —
   the same reason the play control and the movement arrows lost theirs. Being
   an icon rather than a 72px word also stops it reaching so far across the
   card it overlaps. */
#popular-works .ee-th-toggle {
  position: static;
  width: 30px;
  height: 30px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ee-ink, hsl(221, 39%, 13%));
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  opacity: 0.7;
  cursor: pointer;
  transition: opacity 0.15s ease;
}
#popular-works .ee-th-toggle::before {
  width: 21px;
  height: 21px;
}
#popular-works .ee-th-toggle:hover {
  opacity: 1;
  transform: none;
  box-shadow: none;
}
/* In the tray it is one control among others rather than a mark on the field,
   so it takes a little more presence and sits with the View Score button. */
#popular-works .ee-th-toggle.ee-th-inrow {
  opacity: 0.85;
  margin-left: 0.5rem;
  flex: 0 0 auto;
}
/* And the row gives the credit a line of its own once the control is in it.
   Left to wrap on its own, the credit and View Score filled the first line at
   768px and the icon dropped to a second line by itself, stranded at the far
   left. Giving the credit the whole first line puts the two controls together
   on the second at every width, which is the arrangement 420px arrives at
   anyway — so the layout stops depending on how long a performer's name is. */
#popular-works .audio-credit-row:has(.ee-th-inrow) {
  flex-wrap: wrap;
  justify-content: flex-end;
}
#popular-works .audio-credit-row:has(.ee-th-inrow) .audio-performer {
  flex: 1 0 100%;
}

/* Theatre keeps one thing from the panel: the player.
   Putting the card away and leaving no transport meant a suite of five
   movements could only be watched from whichever one happened to be loaded.
   So the card is stripped back to nothing rather than faded out — no plate, no
   glass, no cover, no copy — and the player is all that is left of it.

   Not moved in the DOM. An <audio> element taken out of the document and put
   back is required to pause, and the whole point of the state is that it keeps
   playing; it is translated into place instead.

   !important because the panel's own reveal script writes opacity straight
   onto the element, and an inline value beats any selector however specific. */
#popular-works.ee-theatre #news-new-release-content {
  opacity: 1 !important;
  background: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  pointer-events: none;
}
#popular-works.ee-theatre #news-new-release-content > .composition-image,
#popular-works.ee-theatre .composition-details > *:not(.news-nr-under-actions),
#popular-works.ee-theatre .news-nr-under-actions > *:not(#news-nr-audio-accordion) {
  opacity: 0 !important;
  pointer-events: none !important;
}
/* The transport itself: glass, so the score runs behind it, and the only thing
   on the field that answers a click besides the background. */
/* In theatre the player is the visualiser and nothing else. It used to keep its
   glass plate, its border and its cast, plus the performer credit, the View
   Score button, the play control, the clock and the volume — a panel roughly a
   third of the field, standing in front of the one thing the state exists to
   show. Everything the canvas or the top cluster already provides is dropped,
   and what is left is the waveform on the field itself. */
#popular-works.ee-theatre #news-nr-audio-accordion {
  pointer-events: auto;
  position: relative;
  z-index: 4;
  background: transparent !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  /* No width here. placePlayer sets one inline to fit the gap between the title
     and the actions, and an !important rule silently beat it — the block sized
     itself to its content instead, came out 962px against the 795px the
     centring had been calculated from, and so overlapped the title at one end
     while the maths still believed it was centred. */
  transition: transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Held invisible while it is being placed after a work change, and moved with
   no transition so it cannot be caught gliding into position. */
#popular-works.ee-theatre.ee-th-placing #news-nr-audio-accordion {
  opacity: 0 !important;
  transition: none !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .accordion-body,
#popular-works.ee-theatre #news-nr-audio-accordion .ee-transport {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
}
/* Everything that is not the waveform. The clock is on the canvas, play/pause
   is the background, and the credit and View Score are the card's — which is
   the thing being put away. */
#popular-works.ee-theatre #news-nr-audio-accordion .audio-credit-row,
#popular-works.ee-theatre #news-nr-audio-accordion .ee-tp-vol,
#popular-works.ee-theatre #news-nr-audio-accordion .accordion-toggle {
  display: none !important;
}
/* The play control stays, because the background being the transport is a
   thing you have to try before you know it. It gives up its plate: on the
   field it is a mark rather than a button, the same as everything else here. */
#popular-works.ee-theatre #news-nr-audio-accordion .ee-tp-play {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  color: var(--ee-ink, hsl(221, 39%, 13%)) !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .ee-tp-play:hover {
  transform: none !important;
  opacity: 0.72;
}

/* One row: movement name, waveform, track selector. On the card these stack —
   a header line above the transport — and stacked here the header pushed the
   waveform a row down the field and left the space beside the work's title
   empty. Laid out in a line they fit in that space, and the state reads across
   the top as one sentence: what is playing, the picture of it, which movement.

   display:contents on the header rather than re-parenting in script: it drops
   the wrapper out of the box tree so its two children become items of this row
   directly, which is exactly what re-parenting would achieve and nothing has to
   be moved to get it. Order puts the transport between them. */
#popular-works.ee-theatre #news-nr-audio-accordion .accordion-body {
  display: flex !important;
  /* Hung from the top rather than centred. Centred, everything in the row took
     its line from the tallest thing in it — the waveform — so raising the
     movement name to the title's line dragged the waveform up with it. From the
     top, the movement name and the track selector sit on the title's line and
     the waveform simply extends further down, which is where it belongs. */
  align-items: flex-start !important;
  gap: 0.85rem !important;
}
/* The text in the row still reads as text on that line, not as something
   stuck to the top of a 50px box. */
#popular-works.ee-theatre #news-nr-audio-accordion .composition-audio-title {
  margin-top: 6px !important;
}
/* The selector centres on the movement name's line rather than on its own
   height. Its buttons are 22px against 16px of text, so left to size itself it
   set a 38px box and sat with the waveform instead of with the words it
   belongs to. Given the text's height, the buttons overflow it evenly and the
   whole cluster reads as part of that line. */
#popular-works.ee-theatre #news-nr-audio-accordion .new-release-audio-nav {
  /* No top margin: the movement name needs 6px to drop onto the title's line
     from the top of the row, and this is already there once it stops sizing
     itself to its buttons. */
  margin-top: 0 !important;
  height: 16px !important;
  align-items: center !important;
  overflow: visible !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .audio-movement-row {
  display: contents !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .composition-audio-title {
  order: 1;
  flex: 0 0 auto;
  font-size: 0.82rem !important;
  line-height: 1.2 !important;
  margin: 0 !important;
  white-space: nowrap;
}
#popular-works.ee-theatre #news-nr-audio-accordion .new-release-audio-container {
  order: 2;
  flex: 1 1 auto;
  min-width: 0;
  margin: 0 !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .new-release-audio-nav {
  order: 3;
  flex: 0 0 auto;
  min-height: 0 !important;
  padding: 0 !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .audio-nav-btn {
  width: 22px !important;
  height: 22px !important;
}

/* The movement arrows lose their plates too, for the reason the play control
   did: on the field these are marks, not hardware. They keep the catalogue's
   shape everywhere else. */
#popular-works.ee-theatre #news-nr-audio-accordion .audio-nav-btn {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  color: hsl(var(--field-accent, 221 39% 13%) / 0.85) !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .audio-nav-btn:hover:not(:disabled) {
  transform: none !important;
  opacity: 0.7;
}

/* No Show. Back leaves the state, so a second control that does the same thing
   is one more object standing on the picture. Watch still brings it up — the
   button is only redundant once you are in. */
#popular-works.ee-theatre .ee-th-toggle {
  display: none !important;
}
#popular-works.ee-theatre #news-nr-audio-accordion .ee-tp-stave {
  flex: 1 1 auto !important;
}

/* The rail keeps its colour. It was dimmed to 0.72 on the reasoning that
   anything not the score should recede, but the covers are the way to change
   what is playing from inside the state — the one thing here you might still
   want to do — and greying them made them look disabled rather than quiet. */
/* Says the field is the control, without drawing anything that says so. */
#popular-works.ee-theatre { cursor: pointer; }

/* ...and now something that does say so, and says it where you are pointing.
   A small ring on the cursor rather than a target in the middle of the field:
   the field answers a click anywhere, so a sign you have to aim at would be
   describing a control that does not exist. */
.ee-th-hint {
  position: absolute;
  left: 0;
  top: 0;
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
  z-index: 3;
  display: none;
  /* The mark alone. A ring with a fill behind it was a button following the
     cursor, which is the thing this is not — the field takes the click, and the
     sign only has to say which way it will go. */
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
  will-change: transform;
}
#popular-works.ee-theatre .ee-th-hint { display: block; }
#popular-works.ee-theatre.ee-th-hinting .ee-th-hint { opacity: 1; }
/* Drawn rather than set: a glyph carries a font's idea of a triangle and sits
   off-centre in a ring. */
.ee-th-hint::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent
    hsl(var(--field-accent, 221 39% 13%) / 0.78);
  transform: translate(-38%, -50%);
}
/* Playing: two bars, so the sign says what the press will do rather than what
   is happening. */
#popular-works.ee-theatre.ee-th-playing .ee-th-hint::before {
  width: 4px;
  height: 15px;
  border: 0;
  background: hsl(var(--field-accent, 221 39% 13%) / 0.78);
  box-shadow: 8px 0 0 hsl(var(--field-accent, 221 39% 13%) / 0.78);
  transform: translate(-90%, -50%);
}
@media (prefers-reduced-motion: reduce) {
  .ee-th-hint { transition: none; }
}

.ee-th-top {
  position: absolute;
  top: 20px;
  right: 22px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
/* The actions belong to the state, so they arrive with it. Out of flow rather
   than display:none so they can fade rather than appear. */
.ee-th-acts {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  opacity: 0;
  pointer-events: none;
  transform: translateX(6px);
  transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
}
#popular-works.ee-theatre .ee-th-acts {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(0);
}
.ee-th-btn {
  font: 800 0.7rem/1 system-ui, sans-serif;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  cursor: pointer;
  color: var(--ee-ink, hsl(221, 39%, 13%));
  background: #fff;
  border: 1px solid rgba(2, 6, 23, 0.28);
  box-shadow: 2px 2px 0 rgba(2, 6, 23, 0.16);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.ee-th-btn:hover { transform: translate(-1px, -1px); box-shadow: 3px 3px 0 rgba(2, 6, 23, 0.22); }
/* The one thing here that is a purchase keeps the house call-to-action. */
.ee-th-buy {
  background: hsl(221, 45%, 22%);
  color: #fff;
  border-color: hsl(221, 45%, 18%);
}
.ee-th-time {
  font: 800 0.72rem/1 system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--ee-ink, hsl(221, 39%, 13%));
  padding: 0 0.15rem;
}
.ee-th-sep { opacity: 0.4; padding: 0 0.25rem; }
.ee-th-dur { opacity: 0.62; }
.ee-th-vol { display: inline-flex; align-items: center; gap: 0.35rem; }
.ee-th-vol-i { font-size: 0.7rem; opacity: 0.65; width: 0.9em; text-align: center; }
.ee-th-vol input { width: 78px; accent-color: hsl(221, 45%, 22%); cursor: pointer; }

@media (prefers-reduced-motion: reduce) {
  .ee-th-acts, #news-new-release-content, .ee-th-toggle { transition: none; }
}


/* What is playing, top left, in the work's own colour — the one piece of type
   the state needs, where a title belongs on a page.

   The accent is a light, saturated colour meant for tinting a background, so it
   is taken down to a readable lightness rather than used as-is. Same operation
   the catalogue's audio headings use, and guarded the same way: without
   relative colour syntax it simply stays ink. */
.ee-th-title {
  position: absolute;
  /* Higher, and boxed to the height of the buttons beside it. Both were pinned
     to the same top, but a 21px line of text and a 45px button centre 12px
     apart when they start together — which is why the actions always sat low
     against the title however the two were positioned. Matching the box makes
     the centres match. */
  top: 20px;
  min-height: 44px;
  display: flex;
  align-items: center;
  left: 28px;
  z-index: 3;
  max-width: 46%;
  font: 900 1.15rem/1.15 system-ui, sans-serif;
  letter-spacing: -0.02em;
  color: var(--ee-ink, hsl(221, 39%, 13%));
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}
@supports (color: hsl(from white h s l)) {
  .ee-th-title { color: hsl(from hsl(var(--field-accent, 221 39% 13%)) h s 32%); }
}
#popular-works.ee-theatre .ee-th-title {
  opacity: 1;
  transform: none;
}

/* The transport control. Square, and it answers the pointer the way every other
   control on the site does — a 1px lift into a deeper cast. */
.ee-th-play {
  min-width: 2.1rem;
  font-size: 0.8rem;
  line-height: 1;
}
.ee-th-play:hover { background: var(--secondary-100, #f4efe2); }
.ee-th-btn:active { transform: translate(0, 0); box-shadow: 1px 1px 0 rgba(2, 6, 23, 0.2); }

@media (prefers-reduced-motion: reduce) {
  .ee-th-title { transition: none; }
}


/* The meta column stacks: duration where it earns a place, then the scoring,
   then the dedication under it. It was a flex row, which is right for a single
   line and wrong the moment there are two things to say. */
.composition-page .composition-meta-container {
  flex-direction: column !important;
  align-items: flex-end !important;
  gap: 0.3rem !important;
}
.composition-page .composition-meta-container .composition-dedication {
  margin: 0 !important;
  text-align: right !important;
}

/* The News tag was a pill: a --gray-300 rule around a --gray-50 fill at a 999px
   radius, which is the generic chip this design replaced everywhere else. It
   carries one short word and needs no container to do it — set as the small
   tracked stamp the site uses for labels, the same treatment as the year under
   the cover, it reads as a category rather than as a button nobody can press.

   Text only: the row's layout, the separator and the date are untouched. */
.composition-page .rn-chip {
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 0 !important;
  font-size: 0.66rem !important;
  font-weight: 800 !important;
  text-transform: uppercase !important;
  letter-spacing: 0.12em !important;
  color: var(--gray-600) !important;
}

/* The cover lifts the way the catalogue's does. It could not before: a 3px
   white ring and a soft 5px blurred shadow sat around it, and a ring that thick
   reads as a mount around the artwork rather than as the print itself — there
   was nothing for a lift to lift off. Ring and blur go, the radius comes down
   from 16px to the catalogue's 10px, and the hover is that one exactly: a
   single pixel of movement under a hard cast in the work's own colour.

   --work-accent is set per card on the catalogue and is not set on a work's own
   page, where --field-accent already holds the same value — there is only one
   work here for it to be about. */
.composition-page .composition-cover-media {
  border: 0 !important;
  border-radius: 10px !important;
  box-shadow: none !important;
  transition: transform 0.22s cubic-bezier(0.22, 0.61, 0.36, 1),
    box-shadow 0.22s cubic-bezier(0.22, 0.61, 0.36, 1) !important;
}
.composition-page .composition-cover-media:hover {
  transform: translate(-1px, -1px) !important;
  box-shadow: 10px 10px 0 hsl(var(--work-accent, var(--field-accent, 221 39% 13%)) / 0.42) !important;
}
/* The image keeps its own corners but never its own cast, as on the catalogue:
   two casts on nested boxes read as a double edge on the lift. */
.composition-page .composition-cover-media:hover .composition-cover,
.composition-page .composition-cover-media:hover img {
  transform: none !important;
  box-shadow: none !important;
}

/* ---- hovers on a work's own page --------------------------------------------
   The audio plate lifted on hover: media-styles.css gives every
   .composition-audio-player a --shadow-md and a --primary-300 edge when the
   pointer is over it. It is a plate holding a player, not a control — nothing
   happens if you click it — so answering the pointer promises something it
   cannot deliver. The controls inside it have their own hovers. */
.composition-page .composition-audio-player:hover {
  box-shadow: none !important;
  border-color: rgba(2, 6, 23, 0.35) !important;
}

/* The cover's hover is the catalogue's, which is the version this design
   settled on: a flat scrim and a label made of the image rather than dropped on
   top of it. This one had a 3px --primary-500 ring around the artwork and a
   light pill in the middle — the ring is from the palette the edition replaced,
   and a white plate on a cover reads as a page control that happened to land
   there. A dark fill with a white rule holds the same contrast over the bright
   third of a cover as over the dark third. */
.composition-page .composition-cover-overlay {
  background: rgba(2, 6, 23, 0.52) !important;
  border: 0 !important;
  box-shadow: none !important;
}
/* Three classes deep: .cover-overlay-pill.frosted-btn carries a white fill and
   an ink border with !important, which ties a two-class rule and wins on order. */
.composition-page .cover-overlay-pill,
.composition-page .cover-overlay-pill.frosted-btn {
  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;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  transition: transform 0.15s ease, background 0.15s ease !important;
}
/* Brightens in place, the same as the catalogue's two labels. Nothing moves —
   a label centred over artwork that shifts a pixel reads as a twitch. */
.composition-page .cover-overlay-pill.frosted-btn:hover,
.composition-page .cover-overlay-pill.frosted-btn:active {
  transform: none !important;
  background: rgba(2, 6, 23, 0.34) !important;
  border-color: #ffffff !important;
}
