/* MBK v1.2 — css/cuesheet.css
   v1.2 elevation pass over the v1 baseline. Engraved-score
   styling for the Cue Sheet (spec §4): hairline rules, tabular figures, Didot titles,
   one red accent (award marks / active filter / hover). Extends css/tokens.css and
   css/base.css — does not redefine them.

   v1.2: type scale/air raised a step, poster chips (any row with a poster, since the
   2026-07-09 ordering pass retired the First Desk group), the reused floating
   hover-preview plate (Ken-Burns settle), and [data-reveal]/[data-reveal-stagger]
   hooks consumed by js/motion.js (owned by the motion kit — this file does not
   define the reveal animation itself, only the elements it targets). Desktop-only
   hover mechanics are gated in js/cuesheet.js via matchMedia; this stylesheet mirrors
   that gate with (hover:hover) and (pointer:fine) plus a reduced-motion kill switch
   so nothing here can get stuck mid-transition on touch. */

.cuesheet {
  width: 100%;
  position: relative;
}

/* ---- filter chips ---- */

.cuesheet-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin-bottom: 32px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line-on-paper);
}

.room-dark .cuesheet-filters {
  border-bottom-color: var(--line-on-ink);
}

.cuesheet-chip-btn {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 2px 0 4px;
  font-family: var(--font-sans);
  font-size: var(--size-ui);
  font-weight: 400;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--grey-2);
  cursor: pointer;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

.room-dark .cuesheet-chip-btn {
  color: var(--ecru-dim);
}

/* ported from css/cuesheet-v2.css (item 2): chip hover now underlines with a hairline
   (not just a color shift) so the affordance reads even for readers who don't perceive
   the color change. */
.cuesheet-chip-btn:hover {
  color: var(--ink);
  border-bottom-color: var(--line-on-paper);
}

.room-dark .cuesheet-chip-btn:hover {
  color: var(--paper);
  border-bottom-color: var(--line-on-ink);
}

.cuesheet-chip-btn.is-active {
  color: var(--red);
  border-bottom-color: var(--red);
}

.cuesheet-chip-btn:active {
  opacity: 0.72;
}

/* ported from css/cuesheet-v2.css (item 2): the one deliberate red focus ring in the
   site-wide states pass — chips are a tab-stop-heavy control (6+ in a row) where a
   currentColor outline reads too quietly against the hairline underline above it. */
.cuesheet-chip-btn:focus-visible {
  outline: 1px solid var(--red);
  outline-offset: 4px;
}

/* ---- table shell ---- */

.cuesheet-table-wrap {
  overflow-x: auto;
  overflow-y: visible;
}

.cuesheet-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

/* v2 fix — the ROOT CAUSE of the role column getting pushed off-canvas:
   .cuesheet-row overrides <tr> to display:grid, which takes those rows out of
   the table's own column-layout algorithm entirely — they're sized purely by
   grid-template-columns. The old markup, though, rendered the "Songs —
   Licensed" divider and the 26-item "Also Heard On" title cloud as
   <tbody><tr><th colspan="6"> rows INSIDE that same <table>. Under the
   default table-layout:auto, a colspanning cell contributes its MAX-CONTENT
   width — the width it would need if nothing wrapped — to the table's
   required width, and 26 nowrap title spans summed to roughly 3200px. That
   forced the WHOLE table (and every .cuesheet-row grid inside it, since
   grid-template-columns fills 100% of the table) out to ~3200px, pushing
   every row's role/mark/poster columns thousands of pixels past any real
   viewport's right edge. CSS-only mitigations (blockifying the cell's
   display, the width:0/min-width:100% "don't drive table width" hack) proved
   unreliable against Chrome's colspan handling during the table's initial
   layout pass; table-layout:fixed on the whole table was also tried and
   rejected — it also strips the grid rows' ability to read the table's
   resolved width, collapsing the 1fr title column to 0, worse than the bug
   it fixed. The actual fix lives in js/cuesheet.js: the divider/cloud were
   never really tabular data, so renderTable() now renders them as plain
   sibling <div>s in tableWrap (not <th> inside a <table>), and the licensed
   rows get their own separate <table> — so there is no longer any oversized
   colspan cell for table-layout:auto to measure against in the first place.
   The rules below target those <div>s directly. */
.cuesheet-group-header {
  display: block;
  padding: 44px 4px 14px;
}

/* no scored table above it (e.g. the SONGS filter chip, which shows the
   licensed lane only) — don't add the "coming after a table" gap. */
.cuesheet-table-wrap > .cuesheet-group-header:first-child {
  padding-top: 0;
}

/* "The Songs — Licensed" divider — eyebrow + a quiet sublabel stacked underneath,
   marking the scored/licensed register shift (KOVAS correction, post-v1.2). */
.cuesheet-group-header--songs {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.cuesheet-group-sublabel {
  display: block;
}

/* "Also Heard On" ASCAP title cloud — quiet, wide-tracked, wraps freely (not a
   marquee, not rows/links). Mirrors the homepage platform marquee's item/sep span
   shape (css/home.css .marquee-item / .marquee-sep) at rest, without the scroll. */

.cuesheet-cloud {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--size-small);
  font-weight: 300;
  letter-spacing: var(--track-wide);
  line-height: 2;
  color: var(--grey-2);
}

.cuesheet-cloud-item {
  white-space: nowrap;
}

.cuesheet-cloud-sep {
  color: var(--grey-1);
  margin: 0 8px;
}

.cuesheet-cloud-line {
  display: block;
  margin-top: 12px;
}

/* ---- rows ---- */

/* v2 fix (role can vanish/get pushed off-canvas): the v1 grid used hard pixel
   widths (44+64+200+160+96 = 564px fixed, before the gaps and the title
   column even claim space). Below roughly 1050px that total no longer fits
   the container, so the row silently overflows the scrollable
   .cuesheet-table-wrap and the role/platform/mark columns sit off to the
   right, unreachable without a horizontal scroll a visitor never thinks to
   try — reading as "the role dropped." Switching platform/role/mark to
   minmax() lets them shrink with the viewport instead of forcing overflow,
   and the min-width:0 on .cuesheet-cell stops a long single-word value from
   blowing out its track (grid's default min-width:auto). */
.cuesheet-row {
  display: grid;
  grid-template-columns: 36px 52px minmax(0, 1fr) minmax(84px, 160px) minmax(92px, 160px) 84px;
  column-gap: 18px;
  align-items: baseline;
  border-bottom: 1px solid var(--line-on-paper);
  transition: color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.room-dark .cuesheet-row {
  border-bottom-color: var(--line-on-ink);
}

/* row hover tint — ported from css/cuesheet-v2.css (item 2): a faint red-tinted wash
   behind the whole row, on top of the existing text-color shift, so the hover target
   reads as the full row (not just wherever the cursor happens to sit on the text). */
.cuesheet-row:hover {
  color: var(--red);
  background-color: rgba(235, 28, 36, 0.03);
}

.room-dark .cuesheet-row:hover {
  background-color: rgba(245, 241, 228, 0.03);
}

.cuesheet-row:hover .cuesheet-title-link {
  color: var(--red);
}

.cuesheet-cell {
  display: block;
  padding: 21px 0;
  line-height: 1.5;
  min-width: 0;
}

.cuesheet-num {
  color: var(--grey-1);
  font-size: var(--size-eyebrow);
  letter-spacing: 0.06em;
}

.cuesheet-year {
  color: var(--grey-2);
  font-size: var(--size-small);
}

.room-dark .cuesheet-year {
  color: var(--ecru-dim);
}

.cuesheet-title-wrap {
  display: flex;
  align-items: center;
  gap: 14px;
}

.cuesheet-title-link {
  color: inherit;
  font-size: clamp(1.15rem, 1.3vw + 0.6rem, 1.34rem);
  line-height: 1.3;
}

.cuesheet-title-link:hover {
  color: var(--red);
}

.cuesheet-title-link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

.cuesheet-title-link:active {
  opacity: 0.72;
}

.cuesheet-platform,
.cuesheet-role {
  font-size: var(--size-small);
  color: var(--grey-2);
  letter-spacing: 0.01em;
}

.room-dark .cuesheet-platform,
.room-dark .cuesheet-role {
  color: var(--ecru-dim);
}

.cuesheet-mark {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  text-align: right;
}

.cuesheet-award {
  font-size: 0.9rem;
  cursor: default;
}

.cuesheet-case-link {
  font-family: var(--font-sans);
  font-size: var(--size-ui);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--grey-2);
  white-space: nowrap;
}

.room-dark .cuesheet-case-link {
  color: var(--ecru-dim);
}

.cuesheet-row--case .cuesheet-title-link {
  text-decoration: underline;
  text-decoration-color: var(--line-on-paper);
  text-underline-offset: 4px;
}

.cuesheet-case-link:hover {
  color: var(--red);
}

.cuesheet-case-link:focus-visible,
.cuesheet-official-link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

.cuesheet-case-link:active,
.cuesheet-official-link:active {
  opacity: 0.72;
}

/* quiet external link (row's end) — renders only when the row carries an
   `official` URL (data/projects.js). Same eyebrow treatment as the case-study
   link, just the arrow glyph instead of a text label. */
.cuesheet-official-link {
  font-size: var(--size-eyebrow);
  color: var(--grey-2);
}

.room-dark .cuesheet-official-link {
  color: var(--ecru-dim);
}

.cuesheet-official-link:hover {
  color: var(--red);
}

.cuesheet-empty {
  padding: 24px 4px;
}

/* ---- inline poster chip (any row with a poster) ---- */

.cuesheet-poster-chip {
  display: block;
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  overflow: hidden;
  border: 1px solid var(--line-on-paper);
  box-shadow: 0 2px 6px rgba(10, 10, 10, 0.08);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* ported from css/cuesheet-v2.css (item 2): poster chip picks up the red border +
   deeper shadow and a slow Ken-Burns settle on its image when the row is hovered. */
.cuesheet-row:hover .cuesheet-poster-chip {
  border-color: var(--red);
  box-shadow: 0 4px 12px rgba(10, 10, 10, 0.14);
}

.room-dark .cuesheet-poster-chip {
  border-color: var(--line-on-ink);
}

.room-dark .cuesheet-row:hover .cuesheet-poster-chip {
  border-color: var(--red);
}

.cuesheet-poster-chip img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s var(--ease);
}

.cuesheet-row:hover .cuesheet-poster-chip img {
  transform: scale(1.06);
}

/* ---- shared floating hover-preview plate (desktop only; built + gated in js) ---- */

.cuesheet-preview {
  position: fixed;
  top: 0;
  right: 40px;
  width: 220px;
  aspect-ratio: 3 / 4;
  z-index: 60;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s var(--ease), visibility 0s linear 0.3s;
}

.cuesheet-preview.is-visible {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s var(--ease), visibility 0s linear 0s;
}

/* .kb-preview (css/motion.css) supplies position:relative/overflow:hidden/display:block
   on this frame, plus width/height/object-fit and the opacity+transform transition on
   its <img> descendant, activated by the .is-active class js/cuesheet.js toggles. This
   rule only adds the plate's chrome (ground, hairline, drop shadow) — nothing here
   duplicates motion.css's sizing or transition declarations. */
.cuesheet-preview-frame {
  width: 100%;
  height: 100%;
  background: var(--ink);
  border: 1px solid var(--line-on-paper);
  box-shadow: 0 28px 56px rgba(10, 10, 10, 0.32);
}

.room-dark .cuesheet-preview-frame {
  border-color: var(--line-on-ink);
}

/* belt-and-suspenders: hover mechanics fully off-screen on touch/coarse pointers
   even if a future edit forgets the JS-side matchMedia gate. */
@media (hover: none), (pointer: coarse) {
  .cuesheet-preview {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cuesheet-preview {
    display: none;
  }
}

/* ---- responsive: tablet (641-1024px) — same 6-column grid, tighter tracks
   so the role/platform columns keep real estate instead of forcing the
   table into horizontal scroll (see the minmax() note above .cuesheet-row). ---- */

@media (max-width: 1024px) {
  .cuesheet-row {
    grid-template-columns: 32px 48px minmax(0, 1fr) minmax(72px, 120px) minmax(84px, 128px) 72px;
    column-gap: 14px;
  }

  .cuesheet-title-link {
    font-size: clamp(1.05rem, 1.6vw + 0.5rem, 1.24rem);
  }
}

/* ---- responsive: two-line rows under 640px (title / platform+year / role) ----
   v2 fix: role previously shared its grid column with year in a 2-row layout
   with no min-width guard — a long credit ("Additional Music — 30 for 30")
   was squeezed by whatever width the short year needed, and could render
   clipped against the mark column. Role now gets its own full-width row
   beneath platform/year, so it always has the whole row to wrap into and can
   never be squeezed out. */

@media (max-width: 640px) {
  .cuesheet-row {
    grid-template-columns: 26px 1fr auto auto;
    grid-template-areas:
      "num title    title mark"
      "num platform year  mark"
      "num role     role  mark";
    row-gap: 6px;
    padding: 18px 0;
    align-items: baseline;
  }

  .cuesheet-cell {
    padding: 0;
    min-width: 0;
  }

  .cuesheet-num { grid-area: num; align-self: start; }
  .cuesheet-title { grid-area: title; }
  .cuesheet-platform { grid-area: platform; }
  .cuesheet-year { grid-area: year; padding-left: 16px; text-align: right; }
  .cuesheet-role {
    grid-area: role;
    padding-top: 2px;
    text-align: left;
    white-space: normal;
    overflow-wrap: break-word;
  }
  .cuesheet-mark { grid-area: mark; align-self: start; }

  .cuesheet-title-wrap {
    gap: 10px;
  }

  .cuesheet-poster-chip {
    width: 40px;
    height: 40px;
  }

  .cuesheet-title-link {
    font-size: 1.05rem;
  }

  .cuesheet-mark {
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
  }
}

/* ---- mobile-only quick-scan strip (item 5 — ported from css/cuesheet-v2.css,
   js/cuesheet.js renderCueHighlights) ----
   Hidden entirely above 640px; a plain user-scrolled row (no autoplay — the
   contract bars that), scroll-snapped so a swipe settles on a full card. */
.cuesheet-mobile-highlights {
  display: none;
}

@media (max-width: 640px) {
  .cuesheet-mobile-highlights {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scroll-padding-inline: 4px;
    padding: 4px 4px 16px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--line-on-paper);
  }

  .cuesheet-mobile-highlights::-webkit-scrollbar {
    display: none;
  }

  .cue-highlight {
    scroll-snap-align: start;
    flex: 0 0 auto;
    width: 128px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    color: inherit;
  }

  .cue-highlight-poster {
    display: block;
    width: 128px;
    height: 96px;
    overflow: hidden;
    border: 1px solid var(--line-on-paper);
  }

  .cue-highlight-poster img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  .cue-highlight-title {
    font-size: 0.95rem;
    line-height: 1.25;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .cue-highlight-meta {
    font-size: var(--size-eyebrow);
    letter-spacing: 0.02em;
    color: var(--grey-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* item 2: cue-highlight cards are links on rows with a case study/page — give them
   the same currentColor focus-visible ring as the rest of the sheet's interactive
   surfaces (kept inside the same 640px block since the strip itself only renders there). */
@media (max-width: 640px) {
  a.cue-highlight:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 3px;
  }

  a.cue-highlight:active {
    opacity: 0.72;
  }
}

/* ============================================================================
   QA FIXES (2026-07-09 red-team pass) — touch targets + mobile length
   ============================================================================ */

/* #4 Touch targets: filter chips get a 44px minimum hit area at every width,
   and the official ↗ link gets real padding so it isn't an 11px pinprick. */
.cuesheet-chip-btn {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.cuesheet-official-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}

@media (max-width: 640px) {
  /* title links become a full-height tap row */
  .cuesheet-title-link {
    display: inline-block;
    min-height: 44px;
    padding-block: 8px;
  }

  /* #5 Mobile length: the full 43-row sheet + licensed cloud is ~7,000px on a phone
     and duplicates the Museum. On mobile the quick-scan highlights strip carries the
     proof; the full archive lives in the Museum. Hide the full table here and route
     deep browsing to the Museum via the CTA that renderCueHighlights appends. */
  .cuesheet-table-wrap { display: none; }
  .cuesheet-filters { display: none; }
}

/* the mobile "browse all in the Museum" CTA (appended after the highlights strip by
   renderCueHighlights; only visible where the strip is, i.e. ≤640px) */
.cuesheet-museum-cta {
  display: none;
}
@media (max-width: 640px) {
  .cuesheet-museum-cta {
    display: inline-block;
    margin-top: 20px;
    font-size: var(--size-ui);
    letter-spacing: var(--track-wide);
    text-transform: uppercase;
    color: var(--ink);
    border-bottom: 1px solid var(--red);
    padding: 10px 0;
    min-height: 44px;
  }
  .cuesheet-museum-cta:hover { color: var(--red); }
}
