/* The whole page is black (user's own request, so the wall — already its own dark box — blends
   into the page instead of sitting in a contrasting white frame). Nav bar is deliberately pinned
   back to the sitewide white/dark-text look regardless — same override, same reasoning, as the
   lyrics-detail template's own dark pages already use (see .lyrics-page .site-nav): the nav has
   no background of its own, so without this it would just show through whatever colour body is,
   and .site-nav__brand has no colour of its own either, so it would inherit body's white text
   and vanish against its own now-white-forced bar. */
body[data-page="videos"] {
  background: #000;
  color: #fff;
}

/* The sitewide h1 rule sets its own explicit grey, which otherwise beats this page's inherited
   white (body's own color: #fff above is a lower-specificity fallback that a plain-element h1
   selector already overrides everywhere else) — needs its own explicit override here too. */
body[data-page="videos"] h1 {
  color: #fff;
}

body[data-page="videos"] .site-nav {
  background: var(--color-bg);
  color: var(--color-text);
}

/* Layout: wall (flexible) + a fixed-width credits list on the right, side by side. Both share
   one explicit height (var(--videos-wall-h)) rather than growing with content — the wall
   specifically needs a bounded height for its 3D perspective box to make sense (an unbounded
   height would mean an unbounded number of tiles needed to fill it), and matching the list to
   the same height (with its own internal scroll) keeps the two visually paired as one unit
   instead of the shorter one trailing off into empty space beside a much taller sibling. */
.videos-page__layout {
  display: flex;
  gap: var(--space-5);
  /* Was min(78vh, 760px) — a flat vh percentage against this page's other, roughly constant chrome
     (nav + title + main's padding, ~255px) undershoots on shorter viewports the same way Home's
     original gallery-height vh formula did: at a 13" MacBook-class ~700px viewport, 78vh (546px)
     left the page ~100px taller than the viewport, forcing a scroll. calc(100vh - 255px) instead
     of an approximate percentage fits any viewport height exactly (255px = nav ~112 + main's top
     padding 24 + this h1's own height ~79 + its sitewide margin-bottom 16 + main's bottom padding
     24); 360px/760px keep the same sane floor/ceiling this already had. Both the wall and its
     paired credits list (.videos-page__list-wrap, same height by design — see comment above) share
     this, so both stay in sync however it resolves. */
  height: clamp(360px, calc(100vh - 255px), 760px);
}

/* This page's own content (the wall + credits list) is built by js/videos.js only after its own
   fetch('/data/music-videos.json') resolves — a separate, later gate than the sitewide
   [data-include]/main one in css/base.css, which only waits on the nav partial and would
   otherwise reveal an empty black box here for a beat before the wall/list actually populate.
   Same dual "plain opacity property + animation" shape as that sitewide gate, for the same
   reduced-motion reason: the animation gets disabled by the sitewide `!important` rule, and
   without the plain property here that would leave this stuck at opacity:0 forever instead of
   just skipping the fade. */
.videos-page__layout {
  opacity: 0;
}

.videos-page__layout.is-loaded {
  opacity: 1;
  animation: page-fade-in 0.5s ease;
}

/* Wrapper exists only so the fade-at-bottom scroll cue (below) can be positioned against a fixed
   box rather than the scrolling element itself — a child of .videos-page__list would just scroll
   away with everything else instead of staying put as a "there's more below" hint. */
.videos-page__list-wrap {
  position: relative;
  flex: 0 0 320px;
  height: 100%;
}

/* Touch-only, per request — js/videos.js skips constructing the wall entirely there (its
   mouse-parallax tilt has no hover to respond to), and the credits list takes over the full
   width it would otherwise have shared with the wall rather than leaving that space empty. */
@media (hover: none) {
  .videos-wall {
    display: none;
  }

  .videos-page__list-wrap {
    flex: 1 1 auto;
  }

  /* Gives the marquee below room without pushing the layout past the viewport on a wide touch
     screen (iPad landscape etc.) — same 255px constant as the unmodified rule above, just with
     the marquee's own footprint (130px tall + its var(--space-4) margin-bottom) subtracted too.
     Narrower touch screens fall under the max-width:900px breakpoint further down instead, which
     already switches this to height:auto and comes later in the file, so it wins there — this
     only ever applies at 900px+. */
  .videos-page__layout {
    height: clamp(360px, calc(100vh - 255px - 154px), 760px);
  }
}

/* Touch-only decorative strip standing in for the wall's own visual appeal — a curated, looping
   selection of the wall's GIFs (built by js/videos.js's buildVideosMarquee, same seamless-loop
   technique as Intimacy's lyrics-page marquee: the sequence is duplicated once in the track and
   the animation below translates exactly -50% of that doubled width, landing on a frame identical
   to the start regardless of viewport width). Hidden by default/on any hover-capable device —
   js/videos.js only ever populates the track on touch, but this keeps the (otherwise empty) box
   from claiming any layout space there too. */
.videos-page__marquee {
  display: none;
}

@media (hover: none) {
  .videos-page__marquee {
    display: block;
    width: calc(100% + 2 * var(--space-4));
    margin: 0 calc(-1 * var(--space-4)) var(--space-4);
    overflow: hidden;
  }
}

.videos-page__marquee-track {
  display: flex;
  align-items: center;
  gap: 0;
  width: max-content;
  animation: videos-marquee 40s linear infinite;
}

/* Each tile is a fixed-size crop window (width set inline per item by js/videos.js, matching the
   image's own aspect ratio at height:130 before zooming) — these GIFs are screen-captures from a
   gif-maker tool with a small watermark sitting right at the bottom edge (same source images, same
   issue already handled for the wall's own tiles above), so the img inside is scaled up 18% from
   its top edge and the overflow is clipped, pushing the watermark strip below the visible frame.
   transform (rather than the wall's width/height/margin over-sizing trick) is safe to use here,
   unlike on the wall — that one avoided transform specifically because it sits deep inside a
   transform-style:preserve-3d stack (wall→plane→col→track→tile) where a transform on the img
   itself broke rendering; this marquee has no such stack, just a plain flex track. */
.videos-page__marquee-item {
  position: relative;
  height: 130px;
  overflow: hidden;
  flex-shrink: 0;
}

.videos-page__marquee-item img {
  display: block;
  height: 130px;
  width: auto;
  transform: scale(1.18);
  transform-origin: top center;
}

@keyframes videos-marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .videos-page__marquee-track {
    animation: none;
  }
}

/* A native scrollbar exists here regardless, but on trackpad-default systems (macOS "show
   scrollbars: when scrolling", most mobile browsers) it's invisible until the list is actually
   mid-scroll — against a fully black page there was otherwise no persistent visual cue that this
   box scrolls at all, or anything to grab with a mouse. scrollbar-color covers Firefox;
   ::-webkit-scrollbar below covers Chrome/Safari/Edge. */
.videos-page__list {
  height: 100%;
  overflow-y: auto;
  padding-right: var(--space-2);
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.35) transparent;
}

.videos-page__list::-webkit-scrollbar {
  width: 6px;
}

.videos-page__list::-webkit-scrollbar-track {
  background: transparent;
}

.videos-page__list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.35);
  border-radius: 3px;
}

.videos-page__list::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.55);
}

/* Hidden once js/videos.js detects the list is scrolled to its own bottom (via .is-at-bottom on
   the wrapper) — a fade that's still there when there's genuinely nothing left to scroll to would
   read as a mistake rather than a hint. Purely decorative (pointer-events:none) — it overlaps
   whatever list item happens to render at the very bottom, and clicks need to keep reaching that
   item rather than getting swallowed here. The chevron glyph itself lives on the separate
   .videos-page__list-scroll-btn below instead, which is the actual click target. */
.videos-page__list-fade {
  position: absolute;
  left: 0;
  right: var(--space-2);
  bottom: 0;
  height: 64px;
  background: linear-gradient(to bottom, transparent, #000);
  pointer-events: none;
  transition: opacity 0.25s ease;
}

/* Small, centred hit target instead of spanning the full width of the fade above it — this one
   IS clickable (it's what makes the chevron actually scroll now, which it never did before: the
   old chevron was just the fade's own ::before, and the fade is pointer-events:none by design).
   Kept narrow and short rather than matching the fade's full 64px strip specifically so it can't
   swallow clicks meant for a list item rendering underneath it. */
.videos-page__list-scroll-btn {
  position: absolute;
  left: 50%;
  bottom: var(--space-1);
  transform: translateX(-50%);
  width: 2rem;
  height: 1.5rem;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  transition: opacity 0.25s ease;
}

.videos-page__list-scroll-btn::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0.15rem;
  width: 0.6em;
  height: 0.6em;
  border-right: 2px solid rgba(255, 255, 255, 0.5);
  border-bottom: 2px solid rgba(255, 255, 255, 0.5);
  transform: translate(-50%, 0) rotate(45deg);
  transition: border-color 0.4s ease 0.1s;
}

.videos-page__list-scroll-btn:hover::before,
.videos-page__list-scroll-btn:focus-visible::before {
  border-color: rgba(255, 255, 255, 0.9);
  transition-duration: 0.2s;
  transition-delay: 0s;
}

.videos-page__list-wrap.is-at-bottom .videos-page__list-fade,
.videos-page__list-wrap.is-at-bottom .videos-page__list-scroll-btn {
  opacity: 0;
}

.videos-page__list-year {
  font-family: var(--font-heading);
  color: var(--color-text-muted);
  font-size: 1.1rem;
  margin: var(--space-4) 0 var(--space-2);
}

.videos-page__list-year:first-child {
  margin-top: 0;
}

.videos-page__list-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: var(--space-2) 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
  font-family: var(--font-body);
  color: #fff;
  cursor: pointer;
  transition: color 0.4s ease 0.1s;
}

.videos-page__list-item:hover {
  color: var(--color-accent);
  transition-duration: 0.2s;
  transition-delay: 0s;
}

.videos-page__list-item[disabled] {
  cursor: default;
  color: var(--color-text-muted);
}

.videos-page__list-item[disabled]:hover {
  color: var(--color-text-muted);
}

.videos-page__list-title {
  font-size: 1rem;
}

.videos-page__list-director {
  display: block;
  font-family: var(--font-body-light);
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin-top: 0.15rem;
}

.videos-page__list-item[disabled] .videos-page__list-director {
  font-style: italic;
}

/* The wall itself — a vanilla-JS/CSS port of reactbits.dev's "Drift Wall" (a React-only
   component; this site has no build step or framework, so the actual technique — a
   requestAnimationFrame loop translating each column continuously and wrapping it via modulo,
   the same core idea already used for Intimacy's marquee elsewhere on this site, plus a
   mouse-parallax 3D tilt on the whole plane — was ported by hand into plain js/videos.js rather
   than the original's React hooks). Background is pure #000 — an exact match for the page itself
   (see body[data-page="videos"] above), not just "dark" — so there's no visible seam between the
   wall's own box and the page around it, per the user's own request that it "blend in better"
   once the whole page went black. */
.videos-wall {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  background: #000;
  border-radius: 8px;
  perspective: var(--vw-perspective, 1200px);
  perspective-origin: 50% 50%;
  cursor: pointer;
}

.videos-wall__plane {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  flex-direction: row;
  transform-style: preserve-3d;
  transform-origin: 50% 50%;
  will-change: transform;
}

.videos-wall__col {
  position: relative;
  width: calc(var(--vw-tile-w, 200px) + var(--vw-gap, 18px));
  transform-style: preserve-3d;
}

.videos-wall__track {
  display: flex;
  flex-direction: column;
  will-change: transform;
  transform-style: preserve-3d;
}

.videos-wall__tile {
  position: relative;
  display: block;
  width: 100%;
  height: calc(var(--vw-tile-h, 132px) + var(--vw-gap, 18px));
  flex: 0 0 auto;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  outline: none;
  transform-style: preserve-3d;
  cursor: pointer;
}

.videos-wall__tile-inner {
  position: absolute;
  inset: calc(var(--vw-gap, 18px) / 2);
  display: block;
  border-radius: 10px;
  overflow: hidden;
  background: #14141c;
  opacity: 0.55;
  transform: translateZ(0);
  pointer-events: none;
  transition:
    transform 0.42s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.42s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

.videos-wall__tile img {
  width: calc(100% + 36px);
  height: calc(100% + 36px);
  margin: -18px 0 0 -18px;
  max-width: none;
  object-fit: cover;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
  /* These GIFs are screen-captures from a gif-maker tool — most have a thin letterbox border
     and/or a small watermark sitting right at the edge. object-fit:cover alone crops to the
     tile's own aspect ratio but doesn't guarantee cropping *past* the source image's own edges,
     so this over-sizes the image by a flat 18px per side (clipped by .videos-wall__tile-inner's
     own overflow:hidden) to push those edge artifacts out of the visible frame. Deliberately
     *not* transform:scale() despite being the more obvious tool for this — tried that first and
     it broke tile rendering intermittently (confirmed directly: removing it fixed tiles that had
     been rendering as plain black rectangles). This is deep inside a transform-style:preserve-3d
     stack (wall → plane → col → track → tile), and adding another transform on the img itself
     seems to be one transform too many for the browser to composite reliably here — sizing via
     plain width/height/margin sidesteps the whole problem instead of fighting it. */
}

.videos-wall__tile-overlay {
  position: absolute;
  inset: 0;
  background: #060010;
  opacity: 0.42;
  pointer-events: none;
  transition: opacity 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

.videos-wall__tile-label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--space-2);
  font-family: var(--font-body);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #fff;
  opacity: 0;
  transition: opacity 0.42s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

.videos-wall__tile.is-active .videos-wall__tile-inner {
  opacity: 1;
  transform: translateZ(64px);
  box-shadow: 0 24px 60px -18px rgba(0, 0, 0, 0.7);
}

.videos-wall__tile.is-active .videos-wall__tile-overlay {
  opacity: 0;
}

.videos-wall__tile.is-active .videos-wall__tile-label {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .videos-wall__plane,
  .videos-wall__track {
    will-change: auto;
  }
}

@media (max-width: 900px) {
  .videos-page__layout {
    flex-direction: column;
    height: auto;
  }

  .videos-wall {
    height: 60vh;
  }

  .videos-page__list-wrap {
    flex: none;
    height: 50vh;
  }
}

/* Video overlay modal */
.videos-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.85);
  padding: var(--space-4);
}

.videos-modal.is-open {
  display: flex;
}

.videos-modal__frame-wrap {
  position: relative;
  width: min(100%, 1100px);
  aspect-ratio: 16 / 9;
}

.videos-modal__frame-wrap iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 4px;
}

.videos-modal__close {
  position: absolute;
  top: calc(-1 * var(--space-5));
  right: 0;
  background: none;
  border: none;
  color: #fff;
  font-family: var(--font-body);
  font-size: 0.9rem;
  cursor: pointer;
  padding: var(--space-2);
  transition: color 0.4s ease 0.1s;
}

.videos-modal__close:hover {
  color: var(--color-accent);
  transition-duration: 0.2s;
  transition-delay: 0s;
}
