/* =====================================================================
   Journal · Immersion — Tristan Campbell (tristancampbell.com/journal)
   Full-bleed, one-image-per-screen immersive journal.
   Plain CSS (served directly, no Razor/build).
   ===================================================================== */

:root {
  --bg: #000;
  --ink: #fff;
  --muted: rgba(255, 255, 255, .58);
  --faint: rgba(255, 255, 255, .30);
  --line: rgba(255, 255, 255, .16);
  --ease: cubic-bezier(.16, 1, .3, 1);
  --vh: 100vh;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  background: var(--bg);
  color: var(--ink);
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
}
body { overflow: hidden; }

::selection { background: rgba(255, 255, 255, .18); }

img { max-width: 100%; }

/* ============ LOADER ============ */
.loader {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity .7s var(--ease), visibility .7s;
}
.loader.gone { opacity: 0; visibility: hidden; pointer-events: none; }
.loader .spinner {
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-top-color: var(--ink);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ============ MESSAGE (error / empty) ============ */
.message {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  font-size: clamp(.9rem, 2vw, 1.05rem);
  font-weight: 300;
  letter-spacing: .02em;
  color: var(--muted);
  background: #000;
}

/* ============ SCROLLER ============ */
#scroller {
  position: fixed;
  inset: 0;
  height: 100%;
  overflow-y: scroll;
  overflow-x: hidden;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
}
#scroller::-webkit-scrollbar { display: none; }

.frame {
  position: relative;
  height: var(--vh);
  width: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
  /* Colour theme: the photo's dominant colour as a loading background (set per frame by the
     script / server). Falls back to near-black when the theme is off. */
  background: var(--frame-bg, #040404);
  transition: background-color .5s ease;
}

/* image wrapper — holds the ken-burns transform */
.media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  will-change: transform;
}
/* slightly oversized so parallax/drift never reveals an edge */
.media-inner {
  position: absolute;
  inset: -7% -4%;
  will-change: transform;
  transform: scale(1.06);
  transition: transform 0s;
}
.frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Per-image focal anchor (set as CSS vars by the JS / server on each .frame).
     Defaults to centre. Portrait/mobile uses --pos-m, falling back to --pos-d. */
  object-position: var(--pos-d, center);
  display: block;
}
@media (orientation: portrait) {
  .frame img {
    object-position: var(--pos-m, var(--pos-d, center));
  }
}
.lqip {
  filter: blur(22px) saturate(1.05);
  transform: scale(1.12);
  opacity: 1;
  transition: opacity .9s ease;
  z-index: 1;
}
.full {
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  z-index: 2;
}
.full.loaded { opacity: 1; }
.full.loaded + .lqip,
.lqip.hide { opacity: 0; }

/* legibility scrims */
.scrim { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.scrim-bottom {
  background: linear-gradient(to top,
    rgba(0, 0, 0, .80) 0%,
    rgba(0, 0, 0, .48) 16%,
    rgba(0, 0, 0, .14) 34%,
    rgba(0, 0, 0, 0) 54%);
}
.scrim-top {
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, .55) 0%,
    rgba(0, 0, 0, .16) 30%,
    rgba(0, 0, 0, 0) 56%);
}
.vignette {
  background: radial-gradient(130% 120% at 50% 46%,
    rgba(0, 0, 0, 0) 52%,
    rgba(0, 0, 0, .34) 100%);
}

/* ============ COLOUR THEME ============
   Only active when <html> has .tc-colour-theme (the script adds it when the theme is on),
   so turning the theme off restores the original black scrims/chrome exactly. The per-photo
   colour is inherited from the frame's --frame-bg / the active --accent.
   NOTE: scrims are intentionally NOT tinted — fading a tinted colour to `transparent` (which is
   transparent BLACK) shifts hue and leaves a faint band at the fade edge on warm-dominant photos.
   The original black scrims fade cleanly, so they are left untouched. */
/* accent (a vivid palette colour) on the active timeline tick + the counter number */
.tick.active i { transition: background-color .45s ease, width .18s ease, height .18s ease; }
.tc-colour-theme .tick.active i { background: var(--accent, var(--ink)); }
.rail .counter .cur { transition: color .45s ease; }
.tc-colour-theme .rail .counter .cur { color: var(--accent, var(--ink)); }
/* adaptive chrome: on a light photo, boost legibility of the (light) chrome */
.bottom .date, .bottom .meta, .rail .counter, .rail .year,
.view, .grid-btn, .bottom .actions .archive-link {
  transition: text-shadow .5s ease;
}
.brand .logo { transition: filter .5s ease; }
body.photo-light .bottom .date,
body.photo-light .bottom .meta,
body.photo-light .rail .counter,
body.photo-light .rail .year,
body.photo-light .view,
body.photo-light .grid-btn,
body.photo-light .bottom .actions .archive-link {
  text-shadow: 0 1px 16px rgba(0, 0, 0, .65), 0 0 3px rgba(0, 0, 0, .5);
}
body.photo-light .brand .logo { filter: drop-shadow(0 1px 12px rgba(0, 0, 0, .6)); }

/* ============ CHROME (fixed overlays) ============ */
.chrome { transition: opacity .55s var(--ease), transform .55s var(--ease); }

/* ============ TOP-LEFT BRAND ============ */
.brand {
  position: fixed;
  top: clamp(18px, 3.2vh, 38px);
  left: clamp(18px, 5vw, 48px);
  z-index: 42;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.brand a { display: block; line-height: 0; }
.brand .logo {
  display: block;
  width: clamp(120px, 18vw, 190px);
  height: auto;
  filter: drop-shadow(0 2px 12px rgba(0, 0, 0, .45));
}

/* ============ RIGHT-SIDE YEAR-TICK RAIL ============ */
.rail {
  position: fixed;
  right: clamp(14px, 2.2vw, 26px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
}
/* Hover/focus: fade in a soft 50% black panel behind the rail so the tick marks
   and labels read clearly over bright photos. The gradient fades to transparent on
   the left so it blends into the image rather than reading as a hard box. */
.rail::before {
  content: "";
  position: absolute;
  inset: -14px -20px -14px -44px;
  border-radius: 16px;
  background: linear-gradient(to left, rgba(0, 0, 0, .5), rgba(0, 0, 0, .3) 55%, rgba(0, 0, 0, 0));
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
  z-index: -1;
}
.rail:hover::before,
.rail:focus-within::before {
  opacity: 1;
}
.rail .counter {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 300;
  margin-bottom: 18px;
  text-align: right;
  line-height: 1;
  user-select: none;
}
.rail .counter .cur {
  font-size: 1.5rem;
  letter-spacing: -.02em;
  color: var(--ink);
  display: block;
  font-variant-numeric: tabular-nums;
}
.rail .counter .tot {
  font-size: .72rem;
  letter-spacing: .1em;
  color: var(--faint);
  font-family: "Inter", sans-serif;
}
.rail .year {
  font-family: "Inter", sans-serif;
  font-size: 10px;
  letter-spacing: .22em;
  color: var(--muted);
  margin-bottom: 16px;
  font-variant-numeric: tabular-nums;
}
.ticks {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center; /* centre the visible window of ticks (see JS) */
  gap: 0;
  position: relative;
  /* Available height for the ruler = viewport minus the counter/year above it,
     capped at 1110px = 185 ticks x 6px (its natural full size). The JS reads this
     height and shows only as many full-size ticks as fit — a window centred on
     the active photo — instead of squashing all 185 into an unreadable sliver.
     var(--vh) is the real innerHeight set by the JS (mobile address-bar fix). */
  height: min(1110px, calc(var(--vh, 100vh) * 0.9 - 78px));
}
.tick {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0;
  flex: none;       /* fixed-size ticks; the JS windows how many are shown */
  height: 6px;      /* keep in sync with TICK_H in journal-immersion.js */
  display: flex;
  align-items: center;
  justify-content: flex-end;
  cursor: pointer;
  width: 34px;
  position: relative; /* anchor the hover card so it centres on this tick */
}
.tick i {
  display: block;
  height: 1px;
  width: 10px;
  background: var(--faint);
  transition: width .35s var(--ease), background .35s var(--ease), opacity .35s;
}
.tick.year-start i { width: 18px; background: var(--muted); }
.tick:hover i, .tick:focus-visible i { width: 24px; background: var(--ink); }
.tick:focus-visible { outline: none; }
.tick:focus-visible i { box-shadow: 0 0 0 2px rgba(255, 255, 255, .25); }
.tick.active i { width: 28px; height: 2px; background: var(--ink); }

/* floating date + thumbnail preview card on hover/focus.
   Anchored to the tick (which is position:relative), so `top: 50%` +
   translateY(-50%) centres the whole card vertically on its own tick. */
.tick .flag {
  position: absolute;
  right: 42px;
  top: 50%;
  transform: translateY(-50%) translateX(8px);
  width: 132px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: rgba(0, 0, 0, .82);
  border: 1px solid var(--line);
  border-radius: 7px;
  overflow: hidden;
  box-shadow: 0 12px 34px rgba(0, 0, 0, .55);
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.tick .flag .flag-date {
  font-size: 10px;
  letter-spacing: .14em;
  color: var(--ink);
  padding: 5px 8px;
  text-align: center;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.tick .flag .flag-thumb {
  display: block;
  width: 100%;
  height: 88px;
  object-fit: cover;
  background: rgba(255, 255, 255, .05);
  border-top: 1px solid var(--line);
}
.tick:hover .flag, .tick:focus-visible .flag {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}

/* ============ BOTTOM — DATE + META + VIEW ENTRY (design 03 treatment) ============ */
.bottom {
  position: fixed;
  left: clamp(20px, 5vw, 84px);
  bottom: clamp(40px, 7vh, 92px);
  z-index: 6;
  max-width: min(92vw, 900px);
  display: flex;
  flex-direction: column;
}

/* single meta line BELOW the date: "JOURNAL · 2004–2026 · #099".
   The static journal masthead (.strap) + the per-photo sequence number (.seq)
   share one muted line. Constant (not part of the .revealed stagger) — only the
   number changes per photo, so the line stays put while the date re-animates. */
.bottom .meta {
  margin-top: clamp(12px, 1.8vh, 20px);
  font-family: "Inter", sans-serif;
  font-size: clamp(10px, 1.05vw, 12px);
  font-weight: 500;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--muted);
  text-shadow: 0 1px 8px rgba(0, 0, 0, .55);
  font-variant-numeric: tabular-nums;
}

/* big high-contrast serif date */
.bottom .date {
  margin: 0; /* it is an <h1> */
  font-family: "Fraunces", Georgia, "Times New Roman", serif;
  font-weight: 200;
  font-size: clamp(2.3rem, 7.2vw, 6rem);
  line-height: .94;
  letter-spacing: -.018em;
  color: var(--ink);
  text-shadow: 0 2px 30px rgba(0, 0, 0, .45);
}
.bottom .actions .archive-link {
  align-self: center;
  font-family: "Inter", sans-serif;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  padding: 0 2px;
  transition: color .2s ease;
}
.bottom .actions .archive-link:hover,
.bottom .actions .archive-link:focus-visible { color: var(--ink); }
.noscript-fallback {
  position: relative;
  z-index: 50;
  max-width: 44ch;
  margin: 0 auto;
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--ink, #fff);
  font-family: "Inter", sans-serif;
}
.noscript-fallback a { color: var(--ink, #fff); }
.bottom .date .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(46px) rotate(2deg);
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}
.bottom .suffix[hidden] { display: none; } /* collapse the gap when no suffix */
.bottom .suffix {
  display: block;
  margin-top: clamp(8px, 1.4vh, 16px);
  font-family: "Inter", sans-serif;
  font-weight: 300;
  font-size: clamp(.78rem, 1.5vw, 1rem);
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--muted);
  text-shadow: 0 1px 8px rgba(0, 0, 0, .55);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .7s var(--ease) .35s, transform .7s var(--ease) .35s;
}

/* actions row — view-entry + grid/index buttons, revealed together */
.bottom .actions {
  align-self: flex-start;
  margin-top: clamp(16px, 2.4vh, 26px);
  display: flex;
  align-items: center;
  gap: 10px;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .7s var(--ease) .5s, transform .7s var(--ease) .5s;
}

/* view-entry affordance near the date */
.bottom .view {
  appearance: none;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .06);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: "Inter", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  padding: 12px 20px;
  border-radius: 30px;
  transition: background .3s, color .3s, border-color .3s;
}
.bottom .view:hover, .bottom .view:focus-visible {
  background: var(--ink);
  color: #000;
  border-color: var(--ink);
  outline: none;
}
.bottom .view:focus-visible { box-shadow: 0 0 0 3px rgba(255, 255, 255, .35); }
.bottom .view svg { width: 14px; height: 14px; transition: transform .35s var(--ease); }
.bottom .view:hover svg, .bottom .view:focus-visible svg { transform: translate(3px, -3px); }

/* grid / index icon button — opens the full-screen index of every photo */
.bottom .grid-btn {
  appearance: none;
  width: 42px;
  height: 42px;
  flex: 0 0 auto;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .06);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: background .3s, color .3s, border-color .3s;
}
.bottom .grid-btn:hover, .bottom .grid-btn:focus-visible {
  background: var(--ink);
  color: #000;
  border-color: var(--ink);
  outline: none;
}
.bottom .grid-btn:focus-visible { box-shadow: 0 0 0 3px rgba(255, 255, 255, .35); }
.bottom .grid-btn svg { width: 17px; height: 17px; }

/* reveal on the active frame */
.bottom.revealed .suffix { opacity: 1; transform: none; }
.bottom.revealed .actions { opacity: 1; transform: none; }
.bottom.revealed .date .word { opacity: 1; transform: none; }
.bottom.revealed .date .word:nth-child(1) { transition-delay: .12s; }
.bottom.revealed .date .word:nth-child(2) { transition-delay: .20s; }
.bottom.revealed .date .word:nth-child(3) { transition-delay: .28s; }
.bottom.revealed .date .word:nth-child(4) { transition-delay: .36s; }

/* ============ SCROLL HINT (design 03) ============ */
.hint {
  position: fixed;
  left: 50%;
  bottom: clamp(20px, 3.4vh, 34px);
  transform: translateX(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  font-size: 10px;
  letter-spacing: .4em;
  text-transform: uppercase;
  color: var(--muted);
  pointer-events: none;
  transition: opacity .8s ease;
}
.hint.gone { opacity: 0; }
.hint .mouse {
  width: 20px;
  height: 32px;
  border: 1px solid var(--line);
  border-radius: 11px;
  position: relative;
}
.hint .mouse::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 7px;
  width: 2px;
  height: 5px;
  border-radius: 2px;
  background: var(--muted);
  transform: translateX(-50%);
  animation: wheel 1.8s var(--ease) infinite;
}
@keyframes wheel {
  0% { opacity: 0; transform: translate(-50%, 0); }
  30% { opacity: 1; }
  70% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, 9px); }
}

/* ============ IN-PAGE LIGHTBOX ============ */
#lightbox {
  position: fixed;
  inset: 0;
  z-index: 70;
  /* Slightly translucent so the blurred page shows through faintly — a visual
     cue that the area around the photo is clickable to close. */
  background: rgba(3, 3, 4, .65);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s var(--ease), visibility .45s;
  display: flex;
  flex-direction: column;
}
#lightbox.open { opacity: 1; visibility: visible; }

.lb-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: clamp(16px, 3vh, 30px) clamp(16px, 5vw, 48px) clamp(8px, 1.4vh, 14px);
}
.lb-close {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: "Inter", sans-serif;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  padding: 9px 16px;
  border-radius: 30px;
  transition: color .3s, border-color .3s, background .3s;
}
.lb-close:hover, .lb-close:focus-visible {
  color: #000;
  background: var(--ink);
  border-color: var(--ink);
  outline: none;
}
.lb-close:focus-visible { box-shadow: 0 0 0 3px rgba(255, 255, 255, .35); }
.lb-close svg { width: 14px; height: 14px; }

.lb-stage {
  flex: 1 1 auto;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 clamp(56px, 9vw, 120px);
  min-height: 0;
}
.lb-figure {
  position: relative;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lb-figure img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;   /* show the photo WHOLE */
  display: block;
  border-radius: 6px;
  box-shadow: 0 30px 90px -40px rgba(0, 0, 0, .95);
  opacity: 0;
  transition: opacity .5s var(--ease);
}
.lb-figure img.loaded { opacity: 1; }
.lb-load {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--faint);
}
.lb-figure img.loaded ~ .lb-load { opacity: 0; }

.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  appearance: none;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, .35);
  color: var(--ink);
  width: 46px;
  height: 46px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .3s, border-color .3s, transform .25s;
  z-index: 3;
}
.lb-nav svg { width: 20px; height: 20px; }
.lb-nav:hover, .lb-nav:focus-visible {
  background: var(--ink);
  color: #000;
  border-color: var(--ink);
  outline: none;
}
.lb-nav:focus-visible { box-shadow: 0 0 0 3px rgba(255, 255, 255, .35); }
.lb-nav.prev { left: clamp(10px, 2.4vw, 30px); }
.lb-nav.next { right: clamp(10px, 2.4vw, 30px); }
.lb-nav:disabled { opacity: .25; cursor: default; pointer-events: none; }

.lb-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: clamp(10px, 1.6vh, 18px) 24px clamp(18px, 3vh, 32px);
  min-height: 34px;
}
.lb-foot .lb-count {
  font-size: 11px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.lb-foot .lb-caption {
  font-size: 10.5px;
  letter-spacing: .06em;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion: reduce) {
  .media-inner { transform: scale(1.02) !important; transition: none !important; }
  .bottom .date .word,
  .bottom .suffix,
  .bottom .actions {
    transition: opacity .3s ease !important;
    transform: none !important;
  }
  .gv-cell:hover .gv-thumb, .gv-cell:focus-visible .gv-thumb { transform: none !important; }
  .hint .mouse::after { animation: none; }
  * { scroll-behavior: auto !important; }
}

/* ============ FULL-SCREEN GRID / INDEX ============ */
#gridview {
  position: fixed;
  inset: 0;
  z-index: 75;
  background: rgba(6, 6, 8, .94);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .4s var(--ease), visibility .4s;
  display: flex;
  flex-direction: column;
}
#gridview.open { opacity: 1; visibility: visible; }

.gv-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: clamp(16px, 3vh, 28px) clamp(16px, 5vw, 48px) clamp(8px, 1.4vh, 14px);
}
.gv-title { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; min-width: 0; }
.gv-label {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.4rem, 3vw, 2.1rem);
  color: var(--ink);
}
.gv-sub {
  font-family: "Inter", sans-serif;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.gv-close {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: "Inter", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  padding: 9px 16px;
  border-radius: 30px;
  transition: background .25s, color .25s, border-color .25s;
}
.gv-close:hover, .gv-close:focus-visible {
  background: var(--ink); color: #000; border-color: var(--ink); outline: none;
}
.gv-close:focus-visible { box-shadow: 0 0 0 3px rgba(255, 255, 255, .35); }
.gv-close svg { width: 14px; height: 14px; }

.gv-years {
  flex: 0 0 auto;
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  padding: 0 clamp(16px, 5vw, 48px) clamp(12px, 1.6vh, 18px);
}
.gv-year-chip {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font-family: "Inter", sans-serif;
  font-size: 11px;
  letter-spacing: .1em;
  font-variant-numeric: tabular-nums;
  padding: 4px 11px;
  border-radius: 30px;
  transition: background .25s, color .25s, border-color .25s;
}
.gv-year-chip:hover, .gv-year-chip:focus-visible {
  background: var(--ink); color: #000; border-color: var(--ink); outline: none;
}

.gv-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain; /* don't chain scroll to the immersive view behind */
  -webkit-overflow-scrolling: touch;
  padding: 0 clamp(16px, 5vw, 48px) clamp(24px, 6vh, 60px);
}
.gv-year { margin-top: clamp(6px, 1.4vh, 16px); }
.gv-year-head {
  position: sticky;
  top: 0;
  z-index: 2;
  margin: 0 0 12px;
  padding: 10px 0;
  font-family: "Fraunces", Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.1rem, 2.4vw, 1.6rem);
  color: var(--ink);
  background: linear-gradient(to bottom, rgba(6, 6, 8, .97) 62%, rgba(6, 6, 8, 0));
  display: flex;
  align-items: baseline;
  gap: 12px;
}
.gv-year-count {
  font-family: "Inter", sans-serif;
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.gv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(clamp(120px, 18vw, 220px), 1fr));
  gap: clamp(8px, 1vw, 14px);
}
.gv-cell {
  appearance: none;
  border: 0;
  padding: 0;
  margin: 0;
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border-radius: 4px;
  background: rgba(255, 255, 255, .04);
  cursor: pointer;
  outline: none;
}
.gv-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity .5s var(--ease), transform .6s var(--ease);
}
.gv-thumb.loaded { opacity: 1; }
.gv-cell:hover .gv-thumb, .gv-cell:focus-visible .gv-thumb { transform: scale(1.05); }
.gv-cap {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 20px 10px 8px;
  font-family: "Inter", sans-serif;
  font-size: 10.5px;
  letter-spacing: .04em;
  color: var(--ink);
  text-align: left;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .8);
  background: linear-gradient(to top, rgba(0, 0, 0, .72), rgba(0, 0, 0, 0));
  opacity: 0;
  transition: opacity .25s;
  pointer-events: none;
  font-variant-numeric: tabular-nums;
}
.gv-cell:hover .gv-cap, .gv-cell:focus-visible .gv-cap { opacity: 1; }
.gv-cell:focus-visible { box-shadow: 0 0 0 2px rgba(255, 255, 255, .55); }
.gv-cell.is-current { box-shadow: 0 0 0 2px var(--ink); }
.gv-cell.is-current .gv-cap { opacity: 1; }

/* ============ RESPONSIVE ============ */
@media (max-width: 680px) {
  .bottom .date { font-size: clamp(2rem, 9.5vw, 2.9rem); }
  .bottom { bottom: clamp(28px, 6vh, 64px); }
  .lb-stage { padding: 0 clamp(44px, 14vw, 64px); }
}
@media (max-width: 420px) {
  .brand .logo { width: clamp(108px, 34vw, 140px); }
  .bottom .meta { font-size: 10px; letter-spacing: .2em; }
}
