/*
  Wu-Tang Clan Timeline stylesheet.

  History: the original ~3500-line stylesheet duplicated a ~30-line CSS
  block per album via unique #ids instead of using the per-member classes
  already sitting in the HTML (left completely empty). Rewritten to define
  each member's look once, as a class, reused via data.js + app.js which
  now build the whole page instead of it being hand-authored markup.
*/

:root {
  --bg: #0b0b0d;
  --panel: #17171a;
  --panel-raised: #1e1e22;
  --border: #2a2a2e;
  --text: #e8e8ea;
  --text-dim: #9a9aa0;
  --cover-size: 110px;

  /* one accent colour per member, reused everywhere via class name
     instead of being redeclared per-album */
  --c-wutang: #d4af37;
  --c-methodman: #ff8c42;
  --c-ghostface: #e63946;
  --c-raekwon: #2a9d8f;
  --c-ugod: #f4d35e;
  --c-rza: #457b9d;
  --c-gza: #52b788;
  --c-mastaKilla: #9b5de5;
  --c-oldirty: #f15bb5;
  --c-cappadonna: #48cae4;
  --c-inspectahdeck: #90be6d;
}

* {
  box-sizing: border-box;
}

html {
  font-size: 16px;
}

body {
  margin: 0;
  padding: 32px 24px 64px;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  line-height: 1.5;
}

/* left-aligned, not centred -- max-width alone (no margin:auto) just
   keeps the line length readable without pulling it into the middle
   of the page */
#info {
  max-width: 640px;
  margin: 0 0 28px;
  text-align: left;
  font-size: 0.95rem;
  color: var(--text-dim);
}

#info h1 {
  margin: 0 0 10px;
  font-size: 1.8rem;
  letter-spacing: 0.02em;
  color: var(--text);
}

#info p {
  margin: 0 0 8px;
}

#info .hint {
  font-size: 0.82rem;
  color: #6c6c72;
}

a:link,
a:visited {
  color: inherit;
  text-decoration: none;
}

/* member key row: a real flex row with a real, even gap */
#timeline_key,
#timeline_key_affiliates {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-width: 1400px;
  margin: 0 0 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
}

.key_section_heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: 1400px;
  margin: 0 0 10px;
}
.key_section_label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-dim);
}
.key_section_heading_affiliates {
  margin-top: 4px;
}

/* the toggle is a real checkbox for accessibility/keyboard support,
   visually rebuilt as a small pill switch */
#affiliate_toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--text-dim);
  user-select: none;
}
#affiliate_toggle_input {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
  flex: 0 0 auto;
}
#affiliate_toggle_input::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--text-dim);
  transition: transform 150ms ease, background 150ms ease;
}
#affiliate_toggle_input:checked {
  background: rgba(90, 140, 255, 0.25);
  border-color: #5a8cff;
}
#affiliate_toggle_input:checked::before {
  transform: translateX(14px);
  background: #5a8cff;
}
#affiliate_toggle_input:focus-visible {
  outline: 2px solid #5a8cff;
  outline-offset: 2px;
}

/* affiliate portraits get a slightly dimmer/smaller treatment so the
   two rows read as distinct groups, not one undifferentiated row */
#timeline_key_affiliates .tooltip {
  --cover-size-affiliate: calc(var(--cover-size) * 0.82);
  width: var(--cover-size-affiliate);
  height: var(--cover-size-affiliate);
}

/* Toggling affiliate visibility is a two-phase animation, not a single
   class flip -- `display: none` can't be transitioned at all, so a naive
   version of this just pops elements out of existence with no animation.
   app.js instead: (1) adds .is-affiliate-fading, which this rule
   transitions to opacity 0 + a slight scale-down; (2) once that
   transition finishes, adds .is-affiliate-collapsed (display: none) so
   the grid actually reflows to fill the gap, and removes -fading. The
   reverse happens in opposite order on toggle-on.

   IMPORTANT: the .key_section_heading_affiliates element (which contains
   the toggle switch itself) is deliberately NEVER included in this list.
   An earlier version hid the whole heading along with the portraits row,
   which hid the toggle's own "turn it back on" control the moment you
   used it -- see affiliateAnimatedElements() in app.js. Only the
   portraits row and the grid tiles animate; the heading + toggle always
   stay visible and clickable. */
.tooltip.is-affiliate-release,
#timeline_key_affiliates {
  transition: opacity 220ms ease, transform 220ms ease;
}
.is-affiliate-fading.tooltip.is-affiliate-release {
  opacity: 0;
  transform: scale(0.85);
  pointer-events: none;
}
#timeline_key_affiliates.is-affiliate-fading {
  opacity: 0;
  pointer-events: none;
}
.is-affiliate-collapsed.tooltip.is-affiliate-release,
#timeline_key_affiliates.is-affiliate-collapsed {
  display: none;
}

/* release grid: CSS Grid instead of inline-block flow. inline-block's
   gaps depend on whitespace between tags in the markup, which is why
   they looked uneven before -- grid's `gap` is exact regardless of
   markup whitespace, and it was free to use here once #info and
   #timeline_key stopped being flat siblings mixed in with the covers */
#container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--cover-size), 1fr));
  gap: 8px;
  max-width: 1400px;
}

.tooltip {
  --accent: var(--text-dim);
  position: relative;
  width: var(--cover-size);
  height: var(--cover-size);
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow: hidden;
  background: var(--panel);
  cursor: pointer;
  transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease, opacity 160ms ease;
  /* tiles have a fixed size, so the browser can safely skip ALL rendering
     work (style/layout/paint of the img + its grayscale filter raster)
     for the rows currently scrolled off-screen -- on a 145-tile grid
     that's most of them at any given time */
  content-visibility: auto;
}

.tooltip img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(100%);
  transition: filter 300ms ease;
  pointer-events: none;
}

.tooltip:hover img,
.tooltip:focus-visible img,
.tooltip.is-highlighted img {
  filter: grayscale(0%) saturate(1.15);
}

/* Direct mouse/keyboard interaction on a single tile: the fuller box-shadow
   "lift" effect. This is only ever applied to one element at a time, so its
   cost is negligible. */
.tooltip:hover,
.tooltip:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent), 0 10px 24px rgba(0, 0, 0, 0.55);
  transform: translateY(-2px);
  z-index: 2;
}

/* Batch highlight from hovering a KEY PORTRAIT can mark up to a few dozen
   grid tiles .is-highlighted at once. It deliberately does NOT share the
   box-shadow/transform rule above: animating a blurred box-shadow (which
   can't be handled by the compositor and forces a full repaint) across
   that many elements simultaneously was measured to cost 900ms+ of
   Commit/RasterTask time per hover in Chrome's own tracing -- a real,
   feelable stutter, not a hypothetical one. border-color and opacity are
   both compositor-only properties, so this stays cheap regardless of how
   many releases a member has. */
.tooltip.is-highlighted {
  border-color: var(--accent);
  z-index: 1;
}

/* Same reasoning as the box-shadow rule above, but for the imgs' 300ms
   grayscale `filter` transition: filter transitions repaint the image
   every frame, which is fine for the ONE directly-hovered tile but not
   for the few-dozen tiles a key-portrait hover colorizes at once --
   that's ~18 consecutive frames of repainting dozens of images, twice
   per rollover (in and out). Batch-highlighted tiles colorize instantly
   instead (arguably crisper for "trace the catalogue" anyway); the
   single-tile :hover keeps its animation. The .no-filter-anim helper is
   added by app.js for one frame around batch UN-highlighting, when
   .is-highlighted is already gone and the base 300ms rule would
   otherwise animate everything back to grayscale. */
.tooltip.is-highlighted img,
#container.no-filter-anim .tooltip img {
  transition: none;
}

.tooltip:focus-visible {
  outline: none;
}

/* while a member is being hovered in the key, dim everything that
   ISN'T theirs so the highlighted releases actually stand out. Opacity
   only -- no filter here, since every non-highlighted tile already sits
   at its default grayscale(100%) (see .tooltip img above) and re-stating
   an unchanged filter value buys nothing but extra style recalc work. */
#container.is-filtering .tooltip:not(.is-highlighted) {
  opacity: 0.28;
}

/* per-member accent colours -- declared once, applied by class. A
   collaboration release carries every one of its members' classes at
   once (e.g. "inspectahdeck ghostface"), so hovering ANY of them
   highlights it; the accent colour used is whichever class is declared
   later here (deterministic, just a simplification for multi-member
   releases rather than trying to blend colours). */
.wutang        { --accent: var(--c-wutang); }
.methodman     { --accent: var(--c-methodman); }
.ghostface     { --accent: var(--c-ghostface); }
.raekwon       { --accent: var(--c-raekwon); }
.ugod          { --accent: var(--c-ugod); }
.rza           { --accent: var(--c-rza); }
.gza           { --accent: var(--c-gza); }
.mastaKilla    { --accent: var(--c-mastaKilla); }
.oldirty       { --accent: var(--c-oldirty); }
.cappadonna    { --accent: var(--c-cappadonna); }
.inspectahdeck { --accent: var(--c-inspectahdeck); }

/* A pinned (clicked-to-select) key portrait keeps a persistent ring in the
   member's accent colour even after the mouse leaves, so it's always clear
   which member's works are currently highlighted in the grid. Hovering
   another portrait previews that one (see app.js) but the selected ring
   stays put until you click it off. The ring uses box-shadow only (no
   blurred lift) so it stays cheap even with the smaller affiliate
   portraits; it intentionally overrides the single-tile :hover box-shadow
   because the persistent-selector signal matters more than the hover lift. */
#timeline_key .tooltip.is-selected,
#timeline_key_affiliates .tooltip.is-selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent), 0 0 10px 1px var(--accent);
}
#timeline_key_affiliates .tooltip.is-selected {
  box-shadow: 0 0 0 2px var(--accent), 0 0 8px 1px var(--accent);
}

/* vanilla tooltip bubble (tooltip.js) -- replaces jQuery + Tooltipster */
.uxl-tooltip {
  position: absolute;
  z-index: 600;
  max-width: 260px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 0.8rem;
  line-height: 1.35;
  padding: 6px 10px;
  border-radius: 4px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
  white-space: pre-line;
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 120ms ease, transform 120ms ease;
}
.uxl-tooltip.is-flipped {
  transform: translateY(-4px);
}
.uxl-tooltip.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- 3D CD viewer ---------- */

/* closed state is `visibility: hidden`, not just opacity 0: an opacity-0
   fixed overlay still lives in the render tree, so the compositor kept
   paying for a full-viewport layer with a backdrop-filter blur plus the
   panel's 60px box-shadow on EVERY frame of every visit, viewer open or
   not. visibility:hidden removes it from rendering (and hit-testing)
   entirely while closed. The 0s visibility transition is DELAYED by the
   fade duration on the way out so the close fade still shows, and
   un-delayed by the .is-open rule so opening is instant. */
#cd-viewer {
  position: fixed;
  inset: 0;
  z-index: 500;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 220ms ease, visibility 0s linear 220ms;
}
#cd-viewer.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 220ms ease;
}

#cd-viewer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(2px);
}

#cd-viewer-panel {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: min(560px, 100vw);
  background: var(--panel-raised);
  border-left: 1px solid var(--border);
  box-shadow: -20px 0 60px rgba(0, 0, 0, 0.6);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
#cd-viewer.is-open #cd-viewer-panel {
  transform: translateX(0);
}

#cd-viewer-close {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  width: 34px;
  height: 34px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.4);
  color: var(--text);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}
#cd-viewer-close:hover {
  border-color: var(--text-dim);
}

#cd-canvas-holder {
  flex: 0 0 300px;
  min-height: 0;
}
#cd-canvas-holder canvas {
  display: block;
}

/* the 3D disc gets a fixed-height slot; everything else (metadata,
   descriptors, tracklist, credits) scrolls independently below it,
   since a fully-catalogued release has a lot more content than just
   year/title ever did */
#cd-info {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 18px 28px 28px;
  border-top: 1px solid var(--border);
}
#cd-info-year {
  font-size: 0.8rem;
  color: var(--text-dim);
  letter-spacing: 0.06em;
  margin-bottom: 4px;
}
#cd-info-title {
  font-size: 1.15rem;
  font-weight: 600;
}
#cd-info-hint {
  margin-top: 10px;
  font-size: 0.75rem;
  color: #6c6c72;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

#cd-info-links {
  display: flex;
  gap: 8px;
  margin-top: 18px;
}
.cd-link {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  border: 1px solid var(--border);
  color: var(--text);
  transition: border-color 150ms ease, background 150ms ease;
}
.cd-link:hover {
  background: rgba(255, 255, 255, 0.06);
}
.cd-link-spotify:hover { border-color: #1db954; }
.cd-link-apple:hover { border-color: #fa243c; }

#cd-info-meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 14px;
  margin: 18px 0 0;
  font-size: 0.82rem;
}
#cd-info-meta dt {
  color: var(--text-dim);
}
#cd-info-meta dd {
  margin: 0;
  color: var(--text);
}

#cd-info-descriptors {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 16px;
}
.cd-descriptor {
  font-size: 0.72rem;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
  color: var(--text-dim);
  text-transform: lowercase;
}

#cd-info-summary {
  margin: 18px 0 0;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--text);
}
#cd-info-summary:empty {
  display: none;
}

#cd-info-tracklist-wrap,
#cd-info-credits-wrap {
  margin-top: 18px;
  border-top: 1px solid var(--border);
  padding-top: 14px;
}
#cd-info-tracklist-wrap summary,
#cd-info-credits-wrap summary {
  cursor: pointer;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
#cd-info-tracklist {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  counter-reset: track;
}
#cd-info-tracklist li {
  counter-increment: track;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  font-size: 0.83rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
#cd-info-tracklist li::before {
  content: counter(track) ". ";
  color: var(--text-dim);
  margin-right: 2px;
}
.cd-track-title {
  flex: 1 1 auto;
}
.cd-track-duration {
  flex: 0 0 auto;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
#cd-info-credits {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  font-size: 0.83rem;
  color: var(--text-dim);
}
#cd-info-credits li {
  padding: 4px 0;
}

#cd-info-empty {
  margin-top: 18px;
  font-size: 0.8rem;
  font-style: italic;
  color: #6c6c72;
}

@media (max-width: 640px) {
  :root {
    --cover-size: 84px;
  }
  body {
    padding: 20px 12px 48px;
  }
  #cd-viewer-panel {
    width: 100vw;
  }
}
