/* ===== 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 .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"); }

/* 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. */
#popular-works,
#popular-works::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 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 {
  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 {
    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 {
    background-color: oklch(
      from color-mix(in oklab, hsl(var(--field-accent, 40 20% 50%)) 32%, #f4efe2) 0.952 c h
    ) !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-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. */
  isolation: isolate;
}

/* 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;
}

/* 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 1.2s ease;
}
.ee-field-score.is-shown {
  opacity: 1;
}

/* ---- 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. */
.composition-top-frame .ee-field-staff,
.composition-top-frame .ee-field-notes,
/* Same intent, new element: the staves and notes are one canvas now. */
.composition-top-frame .ee-field-score {
  display: none !important;
}

/* ---- 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;
}
