/* ===== 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;
  transition: background-color 0.55s ease;
}

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

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

/* ---- manuscript ----------------------------------------------------------
   Five ruled lines and a rest, tiled: the paper the catalogue is printed on.

   Bigger than the first attempt and completely still. At a 96px tile the band
   showed seven systems, which read as ruled notepaper — the exact thing a staff
   was rejected for the first time. The band is 900px tall, so the tile has to
   be 230px to show under four: measure it against the field height rather than
   picking a number that looks right in isolation.

   Nothing here moves. The staff drifted downward before, and a page of music
   that slides is a page falling off a stand. */
.ee-field-staff {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    to bottom,
    var(--staff-ink) 0 1.5px, transparent 1.5px 26px,
    var(--staff-ink) 26px 27.5px, transparent 27.5px 52px,
    var(--staff-ink) 52px 53.5px, transparent 53.5px 78px,
    var(--staff-ink) 78px 79.5px, transparent 79.5px 104px,
    var(--staff-ink) 104px 105.5px, transparent 105.5px 230px
  );
  background-size: 100% 230px;
  --staff-ink: hsl(var(--field-accent, 40 20% 50%) / 0.16);
  opacity: 0;
  transition: opacity 1.2s ease;
}
.ee-field-staff.is-shown {
  opacity: 1;
}

/* ---- the notes -----------------------------------------------------------
   What actually moves. Note heads crossing the field left to right, hopping
   between the lines as they go — the one thing on a staff that is supposed to
   travel, doing what it is for.

   Two nested elements because each carries its own axis: the outer runs X at a
   constant rate, the inner hops Y on its own clock. One element cannot do both
   — they would be two animations competing for `transform` and the last one
   declared would simply win. Split, each stays a compositor transform.

   Horizontal, and only horizontal. Lines running the same direction as the
   travel are what makes the movement legible: the note crosses them, so there
   is something to measure it against. */
.ee-field-notes {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.ee-note {
  position: absolute;
  left: 0;
  will-change: transform;
  animation: ee-note-run linear infinite;
}
.ee-note > i {
  display: block;
  /* Sized to the staff it sits on: a note head fills the space between two
     lines, so it scales with them. */
  width: 20px;
  height: 14px;
  border-radius: 50%;
  /* The tilt is the whole difference between a note head and a dot. */
  transform: rotate(-21deg);
  background: hsl(var(--field-accent, 40 20% 50%) / 0.55);
  animation: ee-note-hop ease-in-out infinite;
}
/* Beyond both edges so a note is never seen arriving or leaving. */
@keyframes ee-note-run {
  from { transform: translate3d(-8vw, 0, 0); }
  to   { transform: translate3d(108vw, 0, 0); }
}
/* Held, then moved: the pauses are what make it read as hopping from line to
   line rather than sliding up and down a ramp. 26px is one line spacing, so
   every landing is on a line or in a space, never between them. */
@keyframes ee-note-hop {
  0%, 14%   { transform: translateY(0); }
  22%, 36%  { transform: translateY(-26px); }
  44%, 58%  { transform: translateY(26px); }
  66%, 80%  { transform: translateY(-52px); }
  88%, 100% { transform: translateY(0); }
}

/* ---- 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;
  width: 200%;
  opacity: 0;
  transition: opacity 0.8s ease;
  will-change: transform;
  transform: translate3d(calc(var(--wave-progress, 0) * -50%), 0, 0);
}
.ee-field-wave.is-shown {
  opacity: 0.14;
}
.ee-field-wave svg {
  width: 100%;
  height: 100%;
  display: block;
}
.ee-field-wave path {
  fill: hsl(var(--field-accent, 40 20% 50%));
}

/* 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,
.ee-field-stage.is-paused .ee-note > i {
  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-notes { display: none; }
  .ee-field-wave { transition: none; }
  #popular-works { 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; }
}
