/* wiqi — performances page. Loaded AFTER styles.css.
   Everything that only this page uses lives here.
   Order: tokens → backdrop → video background → list → intro → row header → panel → media grid → lightbox → responsive → reduced motion → desktop grid */

/* ---------- TOKENS ---------- */
body.page-performances{
  /* titles: Syne (already loaded by the page), a wide, characterful grotesque. Nunito = small text + glyph fallback (e.g. Ə) */
  --perf-display: var(--font-display, 'Syne', 'Nunito', system-ui, sans-serif);
  --perf-font: var(--font-text, 'Nunito', system-ui, sans-serif);
  --perf-text: #fff;
  --perf-muted: rgba(255,255,255,.58);     /* year / kind */
  --perf-line: rgba(255,255,255,.16);      /* hairline separators */
  --perf-line-strong: rgba(255,255,255,.5);
  --perf-pad: 6vw;                         /* horizontal page margin, also read by the phone photo grid */
  --perf-ease: cubic-bezier(.2,.8,.2,1);
}

/* ---------- STAGE BACKDROP ----------
   Dark stage instead of the daytime sky (same idea as the sets page): the photos are the light source,
   so the chrome around them stays quiet. */
body.page-performances{
  background: linear-gradient(180deg, #150a12 0%, #0d070f 55%, #050308 100%);
}
body.page-performances nav{
  background: linear-gradient(180deg, rgba(10,6,12,.85), rgba(10,6,12,0));
}
html:has(body.page-performances){
  scrollbar-gutter: stable;      /* no layout jump when the lightbox locks scroll */
  background: #0d070f;           /* the reserved gutter shows <html>'s background: keep it dark, not the site's blue */
}

/* ---------- VIDEO BACKGROUND ---------- */
/* 100lvh (largest viewport) instead of inset:0 → the video no longer rescales when the mobile URL bar collapses */
.video-bg{
  position: fixed; top: 0; left: 0; right: 0;
  height: 100vh; height: 100lvh;
  z-index: 0; overflow: hidden; pointer-events: none; background: #0d070f;
}
.video-bg video{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* lighter scrim while the footage plays bare, then eases into the legible state (.scrim-settled: performance.js) */
.video-bg::after{
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(13,7,15,.32) 0%, rgba(13,7,15,.1) 35%, rgba(13,7,15,.4) 100%);
  transition: background 1.4s ease;
}
.video-bg.scrim-settled::after{
  background: linear-gradient(180deg, rgba(13,7,15,.7) 0%, rgba(13,7,15,.46) 35%, rgba(13,7,15,.76) 100%);
}

/* ---------- LIST ---------- */
.perf-list{
  max-width: 1400px;
  margin: 0;
  padding: clamp(2.5rem, 8vh, 5.5rem) var(--perf-pad) 2rem;
}
.perf-item{ position: relative; color: var(--perf-text); }
.perf-item:nth-child(1){ --i: 0; } .perf-item:nth-child(2){ --i: 1; } .perf-item:nth-child(3){ --i: 2; }
.perf-item:nth-child(4){ --i: 3; } .perf-item:nth-child(5){ --i: 4; } .perf-item:nth-child(6){ --i: 5; }

/* separator lines are pseudo-elements (not borders) so they can draw in from the left */
.perf-item::before, .perf-item:last-child::after{
  content: ""; position: absolute; left: 0; right: 0; height: 1px;
  background: var(--perf-line);
  transform-origin: left center;
  transition: transform 1.1s var(--perf-ease) calc(var(--i) * 90ms), background-color .4s ease;
  pointer-events: none;
}
.perf-item::before{ top: 0; }
.perf-item:last-child::after{ bottom: 0; }
/* the open row gets a slightly firmer top line: the only "state" marker the list needs */
.perf-item.is-open::before{ background: var(--perf-line-strong); }

/* ---------- INTRO: bare video first, then the list draws in ----------
   body.perf-intro is set in the HTML (no flash) and removed by performance.js,
   which adds .perf-intro-done at the same moment to start the entrance. */
.perf-intro .perf-title, .perf-intro .perf-meta, .perf-intro .perf-chevron{ opacity: 0; }
.perf-intro .perf-list{ pointer-events: none; }   /* invisible rows must not be clickable */
.perf-intro .perf-item::before, .perf-intro .perf-item:last-child::after{ transform: scaleX(0); }

/* One orchestrated sequence per row, in this order:
   1. hairline draws in from the left (transition on .perf-item::before, above)
   2. title wipes in left → right while rising a few px
   3. year / kind fades in, then the chevron
   Only opacity / transform / clip-path are animated (no blur, no layout). Keyframes omit the resting
   opacity on purpose, so each element settles on its own final value (the chevron rests at .5). */
@keyframes perfTitleIn{
  from{ opacity: 0; transform: translateY(.45em); clip-path: inset(0 100% 0 0); }
  to{ clip-path: inset(-30% -10% -30% -10%); }      /* oversized end box: the glow is never clipped */
}
@keyframes perfFadeIn{
  from{ opacity: 0; transform: translateY(.35rem); }
}
.perf-intro-done .perf-title{
  animation: perfTitleIn 1.15s var(--perf-ease) backwards;
  animation-delay: calc(var(--i) * 110ms + 250ms);
}
.perf-intro-done .perf-meta{
  animation: perfFadeIn .8s var(--perf-ease) backwards;
  animation-delay: calc(var(--i) * 110ms + 700ms);
}
.perf-intro-done .perf-chevron{
  animation: perfFadeIn .8s var(--perf-ease) backwards;
  animation-delay: calc(var(--i) * 110ms + 800ms);
}

/* ---------- ROW HEADER ---------- */
.perf-head{ margin: 0; font: inherit; }
.perf-toggle, .perf-head--static{
  display: flex; align-items: center; gap: 1.25rem;
  width: 100%; margin: 0; padding: clamp(1.4rem, 3vw, 2.2rem) 0;
  text-align: left;
}
.perf-toggle{
  appearance: none; -webkit-appearance: none; background: none; border: 0;
  color: inherit; font: inherit; cursor: pointer; min-height: 56px;
  -webkit-tap-highlight-color: transparent;
}
.perf-toggle:focus-visible{ outline: 1px solid var(--perf-line-strong); outline-offset: 6px; border-radius: 4px; }

/* title on the left, year / kind on the right, on one baseline; on narrow screens the meta drops under the title */
.perf-heading{
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .35rem 1.5rem;
  flex: 1 1 auto; min-width: 0;
}

/* Syne 600, tight tracking: a confident editorial voice. Hover adds a soft white halo, never a colour change. */
.perf-title{
  font-family: var(--perf-display); font-weight: 600;
  font-size: clamp(1.5rem, 3.1vw, 2.35rem);
  line-height: 1.12; letter-spacing: -.025em;
  color: var(--perf-text);
  /* two shadows always (drop + glow) so hover can interpolate; the glow is invisible at rest */
  text-shadow: 0 2px 20px rgba(0,0,0,.45), 0 0 0 rgba(255,255,255,0);
  text-wrap: balance; overflow-wrap: break-word;
  transition: transform .5s var(--perf-ease), text-shadow .6s ease;
}

/* year / kind = plain quiet text. No pills, no outlines, no caps, no separators: spacing does the grouping */
.perf-meta{ display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem 1.1rem; }
.perf-tag{
  font-family: var(--perf-font); font-weight: 500;
  font-size: clamp(.85rem, 1.1vw, .98rem); line-height: 1.2; letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
  color: var(--perf-muted); white-space: nowrap;
  transition: color .3s ease;
}

/* the year stays hidden until its row is opened. It keeps its space (opacity + visibility, not display),
   so opening never shifts the title or the other tags; visibility also keeps it out of screen readers while hidden. */
.perf-tag--year{
  opacity: 0; visibility: hidden; transform: translateY(.3rem);
  transition: opacity .45s ease, transform .5s var(--perf-ease), visibility 0s linear .45s, color .3s ease;
}
.perf-item.is-open .perf-tag--year{
  opacity: 1; visibility: visible; transform: none;
  transition: opacity .5s ease .12s, transform .55s var(--perf-ease) .12s, visibility 0s, color .3s ease;
}

/* chevron: a bare thin glyph, no circle, no fill */
.perf-chevron{
  flex: none; display: grid; place-items: center;
  width: 24px; height: 24px;
  color: var(--perf-text); opacity: .5;
  transition: opacity .3s ease, transform .5s var(--perf-ease);
}
.perf-chevron svg{ display: block; width: 20px; height: 20px; stroke-width: 1.5; transition: filter .4s ease; }

.perf-item.is-open .perf-chevron{ opacity: 1; transform: rotate(180deg); }
.perf-item.is-open .perf-tag{ color: rgba(255,255,255,.8); }

/* "lights up" = a soft white halo on the title + chevron, brighter meta, firmer hairline. Never a colour change. */
.perf-toggle:focus-visible .perf-title{ text-shadow: 0 2px 20px rgba(0,0,0,.3), 0 0 22px rgba(255,255,255,.4); }
.perf-toggle:focus-visible .perf-chevron{ opacity: 1; }
.perf-toggle:focus-visible .perf-chevron svg{ filter: drop-shadow(0 0 5px rgba(255,255,255,.7)); }
@media (hover: hover){          /* no sticky hover after a tap on touch screens */
  .perf-toggle:hover .perf-title{ transform: translateX(.35rem); text-shadow: 0 2px 20px rgba(0,0,0,.3), 0 0 22px rgba(255,255,255,.4); }
  .perf-toggle:hover .perf-tag{ color: rgba(255,255,255,.85); }
  .perf-toggle:hover .perf-chevron{ opacity: 1; }
  .perf-toggle:hover .perf-chevron svg{ filter: drop-shadow(0 0 5px rgba(255,255,255,.7)); }
  .perf-item:has(.perf-toggle:hover)::before{ background: rgba(255,255,255,.4); }
}

/* rows with no media yet: same layout, quieter, no chevron or pointer */
.perf-item--static .perf-heading{ opacity: .4; }

/* ---------- PANEL ----------
   height animation without measuring: grid rows 0fr → 1fr (performance.js sets .is-open and inert) */
.perf-panel{ display: grid; grid-template-rows: 0fr; transition: grid-template-rows .5s var(--perf-ease); }
.perf-item.is-open .perf-panel{ grid-template-rows: 1fr; }
.perf-panel-inner{
  min-height: 0; overflow: hidden;
  padding-inline: 2px; margin-inline: -2px;        /* keeps the hairline ring from being clipped */
  container-type: inline-size;                     /* lets the photo grid size rows from its real width (cqw) */
}

/* ---------- MEDIA GRID: justified rows (phones + tablets) ----------
   Every row shares one height and fills the full width; photos are never cropped.
   --ar (width/height) is set per card in the HTML. */
.media-grid{
  --gap: .5rem; --cap: 1.7;
  /* phones: row height = a third of the real panel width */
  --rh: calc((100vw - var(--perf-pad) * 2 - var(--gap) - 2px) / 3);
  display: flex; flex-wrap: wrap; gap: var(--gap);
  padding: .25rem 0 clamp(1.8rem, 3.5vw, 2.8rem);
}
@supports (width: 1cqw){
  .media-grid{ --rh: calc((100cqw - var(--gap) - 2px) / 3); }
}
.media-grid::after{ display: none; }   /* a lone last item is capped by max-width below instead of stretching */
@media (min-width: 561px){
  .media-grid{ --gap: .75rem; --rh: 200px; }
  .media-grid::after{ content: ""; display: block; flex-grow: 1000000; height: 0; margin-top: calc(var(--gap) * -1); } /* last row keeps natural size */
}

.media-card{
  --ar: 1.5;
  appearance: none; -webkit-appearance: none; position: relative; display: block;
  flex: calc(var(--ar) * 100) 1 calc(var(--ar) * var(--rh));
  max-width: calc(var(--ar) * var(--rh) * var(--cap));   /* a lone item never balloons */
  aspect-ratio: var(--ar);
  margin: 0; padding: 0; border: 0; border-radius: 2px; overflow: hidden;
  background: #0a0710; cursor: zoom-in;
  -webkit-tap-highlight-color: transparent;
}
.media-card img{
  position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover;
  filter: brightness(.92);
  transition: transform .9s var(--perf-ease), filter .4s ease, opacity .35s ease;
}
.media-card img.is-loading{ opacity: 0; }        /* fades in once decoded instead of popping */
.media-card:focus-visible{ outline: 1px solid var(--perf-line-strong); outline-offset: -4px; } /* inset: the panel clips anything outside */
@media (hover: hover){
  .media-card:hover img{ filter: brightness(1); transform: scale(1.02); }
  .media-card--video:hover img{ transform: none; }
}

/* a lone portrait video (Mil horas) would otherwise be capped to ~1/3 of the panel on phones and tablets:
   give it a proper size. Desktop uses the uniform tile grid below, so this stays out of that query. */
@media (max-width: 900px){
  .media-card--feature{ flex: 0 1 auto; width: min(100%, 17rem); max-width: none; }
}

/* video cards: <video> overlays the poster, so the grid always sizes against the <img>.
   .is-previewing is only added once the clip is really playing (no black flash while it loads). */
.media-card--video{ cursor: pointer; }
.card-video{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .35s ease; pointer-events: none; }
.media-card--video.is-previewing img{ opacity: 0; }
.media-card--video.is-previewing .card-video{ opacity: 1; }

/* quiet badge: dark glass, no outline, no colour change. Always visible so a tile reads as a clip before it's touched. */
.video-badge{
  position: absolute; left: .6rem; bottom: .6rem;
  display: flex; align-items: center; gap: .3rem;
  padding: .3rem .6rem .3rem .45rem;
  border-radius: 999px;
  background: rgba(13,7,15,.6);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  color: #fff;
  font-family: var(--perf-font); font-weight: 500; font-size: .72rem; letter-spacing: .02em;
  pointer-events: none;
  transition: background .25s ease;
}
.video-badge svg{ width: 12px; height: 12px; }
.media-card--video:focus-visible .video-badge{ background: rgba(13,7,15,.88); }
@media (hover: hover){ .media-card--video:hover .video-badge{ background: rgba(13,7,15,.88); } }

/* ---------- LIGHTBOX ----------
   The close / prev / next buttons come BEFORE the <figure> in the DOM, and the figure is a positioned, transformed
   box, so it would paint on top of them: buttons carry an explicit z-index above the media, on a dark glass disc
   that reads on any photo. */
.lightbox{
  --lb-ty: -50%;                                   /* arrows: vertically centred on desktop, reset on phones */
  --lb-edge: 1.25rem;
  --lb-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  position: fixed; inset: 0; z-index: 10000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(13,7,15,.95);
  overscroll-behavior: contain;
  opacity: 0; pointer-events: none;
  transition: opacity .3s ease;
}
.lightbox.is-open{ opacity: 1; pointer-events: auto; }
.lightbox [hidden]{ display: none !important; }   /* author display:flex would beat [hidden] */

.lightbox-figure{
  position: relative; z-index: 1; margin: 0;
  transform: scale(.96);
  transition: transform .3s var(--perf-ease);
}
.lightbox.is-open .lightbox-figure{ transform: scale(1); }

.lightbox img, .lightbox-media{
  display: block;
  max-width: min(calc(100vw - 10rem), 1200px);     /* 5rem each side = room for the arrows, never under them */
  max-height: calc(100vh - 6rem); max-height: calc(100dvh - 6rem);
  width: auto; height: auto;
  border-radius: 2px; object-fit: contain;
}
.lightbox-media{ background: #000; }

.lightbox-close, .lightbox-prev, .lightbox-next{
  position: fixed; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;                       /* comfortable touch target */
  padding: 0; border: 0; border-radius: 50%;
  background: rgba(13,7,15,.55);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: #fff; opacity: .92; cursor: pointer;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: background .25s ease, opacity .25s ease;
}
.lightbox-close svg, .lightbox-prev svg, .lightbox-next svg{
  width: 22px; height: 22px; stroke-width: 1.6;    /* thin, quiet glyph */
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.5));
}
.lightbox-close{ top: calc(var(--lb-edge) + env(safe-area-inset-top, 0px)); right: calc(var(--lb-edge) + env(safe-area-inset-right, 0px)); }
.lightbox-prev{ left: calc(var(--lb-edge) + env(safe-area-inset-left, 0px)); top: 50%; transform: translateY(var(--lb-ty)); }
.lightbox-next{ right: calc(var(--lb-edge) + env(safe-area-inset-right, 0px)); top: 50%; transform: translateY(var(--lb-ty)); }
.lightbox-close:focus-visible, .lightbox-prev:focus-visible, .lightbox-next:focus-visible{ outline: 1px solid var(--perf-line-strong); outline-offset: 3px; }
.lightbox-close:active, .lightbox-prev:active, .lightbox-next:active{ background: rgba(255,255,255,.22); }
@media (hover: hover) and (pointer: fine){          /* :hover sticks after a tap on touch screens */
  .lightbox-close:hover, .lightbox-prev:hover, .lightbox-next:hover{ background: rgba(255,255,255,.16); opacity: 1; }
}
.lightbox-counter{
  position: fixed; z-index: 2;
  bottom: calc(1.4rem + env(safe-area-inset-bottom, 0px)); left: 50%; transform: translateX(-50%);
  color: #fff; opacity: .7; white-space: nowrap;
  font-family: var(--perf-font); font-weight: 500; font-size: .85rem; letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
}

/* PHONES (portrait): media sits between two reserved bands. Top band = close button, bottom band =
   ‹ 2 / 8 › bar. Nothing ever overlaps the photo or the video's native controls. */
@media (max-width: 700px){
  .lightbox{
    --lb-ty: 0px; --lb-edge: .75rem;
    padding: calc(4.5rem + env(safe-area-inset-top, 0px)) .75rem calc(4.5rem + env(safe-area-inset-bottom, 0px));
    box-sizing: border-box;
  }
  .lightbox img, .lightbox-media{
    max-width: calc(100vw - 1.5rem);
    max-height: calc(100vh - 9rem - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    max-height: calc(100dvh - 9rem - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
  }
  .lightbox-prev, .lightbox-next{ top: auto; bottom: var(--lb-bottom); }
  .lightbox-prev{ left: calc(50% - 6.5rem); }
  .lightbox-next{ right: calc(50% - 6.5rem); }
  .lightbox-counter{ bottom: calc(var(--lb-bottom) + 13px); }
}

/* PHONES (landscape, very short): no vertical room for bands, so arrows go to the sides */
@media (max-height: 500px) and (orientation: landscape){
  .lightbox{ --lb-ty: -50%; --lb-edge: .75rem; padding: 0; }
  .lightbox img, .lightbox-media{
    max-width: calc(100vw - 10rem);
    max-height: calc(100vh - 1rem); max-height: calc(100dvh - 1rem);
  }
  .lightbox-prev, .lightbox-next{ top: 50%; bottom: auto; }
  .lightbox-prev{ left: calc(var(--lb-edge) + env(safe-area-inset-left, 0px)); }
  .lightbox-next{ right: calc(var(--lb-edge) + env(safe-area-inset-right, 0px)); }
  .lightbox-counter{ display: none; }
}

/* scroll lock: on BOTH <html> and <body>. styles.css sets html{overflow-x:hidden} on phones, which stops
   body.style.overflow from reaching the viewport, so the page kept scrolling behind the viewer. */
html.lb-lock, body.lb-lock{ overflow: hidden !important; }

/* keep the worm cursor visible: styles.css has it at 9999 and the lightbox at 10000 */
.worm-cursor{ z-index: 10001; }

/* ---------- RESPONSIVE ---------- */
@media (max-width: 700px){
  .perf-list{ padding-top: 2rem; }
  .perf-toggle, .perf-head--static{ gap: .75rem; }
  .perf-heading{ flex-direction: column; align-items: flex-start; justify-content: flex-start; gap: .4rem; }
  .perf-chevron svg{ width: 18px; height: 18px; }
  .perf-title{ font-size: clamp(1.5rem, 7.4vw, 2rem); }
  .perf-tag{ font-size: .85rem; }
}

/* ---------- REDUCED MOTION ---------- */
@media (prefers-reduced-motion: reduce){
  .perf-intro .perf-title, .perf-intro .perf-meta{ opacity: 1; }
  .perf-intro .perf-chevron{ opacity: .5; }
  .perf-intro .perf-item::before, .perf-intro .perf-item:last-child::after{ transform: none; }
  .perf-intro-done .perf-title, .perf-intro-done .perf-meta, .perf-intro-done .perf-chevron{ animation: none; }
  .perf-item::before, .perf-item:last-child::after{ transition: none; }
  .perf-panel, .perf-chevron, .perf-title, .perf-tag, .perf-tag--year, .media-card img, .card-video, .video-bg::after,
  .lightbox, .lightbox-figure,
  .lightbox-close, .lightbox-prev, .lightbox-next{ transition: none !important; }
  .perf-toggle:hover .perf-title{ transform: none; }
  .perf-tag--year{ transform: none; }
  .card-video{ display: none; }
}

/* =====================================================================
   DESKTOP (>= 901px) — uniform tile grid. Mobile/tablet rules above are untouched.
   Every photo AND video gets the exact same tile on a strict column grid.
   Media is cropped to the tile with object-fit: cover (change --tile-ar to 4/5, 3/4 or 4/3 to taste).
   ===================================================================== */
@media (min-width: 901px){
  .media-grid{
    --tile-ar: 1 / 1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(190px, 16vw, 250px), 1fr));
    gap: clamp(.6rem, .9vw, .9rem);
    padding: .25rem 0 clamp(2.2rem, 3.4vw, 3.2rem);
  }
  .media-grid::after{ display: none; }   /* no flex filler needed on a grid */

  .media-card{
    flex: none; width: 100%; max-width: none;
    aspect-ratio: var(--tile-ar);
  }
  .media-card img, .card-video{ object-fit: cover; object-position: center 30%; }  /* favour faces / upper body */
  .video-badge{ left: .65rem; bottom: .65rem; }
}
