/* =============================================================
   ALTYNAI ZHORABAEVA — visual system
   Palette: white / ivory / ice-blue / cold blue / silver + gold glow
   ============================================================= */

@import url('https://fonts.googleapis.com/css2?family=Inter+Tight:wght@300;400;500;600;700&display=swap');

:root {
  /* surfaces — warm ivory rather than cool white */
  --white: #FFFFFF;
  --ivory: #FFF9F6;
  --paper: #FFF4EF;
  --cream: #FFEFE8;
  --mist:  #F8E2DA;
  --silver:#E9D3CB;

  /* ink — a deep warm black, never blue-black */
  --ink:    #181313;
  --ink-70: rgba(24, 19, 19, .74);
  --ink-45: rgba(24, 19, 19, .58);
  --ink-25: rgba(24, 19, 19, .30);
  --ink-10: rgba(24, 19, 19, .10);

  /* red — the accent, used sparingly; the page stays light */
  --crimson:      #C91F37;
  --crimson-deep: #A81830;
  --poppy:        #E33A3A;
  --scarlet:      #EF4B4B;
  --wine:         #7D1F32;
  --wine-deep:    #681B2B;
  --blush:        #FFF1EB;

  /* a warm metal that belongs with crimson, kept for the honours */
  --gold: #C79A55;
  --gold-soft: rgba(199, 154, 85, .35);

  /* glass — warm translucency with the faintest red refraction */
  --glass:        rgba(255, 252, 250, .58);
  --glass-strong: rgba(255, 252, 250, .80);
  --glass-line:   rgba(255, 255, 255, .72);
  --glass-edge:   rgba(24, 19, 19, .07);
  --glass-tint:   rgba(201, 31, 55, .05);

  /* shadows — warmed, so nothing casts a blue-grey */
  --sh-s: 0 2px 10px rgba(72, 26, 34, .06);
  --sh-m: 0 18px 50px -20px rgba(72, 26, 34, .20), 0 2px 8px rgba(72, 26, 34, .05);
  --sh-l: 0 60px 120px -40px rgba(72, 26, 34, .32), 0 8px 30px rgba(72, 26, 34, .07);
  --sh-glow: 0 0 90px rgba(201, 31, 55, .28);

  /* rhythm */
  --pad: clamp(20px, 5vw, 84px);
  --gap: clamp(56px, 12vh, 180px);
  --r-s: 14px;
  --r-m: 24px;
  --r-l: 34px;
  --r-xl: 46px;

  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-soft: cubic-bezier(.33, 1, .68, 1);
}


* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* clip (not hidden) — `hidden` would turn the root into a scroll
   container and kill every position:sticky in the stack */
html { -webkit-text-size-adjust: 100%; overflow-x: clip; }

body {
  font-family: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-weight: 400;
  color: var(--ink);
  background: var(--paper);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.02em;
}


img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
::selection { background: var(--poppy); color: #fff; }

/* soft ambient light for the whole document */
body::before {
  content: '';
  position: fixed; inset: 0;
  pointer-events: none; z-index: 0;
  background:
    radial-gradient(90vw 70vh at 12% -10%, rgba(255, 255, 255, .95), transparent 60%),
    radial-gradient(70vw 60vh at 100% 8%, rgba(201, 31, 55, .26), transparent 62%),
    radial-gradient(58vw 48vh at 6% 72%, rgba(201, 31, 55, .16), transparent 62%),
    radial-gradient(60vw 50vh at 50% 105%, rgba(199, 154, 85, .13), transparent 60%);
}

/* =============================================================
   PLACEHOLDER FRAME — stands in until real photography is uploaded
   ============================================================= */
.frame {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background:
    linear-gradient(152deg, #FFF6F2 0%, #FCE3DB 52%, #FFF1EA 100%);
  overflow: hidden;
}
.frame::before {
  content: '';
  position: absolute; inset: clamp(7px, 4%, 16px);
  border: 1px solid rgba(201, 31, 55, .38);
  border-radius: inherit;
}
.frame::after {
  content: '';
  position: absolute; inset: 0;
  background: repeating-linear-gradient(58deg,
    rgba(201, 31, 55, .075) 0 1px, transparent 1px 13px);
}
.frame span {
  position: relative; z-index: 1;
  font-size: 10px; font-weight: 500; letter-spacing: .3em; text-transform: uppercase;
  color: rgba(125, 31, 50, .58);
  padding: 6px 12px; border-radius: 999px;
  background: rgba(255, 255, 255, .62);
  border: 1px solid rgba(201, 31, 55, .22);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
/* on the deep-blue archive panel the frame flips to a night version */
.frame.dark { background: linear-gradient(152deg, #8E2033 0%, #5C1626 55%, #94233A 100%); }
.frame.dark::before { border-color: rgba(255, 255, 255, .30); }
.frame.dark::after { background: repeating-linear-gradient(58deg, rgba(255,255,255,.07) 0 1px, transparent 1px 13px); }
.frame.dark span { color: rgba(255, 255, 255, .78); background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .26); }

/* ---------- typography scale ---------- */
.eyebrow {
  font-size: clamp(10px, .78vw, 12px);
  font-weight: 500;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ink-45);
}
.display {
  font-size: clamp(44px, 8.4vw, 148px);
  font-weight: 500;
  line-height: .92;
  letter-spacing: -0.045em;
}
.h2 {
  font-size: clamp(30px, 4.6vw, 76px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.04em;
}
.h3 {
  font-size: clamp(19px, 1.7vw, 26px);
  font-weight: 500;
  letter-spacing: -0.03em;
}
.body {
  font-size: clamp(15px, 1.15vw, 18px);
  line-height: 1.62;
  color: var(--ink-70);
  font-weight: 400;
}
.mono {
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase; font-weight: 500;
}

/* reveal-on-scroll primitive */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity 1.1s var(--ease), transform 1.25s var(--ease);
  transition-delay: var(--d, 0s);
}
[data-reveal].in { opacity: 1; transform: none; }

/* The mask has to clip vertically for the slide-up reveal, but at
   line-height .92 it was also shaving ~15px off the ink top and bottom.
   Latin and Cyrillic without descenders got away with it; Kazakh did not —
   the tail of "ң" was cut, leaving what looked like "н". The padding widens
   the clip box and the negative margin puts the layout back where it was. */
.split-line {
  display: block;
  overflow: hidden;
  padding-block: .26em;
  margin-block: -.26em;
}
.split-line > span {
  display: block;
  transform: translateY(135%);
  transition: transform 1.25s var(--ease);
  transition-delay: var(--d, 0s);
}
.in .split-line > span, .split-line.in > span { transform: none; }

/* =============================================================
   NAV — glass pill
   ============================================================= */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px var(--pad);
  transition: transform .8s var(--ease), opacity .6s var(--ease);
  mix-blend-mode: normal;
}
.nav.hidden { transform: translateY(-140%); opacity: 0; pointer-events: none; }

.brand {
  font-size: clamp(12px, 1vw, 14px); font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  display: flex; align-items: center; gap: 10px;
}
.brand .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--crimson); box-shadow: 0 0 14px var(--crimson);
}

.nav-links {
  position: absolute; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 4px;
  padding: 6px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--glass-line);
  box-shadow: var(--sh-s), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(26px) saturate(180%);
  -webkit-backdrop-filter: blur(26px) saturate(180%);
}
.nav-links a {
  padding: 8px 16px; border-radius: 999px;
  font-size: 12.5px; font-weight: 500; letter-spacing: -0.01em;
  color: var(--ink-70);
  transition: color .4s var(--ease), background .4s var(--ease);
}
.nav-links a:hover { color: var(--ink); background: rgba(255,255,255,.8); }

.nav-right { display: flex; align-items: center; gap: 10px; }

/* language switcher */
.lang {
  display: flex; align-items: center; gap: 2px; padding: 5px;
  border-radius: 999px; position: relative;
  background: var(--glass);
  border: 1px solid var(--glass-line);
  box-shadow: var(--sh-s), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(26px) saturate(180%);
  -webkit-backdrop-filter: blur(26px) saturate(180%);
}
.lang .thumb {
  position: absolute; top: 5px; left: 5px; height: calc(100% - 10px);
  border-radius: 999px; background: var(--ink);
  transition: transform .65s var(--ease), width .65s var(--ease);
  z-index: 0;
}
.lang .lang-seg {
  position: relative; z-index: 1;
  padding: 7px 13px; border-radius: 999px;
  font-size: 11px; font-weight: 600; letter-spacing: .1em;
  color: var(--ink-45); transition: color .45s var(--ease);
}
.lang .lang-seg.active { color: #fff; }

/* the single cycling button — phones only */
.lang-cycle { display: none; }

@media (max-width: 900px) {
  /* three segments eat the whole bar on a phone; collapse to one control
     that steps ҚАЗ → РУС → ENG on each tap */
  .lang { padding: 0; background: none; border: 0; box-shadow: none; }
  .lang .lang-seg, .lang .thumb { display: none; }

  .lang-cycle {
    display: flex; align-items: center; gap: 7px;
    padding: 9px 15px 9px 12px; border-radius: 999px;
    background: var(--ink); color: #fff;
    box-shadow: 0 8px 22px -10px rgba(24, 19, 19, .65);
    transition: transform .45s var(--ease), background .45s var(--ease);
  }
  .lang-cycle:active { transform: scale(.94); background: var(--crimson-deep); }
  .lang-cycle svg { width: 15px; height: 15px; opacity: .8; flex: none; }
  .lang-cycle .lang-now {
    font-size: 11.5px; font-weight: 600; letter-spacing: .1em;
    min-width: 3.1em; text-align: left;
    font-variant-numeric: tabular-nums;
  }
  /* the label rolls over as the language steps */
  .lang-cycle.flip .lang-now { animation: lang-roll .5s var(--ease); }
  .lang-cycle.flip svg { animation: lang-spin .6s var(--ease); }
}
@keyframes lang-roll {
  0%   { opacity: 0; transform: translateY(9px); }
  100% { opacity: 1; transform: none; }
}
@keyframes lang-spin {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(180deg); }
}

.nav-cta {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 10px 20px; border-radius: 999px;
  font-size: 12px; font-weight: 500; white-space: nowrap;
  background: var(--ink); color: #fff;
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), padding .4s var(--ease);
  box-shadow: 0 8px 24px -10px rgba(24, 19, 19,.6);
}
.nav-cta svg { width: 15px; height: 15px; fill: currentColor; display: none; }
.nav-cta:hover { transform: translateY(-2px); background: var(--crimson-deep); box-shadow: 0 14px 34px -12px rgba(168, 24, 48,.55); }

/* =============================================================
   LOADING SCREEN
   Covers the finished page while the portrait decodes, then lifts. The
   site underneath is already laid out, so nothing assembles on reveal.
   ============================================================= */
body.boot-lock { overflow: hidden; }

#boot {
  position: fixed; inset: 0; z-index: 120;
  background: linear-gradient(168deg, #FFFCFA 0%, #FFF3EE 55%, #FFEEE6 100%);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 26px;
  transition: opacity .55s var(--ease);
}
#boot.gone { opacity: 0; pointer-events: none; }

.boot-mark {
  display: flex; align-items: center; gap: 11px;
  font-size: clamp(11px, 1vw, 13px); font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--ink);
  opacity: 0; animation: boot-in .9s var(--ease) .1s forwards;
}
.boot-mark .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--crimson); box-shadow: 0 0 16px var(--crimson);
}
@keyframes boot-in { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }

.boot-meter {
  width: min(220px, 46vw); height: 1px;
  background: rgba(24, 19, 19, .10);
  overflow: hidden;
  opacity: 0; animation: boot-in .9s var(--ease) .25s forwards;
}
.boot-meter i {
  display: block; width: 100%; height: 100%;
  background: linear-gradient(90deg, var(--crimson), var(--crimson-deep));
  transform: scaleX(0); transform-origin: 0 50%;
}
.boot-pct {
  font-size: 10px; letter-spacing: .3em; color: var(--ink-25);
  font-variant-numeric: tabular-nums;
  opacity: 0; animation: boot-in .9s var(--ease) .35s forwards;
}

/* The nav waits for the reveal so it never sits on top of the loader.
   Driven by a body class the loader sets rather than a bare `.nav` rule, so
   the rule cannot strand the nav on a page that never runs a loader. */
body.nav-hold .nav { opacity: 0; pointer-events: none; }

/* =============================================================
   BIOGRAPHY — a scroll-read, not an "about" block

   Layering is fixed and deliberate, because the first build let the
   hero's poppies sit on top of the copy:
     0  section ground
     1  the watermark year
     2  background poppies
     5  the timeline
     10 headings and text
   Nothing decorative is ever allowed above 2.
   ============================================================= */
#story { z-index: 5; }

/* Deliberately NOT a .stack section. The stack pins its members at 100vh and
   clips them, which flattened the 600svh scroll track inside to a single
   screen — that is what put two chapters on the page at once. This one runs
   at its natural height and does its pinning internally. */
.story {
  position: relative;
  z-index: 5;
  background: linear-gradient(180deg, var(--ivory) 0%, var(--paper) 46%, var(--ivory) 100%);
  padding: 0 var(--pad);
}
.story-bg {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(58vw 46vh at 82% 10%, rgba(201, 31, 55, .055), transparent 62%),
    radial-gradient(46vw 40vh at 4% 78%, rgba(125, 31, 50, .04), transparent 64%);
}

/* the year, set enormous and almost invisible — a watermark, not a heading */
.story-ghost {
  position: absolute; z-index: 1; right: -.04em; top: 26vh;
  font-size: clamp(150px, 26vw, 460px);
  font-weight: 600; letter-spacing: -.06em; line-height: .8;
  color: rgba(201, 31, 55, .05);
  pointer-events: none; user-select: none;
  transform: scale(.97);
  transition: opacity 1.1s var(--ease), transform 1.4s var(--ease);
}

/* ---------- background poppies ---------- */
.story-poppies { position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: clip; }
.sp {
  position: absolute;
  opacity: 0;                       /* raised per chapter, never above .24 */
  transition: opacity 1.2s var(--ease);
  will-change: transform;
}
.sp svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* ---------- the opening ---------- */
.story-open {
  position: relative; z-index: 10;
  padding: clamp(96px, 17vh, 210px) 0 clamp(60px, 10vh, 130px);
}
.story-name {
  font-size: clamp(3rem, 6vw, 7rem);
  font-weight: 500; line-height: .92; letter-spacing: -.05em;
  color: var(--ink);
}
.story-name .split-line + .split-line { color: var(--crimson); }
.story-label { color: var(--ink-45); margin-top: clamp(16px, 3vh, 30px); }

/* ---------- the pinned stage ---------- */
.story-track { position: relative; z-index: 10; }
.story-stage {
  position: sticky; top: 0;
  height: 100svh;
  display: grid; grid-template-columns: 104px minmax(0, 1fr);
  gap: clamp(18px, 3vw, 56px);
  align-items: center;
  /* the nav is fixed over the page; nothing may sit underneath it */
  padding: clamp(96px, 13vh, 150px) 0 clamp(40px, 8vh, 90px);
}

/* ---------- timeline ---------- */
.story-rail { position: relative; z-index: 5; align-self: center; height: min(58vh, 460px); }
.rail-line {
  position: absolute; left: 11px; top: 2px; bottom: 2px; width: 1px;
  background: rgba(24, 19, 19, .13);
}
.rail-line i {
  position: absolute; left: 0; top: 0; width: 100%; height: 0;
  background: linear-gradient(180deg, var(--crimson), var(--wine));
  transition: height .2s linear;
}
.rail-years {
  list-style: none; height: 100%;
  display: flex; flex-direction: column; justify-content: space-between;
}
.rail-years li {
  position: relative; padding-left: 26px;
  font-size: 11px; letter-spacing: .14em; font-variant-numeric: tabular-nums;
  color: var(--ink); opacity: .25;
  transition: opacity .5s var(--ease), color .5s var(--ease), transform .5s var(--ease);
}
.rail-years li::before {
  content: ''; position: absolute; left: 8px; top: 50%; width: 7px; height: 7px;
  margin-top: -3.5px; border-radius: 50%; background: var(--silver);
  transition: background .5s var(--ease), transform .5s var(--ease);
}
.rail-years li.on { opacity: 1; color: var(--crimson); transform: translateX(3px); }
.rail-years li.on::before { background: var(--crimson); transform: scale(1.35); }

/* ---------- chapters, stacked and cross-faded ---------- */
.story-chapters { position: relative; z-index: 10; height: 100%; }
.chapter {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  /* the safe reading zone: copy stays left of centre, poppies keep to the
     edges, so nothing decorative ever lands under a line of text */
  max-width: min(62ch, 46vw);
  opacity: 0;
  transform: translateY(40px);
  filter: blur(8px);
  pointer-events: none;
  transition: opacity .5s var(--ease), transform .6s var(--ease), filter .5s var(--ease);
}
.chapter.on { opacity: 1; transform: none; filter: none; pointer-events: auto; }
.chapter.out { opacity: 0; transform: translateY(-30px); filter: blur(6px); }

.ch-head { display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; margin-bottom: clamp(14px, 2.4vh, 28px); }
.ch-no { font-size: 12px; letter-spacing: .28em; color: var(--crimson); font-variant-numeric: tabular-nums; }
.ch-period { font-size: 12px; letter-spacing: .2em; color: var(--ink-45); text-transform: uppercase; }
.ch-title {
  flex: 1 1 100%;
  font-size: clamp(2.1rem, 4.4vw, 4.4rem);
  font-weight: 500; line-height: 1.03; letter-spacing: -.04em;
  color: var(--ink);
}
.ch-title em { font-style: normal; color: var(--crimson); }
.ch-text {
  font-size: clamp(1.05rem, 1.45vw, 1.65rem);
  line-height: 1.5;
  color: rgba(24, 19, 19, .62);
  max-width: 60ch;
}
.ch-text b { font-weight: 500; color: var(--ink); }

/* ---------- archival prints in a chapter ----------
   The photographs enter and leave with the chapter that owns them, but on
   their own curve: the outgoing frame settles back and tips one way, the
   incoming one arrives from the other. Because both states are written
   against `.chapter.on` / `.chapter.out`, they are driven by the same scroll
   position as the text and cannot drift out of step with it. */
.ch-shots {
  display: flex; gap: clamp(12px, 1.8vw, 26px);
  margin-top: clamp(20px, 3.4vh, 40px);
}
.ch-shot {
  overflow: hidden;
  opacity: 0;
  transform: scale(.94) rotate(2deg);
  transition: opacity .62s var(--ease), transform .78s var(--ease);
  transition-delay: calc(var(--i, 0) * .07s);
}
.chapter.on .ch-shot { opacity: 1; transform: scale(1) rotate(var(--tilt, 0deg)); }
.chapter.out .ch-shot { opacity: 0; transform: scale(.94) rotate(-2deg); }
.ch-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ch-shot.a { width: clamp(120px, 13vw, 190px); aspect-ratio: 3/4; --i: 0; }
.ch-shot.b { width: clamp(100px, 11vw, 150px); aspect-ratio: 3/4; align-self: flex-end; --i: 1; }
.ch-shot.c { width: clamp(88px, 9.5vw, 128px); aspect-ratio: 3/4; align-self: center; --i: 2; }
@media (hover: hover) and (pointer: fine) {
  .chapter.on .ch-shot:hover {
    transform: scale(1.03) rotate(calc(var(--tilt, 0deg) * .4));
    box-shadow: 0 30px 60px -22px rgba(72, 26, 34, .42);
  }
}

@media (max-width: 900px) {
  .story-stage {
    grid-template-columns: 46px minmax(0, 1fr);
    gap: 12px;
    padding: clamp(84px, 12vh, 110px) 0 clamp(30px, 6vh, 60px);
  }
  .story-rail { height: min(52vh, 380px); }
  .rail-years li { font-size: 9.5px; letter-spacing: .06em; padding-left: 18px; }
  .rail-line { left: 6px; }
  .rail-years li::before { left: 3px; width: 6px; height: 6px; margin-top: -3px; }
  .chapter { max-width: none; }
  .story-ghost { font-size: clamp(120px, 40vw, 240px); top: 30vh; }
  .ch-shot.a { width: 38vw; }
  .ch-shot.b { width: 30vw; }
  /* the blur costs more than it gives at this size */
  .chapter { filter: none; transform: translateY(24px); }
  .chapter.out { filter: none; }
}

/* -------------------------------------------------------------
   BIOGRAPHY ON A PHONE — the same chapters, a different gesture

   On desktop this section pins itself and spends six screens of scroll
   playing a timeline. On a phone that is a trap: a reader who does not
   want the biography still has to swipe six times to get out of it.

   So below 768px the pin is simply never built — `.story-track` keeps its
   natural height (the JS does not set the 600svh) and the stage stops being
   sticky. The chapters become a horizontal scroll-snap strip: native scroll,
   no touch handlers, no preventDefault anywhere. The browser resolves which
   axis the finger meant, so an upward swipe always belongs to the page and
   a sideways one always belongs to the story.

   `.is-mobile` is set by the JS when it mounts this mode, so these rules
   need both it and the media query to apply — desktop cannot be reached
   by either alone.
   ------------------------------------------------------------- */

/* phone-only furniture, absent from the desktop read */
.story-kicker, .story-cta, .story-hint, .story-prog { display: none; }

@media (max-width: 767px) {

  /* ---------- the way in ---------- */
  .story-open {
    display: flex; flex-direction: column; align-items: flex-start;
    padding: clamp(80px, 14vh, 130px) 0 clamp(26px, 5vh, 44px);
  }
  /* the date sits above the name here, as a dateline does */
  .story-label { order: -1; margin-top: 0; margin-bottom: 14px; }
  .story-name { font-size: clamp(2.9rem, 13vw, 4.4rem); }

  .story-kicker {
    display: block; margin-top: 18px;
    font-size: clamp(1.15rem, 5vw, 1.5rem);
    font-weight: 500; letter-spacing: -.02em;
    color: var(--crimson);
  }
  .story-cta {
    display: inline-flex; align-items: center; gap: 9px;
    margin-top: 20px; padding: 11px 20px 11px 18px;
    font: inherit; font-size: 13.5px; letter-spacing: .02em;
    color: var(--ink); cursor: pointer;
    background: rgba(255, 255, 255, .66);
    border: 1px solid rgba(201, 31, 55, .22);
    border-radius: 999px;
    -webkit-tap-highlight-color: transparent;
  }
  .story-cta::after {
    content: '→'; color: var(--crimson);
    transition: transform .35s var(--ease);
  }
  .story-cta:active::after { transform: translateX(3px); }
  .story-hint {
    display: block; margin-top: 16px;
    font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
    color: var(--ink-45);
  }
  .story-hint::before { content: '← '; }
  .story-hint::after  { content: ' →'; }

  .story-ghost { font-size: clamp(110px, 36vw, 200px); top: 16vh; }

  /* ---------- the pin, removed ---------- */
  /* height is cleared by the JS on unmount too; this is the guarantee that
     no stale inline value can leave six empty screens behind on a phone */
  .is-mobile .story-track { height: auto !important; }
  .is-mobile .story-stage {
    position: static;
    display: block;
    height: auto;
    padding: 0 0 clamp(26px, 6vh, 48px);
  }
  /* the full-section poppy layer belongs to the pinned read; on a phone the
     flowers live on the cards instead */
  .is-mobile .story-poppies { display: none; }

  /* ---------- timeline, turned on its side ---------- */
  .is-mobile .story-rail {
    height: auto; padding: 0; margin: 0 0 18px;
    overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .is-mobile .story-rail::-webkit-scrollbar { display: none; }
  .is-mobile .rail-years {
    flex-direction: row; justify-content: flex-start;
    align-items: flex-end; gap: 22px; height: auto;
    width: max-content; min-width: 100%;
  }
  /* the hairline that joins the dots, level with their centres */
  .is-mobile .rail-line {
    left: 10px; right: 10px; top: auto; bottom: 3.5px;
    width: auto; height: 1px;
  }
  .is-mobile .rail-line i { display: none; }   /* progress lives in .sp-line */
  .is-mobile .rail-years li {
    padding: 0; opacity: 1; transform: none;
  }
  .is-mobile .rail-years li::before { display: none; }
  .is-mobile .rail-years li button {
    display: grid; justify-items: center; gap: 7px;
    padding: 0; border: 0; background: none; cursor: pointer;
    font: inherit; font-size: 11px; letter-spacing: .1em;
    font-variant-numeric: tabular-nums;
    color: var(--ink); opacity: .3;
    -webkit-tap-highlight-color: transparent;
    transition: opacity .4s var(--ease), color .4s var(--ease);
  }
  .is-mobile .rail-years li button::after {
    content: ''; width: 7px; height: 7px; border-radius: 50%;
    background: var(--silver);
    transition: background .4s var(--ease), transform .4s var(--ease);
  }
  .is-mobile .rail-years li.on button { opacity: 1; color: var(--crimson); }
  .is-mobile .rail-years li.on button::after {
    background: var(--crimson); transform: scale(1.35);
  }

  /* ---------- the chapters, swiped ---------- */
  .is-mobile .story-chapters {
    display: flex; gap: 14px; height: auto;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    /* a swipe that runs off the end must not chain into the page or trigger
       the browser's back gesture */
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* the side padding is what lets the first and last card reach the centre */
    padding: 4px 7vw 12px;
  }
  .is-mobile .story-chapters::-webkit-scrollbar { display: none; }

  .is-mobile .chapter {
    position: relative; inset: auto;
    flex: 0 0 86vw; max-width: none;
    scroll-snap-align: center;
    display: flex; flex-direction: column; justify-content: flex-start;
    min-height: 60svh;
    padding: 26px 22px 30px;
    border-radius: var(--r-l);
    /* paper, not a product card: a warm wash and a hairline, no elevation */
    background: linear-gradient(168deg, rgba(255,255,255,.74), rgba(255,241,235,.52));
    border: 1px solid rgba(201, 31, 55, .11);
    overflow: hidden;                 /* the card's poppies crop to its edge */
    pointer-events: auto;
    /* opacity and scale are written inline from the scroll position, so a
       transition here would only lag the finger */
    opacity: 1; transform: none; filter: none; transition: none;
    will-change: transform, opacity;
  }
  /* the desktop cross-fade classes must not reach this mode */
  .is-mobile .chapter.on, .is-mobile .chapter.out {
    opacity: 1; transform: none; filter: none;
  }

  .is-mobile .ch-head {
    display: flex; flex-direction: column; align-items: flex-start;
    gap: 10px; margin-bottom: 16px;
  }
  .is-mobile .ch-title { flex: 0 1 auto; font-size: clamp(1.9rem, 8.4vw, 2.7rem); }
  .is-mobile .ch-text { font-size: 15.5px; line-height: 1.58; }
  .is-mobile .ch-head, .is-mobile .ch-text, .is-mobile .ch-shots {
    position: relative; z-index: 1;          /* above the card's poppies */
  }
  .is-mobile .ch-shots { margin-top: auto; padding-top: 22px; }
  .is-mobile .ch-shot.a { width: 34vw; }
  .is-mobile .ch-shot.b { width: 27vw; }
  /* a card is not a gallery: the second print tucks behind the first rather
     than standing beside it, and there is never a third */
  .is-mobile .ch-shots.stacked { position: relative; }
  .is-mobile .ch-shots.stacked .ch-shot.b {
    position: absolute; left: 21vw; bottom: 8px; z-index: -1;
  }
  .is-mobile .ch-shot.c { display: none; }
  /* the chapters do not cross-fade here, so the prints must simply be on */
  .is-mobile .ch-shot { opacity: 1; transform: rotate(var(--tilt, 0deg)); }

  /* a poppy at the card's edge, never under the paragraph */
  .ch-poppy { position: absolute; z-index: 0; pointer-events: none; }
  .ch-poppy svg { display: block; width: 100%; height: 100%; overflow: visible; }

  /* ---------- progress ---------- */
  .is-mobile .story-prog {
    display: flex; align-items: center; gap: 14px;
    margin-top: 18px; padding: 0 2px;
  }
  .sp-count {
    font-size: 11px; letter-spacing: .18em;
    font-variant-numeric: tabular-nums; color: var(--ink-45);
  }
  .sp-count b { color: var(--crimson); font-weight: 500; }
  .sp-count i { font-style: normal; }
  .sp-line {
    position: relative; flex: 1; height: 1px;
    background: rgba(24, 19, 19, .13);
  }
  .sp-line i {
    position: absolute; left: 0; top: 0; height: 100%; width: 0;
    background: linear-gradient(90deg, var(--crimson), var(--wine));
    transition: width .18s linear;
  }
}

/* the depth effect is written inline, so switching it off has to outrank it */
@media (prefers-reduced-motion: reduce) {
  .is-mobile .chapter { transform: none !important; opacity: 1 !important; }
}

/* =============================================================
   HERO DISSOLVE
   Full-viewport canvas so the blooms can leave the picture's box. It sits
   just above the hero and below every following chapter, which is what
   lets the next section rise through the thinning flowers.
   ============================================================= */
#dissolveCv {
  position: fixed; inset: 0; z-index: 5;
  pointer-events: none;
  will-change: transform;
}
/* the real <img> is only hidden while the effect is mid-flight; at rest the
   page is back to a plain photograph */
.hero-portrait.dissolving img { transition: opacity .18s linear; }

/* =============================================================
   HERO
   ============================================================= */
.hero {
  position: relative; z-index: 2;
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  padding: 120px var(--pad) 90px;
  overflow: hidden;
}
.hero-portrait {
  position: relative;
  /* Bounded on BOTH axes so the 3:4 always survives — the intro card lands
     on this exact rectangle, and a squashed portrait would break the match. */
  width: min(46vw, 520px, 49.5vh);
  height: auto;
  aspect-ratio: 3 / 4;
  flex: none;
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--sh-l), inset 0 0 0 1px rgba(255,255,255,.6);
  will-change: transform;
}
.hero-portrait img { width: 100%; height: 100%; object-fit: cover; }

/* Background-free portrait: no card, no crop — the figure itself is the shape,
   so the frame, the glass sheen and the box-shadow all have to go, and the
   depth comes from a drop-shadow that follows the alpha edge. */
.hero-portrait.cutout {
  background: none;
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
  width: min(56vw, 620px, 62vh);
  aspect-ratio: auto;
  height: min(72vh, 720px);
}
.hero-portrait.cutout::after { display: none; }
.hero-portrait.cutout img {
  object-fit: contain;
  filter: drop-shadow(0 40px 60px rgba(72, 26, 34,.28))
          drop-shadow(0 4px 14px rgba(72, 26, 34,.10));
}
.hero-portrait::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(140deg, rgba(255,255,255,.34), transparent 40%, rgba(248, 210, 200,.20));
  mix-blend-mode: screen;
}
.hero-glow {
  position: absolute; left: 50%; top: 50%;
  width: min(92vw, 1000px); aspect-ratio: 1; transform: translate(-50%, -50%);
  background:
    radial-gradient(46% 46% at 50% 50%, rgba(199, 154, 85,.20), transparent 62%),
    radial-gradient(58% 58% at 50% 50%, rgba(201, 31, 55,.20), transparent 66%);
  filter: blur(20px); pointer-events: none;
}

/* Typography sits above every poppy layer. The front layer is z-index 12, so
   at z-index 4 the copy was literally underneath it — measured at 93%% of the
   headline covered by one bloom. Composition keeps the flowers clear of the
   words; this makes sure they can never be on top of them either. */
.hero-copy {
  position: absolute; left: var(--pad); bottom: clamp(60px, 10vh, 120px);
  max-width: min(38vw, 460px); z-index: 13;
}
.hero-copy .display { color: #171111; line-height: .86; }
.hero-copy .eyebrow {
  font-size: clamp(11px, .85vw, 15px);
  letter-spacing: .22em;
  font-weight: 500;
  color: rgba(23, 17, 17, .74);
}
.hero-copy .display { margin: 14px 0 18px; }
.hero-meta {
  position: absolute; right: var(--pad); bottom: clamp(60px, 10vh, 120px);
  text-align: right; z-index: 13; max-width: 300px;
}
.hero-meta .body {
  font-size: clamp(14px, 1vw, 18px) !important;
  line-height: 1.45;
  color: rgba(23, 17, 17, .78);
}
.scroll-cue .mono { color: rgba(23, 17, 17, .72); }
.scroll-cue .rail { background: rgba(23, 17, 17, .22); }
.scroll-cue {
  position: absolute; left: 50%; bottom: 30px; transform: translateX(-50%);
  z-index: 13;
  display: flex; flex-direction: column; align-items: center; gap: 10px; z-index: 4;
}
.scroll-cue .rail {
  width: 1px; height: 46px; background: linear-gradient(var(--ink-25), transparent);
  position: relative; overflow: hidden;
}
.scroll-cue .rail::after {
  content: ''; position: absolute; inset: 0; background: var(--ink);
  animation: railRun 2.4s var(--ease) infinite;
}
@keyframes railRun { 0% { transform: translateY(-100%); } 60%, 100% { transform: translateY(100%); } }

/* =============================================================
   FLOWERS — persistent living layer
   ============================================================= */
#flowers {
  position: fixed; inset: 0; z-index: 2;   /* behind the transparent hero */
  pointer-events: none;
  overflow: hidden;
}
#flowers .fl {
  position: absolute;
  will-change: transform, opacity;
  transform-origin: 50% 50%;
}
#flowers svg { display: block; overflow: visible; }

/* Text safe zones, carved out of the flower layers themselves.

   Per-bloom masks were tried first and did not hold: each one is anchored to
   its own flower, so a bloom only has to drift for the hole to stop lining up
   with the words — measured 0.54 average ink over the headline and peaks of
   1.58 over the description where two blooms stacked.

   These are anchored to the copy instead. Two soft ellipses sit exactly where
   the headline and the description live; `intersect` keeps the layer only
   where both are opaque, so the flowers thin out over the words and stay
   fully saturated everywhere else.

   The stop positions matter as much as the radii. The headline box runs from
   45% to 95% of the viewport height, so a gradient that starts ramping at 26%
   of its radius is already fully opaque by the time it reaches the first line
   -- measured alpha 1.0 across the whole top band. Holding it clear to 62% and
   ramping only over the outer third covers the box without spreading the
   faded area any wider. */
#flowers, #flowers-front {
  -webkit-mask-image:
    radial-gradient(38% 52% at 23% 70%, transparent 0%, transparent 62%, #000 100%),
    radial-gradient(26% 24% at 82% 89%, transparent 0%, transparent 58%, #000 100%);
  mask-image:
    radial-gradient(38% 52% at 23% 70%, transparent 0%, transparent 62%, #000 100%),
    radial-gradient(26% 24% at 82% 89%, transparent 0%, transparent 58%, #000 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* On a phone the copy is centred and static, so the protected area moves
   with it: one wide, low ellipse instead of two corners.

   Sized to the measured box rather than guessed. The headline occupies
   18%-82% across and 72%-87% down, so the ellipse is wide and shallow — an
   earlier version was 36% tall, nearly five times the height of the text it
   was protecting, and it erased 61% of the one large bloom the composition
   is built around. The vertical radius carries enough margin for a headline
   that runs to three lines in another language. */
@media (max-width: 767px) {
  #flowers, #flowers-front {
    -webkit-mask-image:
      radial-gradient(80% 22% at 50% 79.5%, transparent 0%, transparent 58%, #000 100%);
    mask-image:
      radial-gradient(80% 22% at 50% 79.5%, transparent 0%, transparent 58%, #000 100%);
  }
}

#flowers-front .fl { position: absolute; transform-origin: 50% 50%; }
#flowers-front svg { display: block; overflow: visible; }

/* Compositor-only drift, used instead of the JS loop on phones. Keeping the
   whole animation to transform means it never touches layout or paint.

   Deliberately small. This is the only continuous motion left on a phone, and
   at 18px of travel with four degrees of roll it read as the page wobbling
   rather than as air moving through a field. Half that, over a longer cycle,
   reads as wind. */
.fl.drift {
  will-change: transform;
  animation-name: fl-drift;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
@keyframes fl-drift {
  from { transform: translate3d(0, 0, 0) rotate(-1.8deg) scale(.986); }
  to   { transform: translate3d(0, -8px, 0) rotate(1.8deg) scale(1.014); }
}

/* A loose petal keeps the angle it was dropped at, so its sway has to be
   written around that resting rotation rather than replacing it. */
.fl.pt.drift { animation-name: pt-drift; }
@keyframes pt-drift {
  from { transform: translate3d(0, 0, 0) rotate(calc(var(--rot) - 3deg)) scale(.98); }
  to   { transform: translate3d(0, -7px, 0) rotate(calc(var(--rot) + 3deg)) scale(1.02); }
}
/* no resting angle set (desktop never builds petals) — degrade to no tilt */
.fl.pt { --rot: 0deg; }
#flower-video {
  position: fixed; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 3; pointer-events: none;
  mix-blend-mode: multiply; opacity: .38; filter: saturate(.7) brightness(1.25);
}

/* =============================================================
   STACK — every section pins to the top, the next one rides over it
   ============================================================= */
/* Every chapter is exactly one screen tall. That is what makes the stack
   work: a sticky box taller than the viewport would hide its own tail. */
.stack {
  position: sticky; top: 0;
  height: 100svh; min-height: 560px;
  display: flex; flex-direction: column; justify-content: center;
  border-radius: clamp(20px, 2.6vw, 42px) clamp(20px, 2.6vw, 42px) 0 0;
  box-shadow: 0 -34px 90px -34px rgba(72, 26, 34, .28), 0 -1px 0 rgba(255, 255, 255, .8);
  overflow: hidden;
  isolation: isolate;
  will-change: transform;
}
/* the covered section quietly falls away underneath */
.stack > * { transition: none; }
.stack-inner { width: 100%; }

/* .section / .music / .footer also set `position`, so win the cascade back */
.hero.stack, .section.stack, .music.stack, .footer.stack {
  position: sticky; top: 0;
}

/* explicit paint order: each later section sits on top of the last */
#hero    { z-index: 4; }
#about   { z-index: 5; }
#archive { z-index: 6; }
#music   { z-index: 7; }
#films   { z-index: 8; }
#awards  { z-index: 9; }
#live    { z-index: 10; }
#footer  { z-index: 11; }

/* the first one owns the top of the page — no lip, and it lets the
   flower layer behind it show through */
#hero.stack { border-radius: 0; box-shadow: none; background: transparent; overflow: visible; }

/* opaque tones so a section genuinely hides the one below */
.tone-a { background: linear-gradient(180deg, #FFFFFF 0%, #FFF7F2 100%); }
.tone-b { background: linear-gradient(180deg, #FFFFFF 0%, #FFF2EC 100%); }
.tone-c { background: linear-gradient(170deg, #FFF8F4 0%, #FFEBE3 100%); }

/* the archive chapter carries the flag blue and hands it to the panel */
#archive.stack {
  background: linear-gradient(168deg, #C91F37 0%, #A81830 55%, #7D1F32 100%);
  color: #fff;
}
#archive .eyebrow, #archive .mono { color: rgba(255, 255, 255, .72); }
#archive .h2 { color: #fff; }
.tone-d { background: linear-gradient(180deg, #FFF9F6 0%, #FFF2EB 100%); }
.tone-e { background: linear-gradient(180deg, #FFF7F2 0%, #FFE8DF 100%); }
.tone-f { background: linear-gradient(180deg, #FFF2EC 0%, #FFFFFF 100%); }
/* the awards room: ivory warmed by the gold the honours carry */
.tone-g { background: linear-gradient(172deg, #FFFBF8 0%, #FFF5F0 46%, #FFF0E9 100%); }

/* =============================================================
   AWARDS — a horizontal cabinet of honours
   ============================================================= */
#awards.stack { overflow: hidden; }
#awards .sec-head { align-items: flex-end; }
.aw-count { color: var(--ink-25); white-space: nowrap; }
.aw-count span:first-child { color: var(--gold); font-weight: 600; }

/* the rail itself */
.aw-rail {
  display: flex; gap: clamp(14px, 1.6vw, 26px);
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory;
  padding: 6px calc(var(--pad)) 26px 0;
  margin-right: calc(var(--pad) * -1);
  scrollbar-width: none;
  cursor: grab;
  overscroll-behavior-x: contain;   /* never hand the swipe to the page */
}
.aw-rail::-webkit-scrollbar { display: none; }
.aw-rail.drag { cursor: grabbing; scroll-snap-type: none; }

.aw-card {
  position: relative; flex: 0 0 auto;
  width: clamp(232px, 23vw, 316px);
  scroll-snap-align: start;
  display: flex; flex-direction: column;
  border-radius: var(--r-m);
  background: var(--glass-strong);
  border: 1px solid var(--glass-line);
  box-shadow: var(--sh-m), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);
  overflow: hidden;
  transition: transform .7s var(--ease), box-shadow .7s var(--ease);
}
.aw-card:hover { transform: translateY(-8px); box-shadow: var(--sh-l), inset 0 1px 0 rgba(255,255,255,.95); }

/* the picture slot — a frame until the photographs arrive */
.aw-shot { position: relative; aspect-ratio: 4 / 3; overflow: hidden; flex: none; }
.aw-shot img { width: 100%; height: 100%; object-fit: cover; }

.aw-year {
  position: absolute; left: 14px; top: 14px; z-index: 2;
  padding: 5px 11px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; letter-spacing: .06em;
  font-variant-numeric: tabular-nums;
  color: #fff; background: rgba(24, 19, 19, .62);
  border: 1px solid rgba(255,255,255,.34);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}

/* the accent ribbon reads the kind of honour at a glance */
.aw-kind {
  position: absolute; right: 14px; top: 14px; z-index: 2;
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255,255,255,.82); border: 1px solid rgba(255,255,255,.7);
  box-shadow: var(--sh-s);
}
.aw-kind svg { width: 14px; height: 14px; }
.aw-card[data-kind="state"] .aw-kind svg { fill: var(--gold); }
.aw-card[data-kind="grand"] .aw-kind svg { fill: #B07B2C; }
.aw-card[data-kind="prize"] .aw-kind svg { fill: var(--crimson-deep); }

.aw-card::after {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 3px; z-index: 3;
  background: linear-gradient(90deg, var(--crimson), var(--scarlet));
}
.aw-card[data-kind="state"]::after { background: linear-gradient(90deg, var(--gold), #EEDCB6); }
.aw-card[data-kind="grand"]::after { background: linear-gradient(90deg, #B07B2C, var(--gold), #F3E4C4); }

.aw-body { padding: 18px 20px 22px; display: flex; flex-direction: column; gap: 9px; flex: 1; }
.aw-title {
  font-size: 15.5px; font-weight: 600; line-height: 1.32; letter-spacing: -.02em;
  text-wrap: balance;                 /* stop a lone word dangling on line 4 */
  overflow-wrap: anywhere;            /* long Kazakh compounds must break */
}
.aw-place {
  font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase;
  line-height: 1.4; color: var(--wine); font-weight: 600;
  padding-bottom: 3px; border-bottom: 1px solid rgba(201, 31, 55, .18);
}
.aw-text { font-size: 13.5px; line-height: 1.62; color: var(--ink-70); }

.aw-hint {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  color: var(--ink-25); margin-top: 4px;
}
.aw-arrows { display: flex; gap: 8px; }
.aw-nav {
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center; color: var(--ink-70);
  background: var(--glass-strong); border: 1px solid var(--glass-line);
  box-shadow: var(--sh-s);
  transition: transform .5s var(--ease), background .4s var(--ease), color .4s var(--ease);
}
.aw-nav svg { width: 19px; height: 19px; }
.aw-nav:hover { background: var(--crimson-deep); color: #fff; transform: scale(1.08); }
.aw-nav:active { transform: scale(.93); }
.aw-nav[disabled] { opacity: .3; pointer-events: none; }

/* =============================================================
   SECTIONS shell
   ============================================================= */
.section { position: relative; z-index: 4; padding: var(--gap) var(--pad); }
.section.stack { padding: clamp(80px, 11vh, 128px) var(--pad) clamp(34px, 6vh, 66px); }
.stack .sec-head { margin-bottom: clamp(22px, 4vh, 54px); }
.sec-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 32px; margin-bottom: clamp(36px, 6vh, 84px); }
.sec-head .left { max-width: 60ch; }
.sec-head .eyebrow { margin-bottom: 18px; }

/* ABOUT */
.about { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(30px, 6vw, 96px); align-items: center; }
.about-figure {
  position: relative; border-radius: var(--r-l); overflow: hidden;
  aspect-ratio: 4/5; height: min(62vh, 620px); width: 100%; margin-left: auto;
  box-shadow: var(--sh-m);
}
.about-figure img { width: 100%; height: 100%; object-fit: cover; }
.stats { display: flex; gap: clamp(20px, 4vw, 60px); margin-top: clamp(22px, 4vh, 44px); flex-wrap: wrap; }
.stat .n { font-size: clamp(32px, 4vw, 58px); font-weight: 500; letter-spacing: -0.05em; line-height: 1; }
.stat .l { font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-45); margin-top: 10px; }

/* =============================================================
   GALLERY — faithful port of the reference scroll engine
   ============================================================= */
/* The whole archive block shares z-index 6 with the #archive chapter and
   sits after it in the DOM, so it covers it — while #music (z 7) is free
   to ride over the top of the archive on the way out. */
#gal-spacer { position: relative; z-index: 6; user-select: none; }

#gal-panel {
  position: fixed; inset: 0; z-index: 1;
  background: var(--wine);
  overflow: hidden;
  transform: translateY(100vh);
  will-change: transform;
  visibility: hidden;
}
#gal-panel.live { visibility: visible; }
#gal-panel::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background:
    radial-gradient(60vw 50vh at 12% 0%, rgba(201, 31, 55,.55), transparent 62%),
    radial-gradient(50vw 45vh at 92% 92%, rgba(199, 154, 85,.15), transparent 60%);
}
/* the lead-in used to be 40vh, which read as a huge empty blue band before
   the first frame ever appeared */
#gal-wrap { width: 100%; padding-top: min(140px, 12vh); position: relative; z-index: 2; will-change: transform; }
#gal-grid { display: grid; gap: 0; }
.gal-cell { aspect-ratio: 2 / 3; }
.bp-card {
  transform: scale(0);
  width: 100%; height: 100%;
  overflow: hidden;
  border-radius: 4px;
  position: relative;
  background: rgba(255,255,255,.04);
}
.bp-card img { width: 100%; height: 100%; object-fit: cover; }
.bp-card .frame { border-radius: inherit; }
.bp-card::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(150deg, rgba(255,255,255,.16), transparent 42%);
  mix-blend-mode: screen; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .bp-card { will-change: auto; } }

/* fixed gallery chrome — plain white, not `exclusion`: on the flag-blue
   panel an inverted blend would turn the type muddy red */
.gal-fixed { position: fixed; z-index: 6; pointer-events: none; color: #fff; }
#gal-info { right: var(--pad); bottom: 80px; width: 330px; display: flex; flex-direction: column; align-items: center; opacity: 0; }
#gal-info .top { display: flex; flex-direction: column; align-items: flex-start; width: 100%; margin-bottom: 32px; }
#gal-circle {
  position: relative; width: 30px; height: 30px; display: grid; place-items: center; margin-bottom: 14px;
}
#gal-circle svg { position: absolute; inset: 0; width: 100%; height: 100%; }
#circle-symbol { font-size: 15px; font-weight: 500; letter-spacing: -.04em; text-transform: uppercase; }
#gal-collection { font-size: 30px; font-weight: 500; line-height: 1; text-align: center; letter-spacing: -.04em; text-transform: uppercase; width: 100%; }

#gal-view {
  right: var(--pad); bottom: 32px; width: 330px; height: 174px;
  transform-origin: right bottom; transform: scale(0);
  background: #fff; border-radius: 1335px;
  display: flex; align-items: center; justify-content: center;
}
#gal-view span { font-size: 96px; font-weight: 500; letter-spacing: -.04em; color: var(--wine); line-height: 1; }

#gal-overlay { position: fixed; inset: 0; z-index: 6; pointer-events: none; background: #fff; opacity: 0; }

#gal-footer {
  left: var(--pad); bottom: 32px; display: flex; gap: 80px; opacity: 0;
  font-size: 13px; font-weight: 500; letter-spacing: -.02em; text-transform: uppercase;
}

/* =============================================================
   MUSIC — Apple-Music-grade coverflow + glass transport
   ============================================================= */
.music { position: relative; z-index: 4; padding: var(--gap) 0; overflow: hidden; }
.music.stack { padding: clamp(80px, 11vh, 128px) 0 clamp(28px, 4vh, 52px); }
.music.stack .music-head { margin-bottom: 0; }
.music-bg {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60vw 60vh at 50% 40%, var(--tint, rgba(227, 58, 58,.22)), transparent 65%);
  transition: background 1.2s var(--ease);
  filter: blur(6px);
}
.music-head { padding: 0 var(--pad); position: relative; z-index: 2; }

/* ---- carousel + its flanking arrows ---- */
.cf-wrap {
  position: relative; z-index: 2;
  display: flex; align-items: center; gap: clamp(4px, 1.5vw, 18px);
  padding: 0 clamp(6px, 2vw, 26px);
}
.cf-arrow {
  flex: none;
  width: clamp(44px, 4.2vw, 58px); height: clamp(44px, 4.2vw, 58px);
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink-70);
  background: var(--glass-strong);
  border: 1px solid var(--glass-line);
  box-shadow: var(--sh-m), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);
  transition: transform .5s var(--ease), background .4s var(--ease), color .4s var(--ease), box-shadow .5s var(--ease);
}
.cf-arrow svg { width: 22px; height: 22px; }
.cf-arrow:hover {
  color: #fff; background: var(--crimson-deep);
  transform: scale(1.08);
  box-shadow: 0 18px 40px -14px rgba(168, 24, 48,.65);
}
.cf-arrow:active { transform: scale(.93); }
.cf-arrow.kick { animation: cf-kick .45s var(--ease); }
.cf-arrow.prev.kick { animation-name: cf-kick-l; }
@keyframes cf-kick-l { 40% { transform: translateX(-6px) scale(1.06); } }
@keyframes cf-kick { 40% { transform: translateX(6px) scale(1.06); } }

.cf {
  position: relative; z-index: 2;
  flex: 1; min-width: 0;
  height: clamp(230px, 36vh, 420px);
  margin: clamp(20px, 4vh, 52px) 0 clamp(18px, 3.5vh, 44px);
  perspective: 1400px;
  perspective-origin: 50% 50%;
  cursor: grab;
  touch-action: pan-y;          /* let the page scroll vertically through it */
}
.cf.drag { cursor: grabbing; }
.cf-track { position: absolute; left: 50%; top: 50%; width: 0; height: 0; transform-style: preserve-3d; }
.cover {
  position: absolute; top: 0; left: 0;
  width: clamp(160px, 17vw, 250px); aspect-ratio: 1;
  margin-left: calc(clamp(160px, 17vw, 250px) / -2);
  margin-top: calc(clamp(160px, 17vw, 250px) / -2);
  border-radius: clamp(14px, 1.5vw, 22px);
  overflow: hidden; will-change: transform, opacity, filter;
  box-shadow: 0 34px 70px -26px rgba(72, 26, 34,.42), inset 0 0 0 1px rgba(255,255,255,.5);
  background: var(--mist);
  transform-style: preserve-3d;
}
.cover img { width: 100%; height: 100%; object-fit: cover; }
.cover::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(135deg, rgba(255,255,255,.38), transparent 44%);
  mix-blend-mode: screen; pointer-events: none;
}
.cover .cap {
  position: absolute; left: 8px; right: 8px; bottom: 8px;
  padding: 12px 14px; border-radius: 14px;
  background: rgba(255,255,255,.30);
  border: 1px solid rgba(255,255,255,.45);
  backdrop-filter: blur(22px) saturate(180%); -webkit-backdrop-filter: blur(22px) saturate(180%);
  color: #fff; text-shadow: 0 1px 12px rgba(72, 26, 34,.4);
  opacity: 0; transform: translateY(8px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.cover.active .cap { opacity: 1; transform: none; }
.cover .cap .t { font-size: 14px; font-weight: 600; letter-spacing: -.02em; }
.cover .cap .a { font-size: 11.5px; opacity: .85; margin-top: 2px; }
.cover.active { box-shadow: 0 60px 110px -34px rgba(72, 26, 34,.5), 0 0 70px rgba(199, 154, 85,.25), inset 0 0 0 1px rgba(255,255,255,.7); }

/* transport bar */
.transport {
  position: relative; z-index: 3;
  margin: 0 var(--pad);
  display: flex; align-items: center; gap: clamp(10px, 1.4vw, 22px);
  padding: 12px 16px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--glass-line);
  box-shadow: var(--sh-m), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(34px) saturate(190%); -webkit-backdrop-filter: blur(34px) saturate(190%);
}
.tp-btn {
  width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink-70);
  transition: background .4s var(--ease), color .4s var(--ease), transform .4s var(--ease);
}
.tp-btn:hover { background: rgba(255,255,255,.75); color: var(--ink); transform: scale(1.06); }
.tp-btn:active { transform: scale(.94); }
.tp-btn svg { width: 20px; height: 20px; fill: currentColor; }
.tp-play {
  width: 48px; height: 48px; position: relative;
  background: var(--ink); color: #fff;
  box-shadow: 0 10px 26px -12px rgba(24, 19, 19,.7);
  transition: background .5s var(--ease), transform .4s var(--ease), box-shadow .5s var(--ease);
}
.tp-play:hover { background: var(--crimson-deep); color: #fff; }
.tp-play.on { background: var(--crimson-deep); box-shadow: 0 14px 34px -12px rgba(168, 24, 48,.75); }

/* the two glyphs cross-fade through each other instead of swapping a path */
.tp-play svg {
  position: absolute; top: 50%; left: 50%;
  width: 20px; height: 20px; fill: currentColor;
  transition: opacity .34s var(--ease), transform .44s var(--ease);
}
.tp-play .ic-play  { transform: translate(-50%,-50%) scale(1) rotate(0deg);      opacity: 1; }
.tp-play .ic-pause { transform: translate(-50%,-50%) scale(.45) rotate(-90deg);  opacity: 0; }
.tp-play.on .ic-play  { transform: translate(-50%,-50%) scale(.45) rotate(90deg); opacity: 0; }
.tp-play.on .ic-pause { transform: translate(-50%,-50%) scale(1) rotate(0deg);    opacity: 1; }

/* a ring breathes out of the button on each press */
.tp-ring {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid var(--crimson); opacity: 0; pointer-events: none;
}
.tp-play.kick .tp-ring { animation: tp-ring .62s var(--ease); }
@keyframes tp-ring {
  0%   { transform: scale(1);   opacity: .85; }
  100% { transform: scale(1.9); opacity: 0; }
}
.tp-play.kick { animation: tp-press .42s var(--ease); }
@keyframes tp-press { 35% { transform: scale(.88); } }

/* the live cover lifts and glows while the track runs */
.cover.playing {
  box-shadow: 0 70px 130px -34px rgba(72, 26, 34,.55),
              0 0 90px var(--album, rgba(201, 31, 55,.45)),
              inset 0 0 0 1px rgba(255,255,255,.8);
}
.cover.playing::before {
  content: ''; position: absolute; inset: -3px; border-radius: inherit;
  border: 1.5px solid rgba(255,255,255,.55);
  animation: cover-pulse 2.6s var(--ease-soft) infinite;
  pointer-events: none;
}
@keyframes cover-pulse {
  0%, 100% { opacity: .18; transform: scale(1); }
  50%      { opacity: .58; transform: scale(1.022); }
}
.prow.live .eq i { animation-play-state: running; }
.prow .eq i { animation-play-state: paused; }

.tp-now {
  flex: 1; display: flex; align-items: center; gap: 12px;
  padding: 6px 8px; border-radius: 999px; min-width: 0;
  background: rgba(255,255,255,.45);
  border: 1px solid rgba(255,255,255,.6);
}
.tp-now .mini { width: 38px; height: 38px; border-radius: 11px; overflow: hidden; flex: none; box-shadow: var(--sh-s); position: relative; }
/* no artwork yet: the slot keeps its shape as a small tinted plate */
.tp-now .mini.empty {
  background: linear-gradient(150deg, #FFF6F2, #FCE3DB 60%, #FFF1EA);
  box-shadow: inset 0 0 0 1px rgba(201, 31, 55, .30);
}
.tp-now .mini img { width: 100%; height: 100%; object-fit: cover; }
.tp-txt { min-width: 0; flex: 1; }
.tp-txt .t { font-size: 13.5px; font-weight: 600; letter-spacing: -.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tp-txt .a { font-size: 11.5px; color: var(--ink-45); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tp-bar { position: relative; height: 4px; border-radius: 3px; background: var(--ink-10); margin-top: 6px; cursor: pointer; }
.tp-fill { position: absolute; inset: 0 auto 0 0; width: 0%; border-radius: 3px; background: linear-gradient(90deg, var(--crimson), var(--crimson-deep) 60%, var(--gold)); }
.tp-time { font-size: 11px; color: var(--ink-45); font-variant-numeric: tabular-nums; flex: none; }
.tp-icons { display: flex; align-items: center; gap: 4px; }

/* playlist */
.plist {
  margin: clamp(16px, 3vh, 32px) var(--pad) 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 6px; position: relative; z-index: 2;
  max-height: 21vh; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--ink-10) transparent;
}
.plist::-webkit-scrollbar { width: 6px; }
.plist::-webkit-scrollbar-thumb { background: var(--ink-10); border-radius: 6px; }
.prow {
  display: flex; align-items: center; gap: 14px; padding: 10px 14px;
  border-radius: 16px; cursor: pointer;
  border: 1px solid transparent;
  transition: background .45s var(--ease), border-color .45s var(--ease), transform .45s var(--ease);
}
.prow:hover { background: rgba(255,255,255,.6); border-color: var(--glass-line); transform: translateX(3px); }
.prow.on { background: rgba(255,255,255,.82); border-color: var(--glass-line); box-shadow: var(--sh-s); }
.prow .idx { font-size: 11px; color: var(--ink-25); width: 18px; font-variant-numeric: tabular-nums; }
/* `position: relative` is load-bearing: the placeholder .frame inside is
   absolutely positioned, and without a positioned parent it resolved
   against the whole playlist — eight 40px thumbs became eight stacked
   535px panels filling the section. */
.prow .th { position: relative; width: 40px; height: 40px; border-radius: 11px; overflow: hidden; flex: none; }
.prow .th img { width: 100%; height: 100%; object-fit: cover; }
.prow .nm { font-size: 13.5px; font-weight: 500; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.eq { display: flex; gap: 2px; align-items: flex-end; height: 14px; opacity: 0; transition: opacity .4s; }
.prow.on .eq { opacity: 1; }
.eq i { width: 2px; background: var(--crimson-deep); border-radius: 2px; animation: eq .9s ease-in-out infinite; }
.eq i:nth-child(2) { animation-delay: .18s; } .eq i:nth-child(3) { animation-delay: .36s; }
@keyframes eq { 0%,100% { height: 4px; } 50% { height: 14px; } }

/* =============================================================
   FILMS
   ============================================================= */
/* A single unbroken band of clips: no gaps, no radii, no shadows between
   them — the seam between two clips should read as a cut, not a gutter.
   Bleeds past the section padding to touch both edges of the screen. */
/* the chapter is nothing but the band of clips — no head, no padding */
#films.stack { padding: 0; overflow: hidden; }

.films-strip {
  display: flex;
  gap: 0;
  height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  width: 100%;
  scrollbar-width: none;
  cursor: grab;
  background: var(--wine-deep);
}
.films-strip::-webkit-scrollbar { display: none; }
.films-strip.drag { cursor: grabbing; scroll-snap-type: none; scroll-behavior: auto; }

.film {
  /* Sized as a fraction of the strip, never a fixed pixel width, so a whole
     number of clips always spans the section with no dead space at the end.
     Percentages resolve against the scroll container, which — unlike 100vw —
     excludes the scrollbar and so cannot cause a horizontal overflow. */
  position: relative;
  flex: 0 0 25%;
  width: 25%;
  height: 100%;
  border-radius: 0; overflow: hidden;
  box-shadow: none; cursor: pointer;
  scroll-snap-align: start;
}
@media (max-width: 1279px) { .film { flex-basis: 33.3333%; width: 33.3333%; } }
@media (max-width: 1023px) { .film { flex-basis: 50%;      width: 50%; } }
/* one clip per screen on a phone — a quarter-width vertical video would be
   a sliver, and the footage is the whole point of this chapter */
@media (max-width: 639px)  { .film { flex-basis: 100%;     width: 100%; } }
.film img, .film video, .film iframe {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border: 0;
}
/* the clip plays underneath the poster, which lifts once it is running */
.film video, .film iframe { opacity: 0; transition: opacity .9s var(--ease); }
.film.play video, .film.play iframe { opacity: 1; }
/* a YouTube frame is 16:9 — blow it up so the vertical crop stays filled */
.film iframe { pointer-events: none; }
.film.yt iframe {
  width: 300%; height: 100%; left: -100%;
}

/* navigation floats over the footage itself, one arrow per edge */
.film-nav {
  position: absolute; top: 50%; z-index: 5;
  transform: translateY(-50%);
  width: clamp(46px, 4vw, 60px); height: clamp(46px, 4vw, 60px);
  border-radius: 50%;
  display: grid; place-items: center;
  color: #fff;
  background: rgba(72, 26, 34, .34);
  border: 1px solid rgba(255, 255, 255, .38);
  box-shadow: 0 12px 34px -14px rgba(0, 0, 0, .7);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  transition: background .4s var(--ease), border-color .4s var(--ease), opacity .4s var(--ease);
}
.film-nav.prev { left: clamp(10px, 2vw, 30px); }
.film-nav.next { right: clamp(10px, 2vw, 30px); }
.film-nav svg { width: 22px; height: 22px; }
.film-nav:hover { background: rgba(201, 31, 55, .78); border-color: rgba(255,255,255,.6); }
/* the transform carries the centring, so the press has to keep it */
.film-nav:active { transform: translateY(-50%) scale(.92); }
/* the veil existed to keep a caption legible; with the captions gone it was
   only darkening the footage */
/* a hairline seam so two dark clips do not merge into one another */
.film + .film::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 1px; z-index: 3;
  background: rgba(255, 255, 255, .12);
}
.film .badge {
  position: absolute; top: 16px; left: 16px;
  padding: 7px 13px; border-radius: 999px; font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  background: rgba(255,255,255,.28); border: 1px solid rgba(255,255,255,.42); color: #fff;
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  opacity: 0; transform: translateY(-6px); transition: all .6s var(--ease);
}
.film:hover .badge { opacity: 1; transform: none; }

/* =============================================================
   LIVE
   ============================================================= */
/* =============================================================
   CONCERTS — a listing, not event cards

   The date is the loudest thing on the row: two enormous numerals with the
   month set small and wide underneath, the way a poster prints it. Everything
   else is quiet — city, title, venue, and a ticket link only when there is
   somewhere for it to go.
   ============================================================= */
.live-list { display: flex; flex-direction: column; gap: 8px; }

.gig {
  position: relative;
  display: grid;
  grid-template-columns: clamp(96px, 11vw, 148px) minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(16px, 3vw, 44px);
  padding: clamp(20px, 2.6vh, 34px) clamp(18px, 2.4vw, 34px);
  border-radius: var(--r-m);
  background: var(--glass);
  border: 1px solid var(--glass-line);
  box-shadow: var(--sh-s), inset 0 1px 0 rgba(255, 255, 255, .85);
  backdrop-filter: blur(24px) saturate(170%);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  overflow: hidden;
  transition: transform .7s var(--ease), box-shadow .7s var(--ease),
              background .7s var(--ease);
}
.gig:hover { transform: translateY(-4px); box-shadow: var(--sh-m); background: var(--glass-strong); }
/* a featured concert is marked by a crimson edge, not by a badge */
.gig.feat { border-left: 2px solid var(--crimson); }
.gig.off { opacity: .62; }
.gig.off .t, .gig.off .c { text-decoration: line-through; text-decoration-thickness: 1px; }

/* ---------- the date ---------- */
.gd { display: flex; flex-direction: column; line-height: 1; }
.gd .day {
  font-size: clamp(40px, 5.4vw, 74px); font-weight: 500;
  letter-spacing: -.05em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.gd .mon {
  margin-top: 8px; font-size: 11px; letter-spacing: .2em;
  color: var(--crimson); text-transform: uppercase;
}
.gd .yr {
  margin-top: 5px; font-size: 11px; letter-spacing: .16em;
  color: var(--ink-45); font-variant-numeric: tabular-nums;
}
/* no date yet — the placeholder takes the same slot without shouting */
.gd .tba {
  font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-45); line-height: 1.5;
}

/* ---------- the body ---------- */
.gb { min-width: 0; }
.gb .c {
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--ink-45); margin-bottom: 9px;
}
.gb .t {
  font-size: clamp(19px, 2.1vw, 31px); font-weight: 500;
  letter-spacing: -.035em; line-height: 1.1; color: var(--ink);
}
.gb .v { margin-top: 9px; font-size: 12.5px; color: var(--ink-45); }
.gb .gx {
  margin-top: 11px; font-size: 13.5px; line-height: 1.55;
  color: rgba(24, 19, 19, .58); max-width: 54ch;
}

/* ---------- actions ---------- */
.ga { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }
.tag {
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--ink-10); color: var(--ink-45);
}
.tag.out { color: var(--wine); border-color: rgba(125, 31, 50, .3); }
.tag.off { color: var(--ink-25); }
/* placeholder content, marked so it can never read as a real date */
.demo {
  font-size: 9.5px; letter-spacing: .2em; text-transform: uppercase;
  padding: 5px 10px; border-radius: 999px;
  color: var(--crimson); background: rgba(201, 31, 55, .08);
  border: 1px solid rgba(201, 31, 55, .18);
}
.buy {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 12px 24px; border-radius: 999px; font-size: 12px; font-weight: 500;
  background: var(--ink); color: #fff; white-space: nowrap;
  transition: transform .5s var(--ease), background .5s var(--ease);
}
.buy i { font-style: normal; transition: transform .4s var(--ease); }
.buy:hover { transform: translateY(-2px); background: var(--crimson-deep); }
.buy:hover i { transform: translate(2px, -2px); }

/* ---------- optional poster ----------
   A concert with a cover reveals it inside its own row on hover. Pointer
   only: there is no hover on a phone, so nothing there depends on it. */
.gp {
  position: absolute; right: 0; top: 0; bottom: 0; width: 34%;
  opacity: 0; pointer-events: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 62%);
  mask-image: linear-gradient(90deg, transparent, #000 62%);
  transition: opacity .8s var(--ease);
}
.gp img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (hover: hover) and (pointer: fine) {
  .gig:hover .gp { opacity: .3; }
}

@media (max-width: 767px) {
  /* one column, and the date turns to run across rather than down */
  .gig {
    grid-template-columns: 1fr;
    gap: 16px;
    padding: 22px 20px 24px;
  }
  .gd { flex-direction: row; align-items: baseline; gap: 10px; }
  .gd .day { font-size: 46px; }
  .gd .mon, .gd .yr { margin-top: 0; }
  .gb .t { font-size: 22px; }
  .ga { justify-content: flex-start; }
  /* a thumb needs a real target, and the link has the row to itself here */
  .buy { padding: 14px 26px; font-size: 13px; }
  .gp { display: none; }
}

/* =============================================================
   FOOTER
   ============================================================= */
.footer { position: relative; z-index: 4; padding: var(--gap) var(--pad) 40px; }
.footer.stack { padding: clamp(80px, 11vh, 128px) var(--pad) 34px; justify-content: space-between; }
.footer.stack .f-bottom { margin-top: clamp(24px, 4vh, 60px); }
.f-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: clamp(30px, 5vw, 80px); }
.f-name { font-size: clamp(30px, 5vw, 74px); font-weight: 500; letter-spacing: -.05em; line-height: .95; }
.f-col h4 { font-size: 10.5px; letter-spacing: .24em; text-transform: uppercase; color: var(--ink-45); margin-bottom: 20px; font-weight: 500; }
.f-col a, .f-col p { display: block; font-size: 14px; color: var(--ink-70); margin-bottom: 11px; transition: color .4s var(--ease), transform .4s var(--ease); }
.f-col a:hover { color: var(--ink); transform: translateX(4px); }
.f-bottom {
  display: flex; justify-content: space-between; align-items: center; gap: 20px; flex-wrap: wrap;
  margin-top: clamp(40px, 8vh, 90px); padding-top: 24px; border-top: 1px solid var(--ink-10);
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-25);
}

/* =============================================================
   RESPONSIVE
   ============================================================= */
@media (max-width: 1024px) {
  .nav-links { display: none; }
  .about { grid-template-columns: 1fr; }
  .f-grid { grid-template-columns: 1fr 1fr; }
  #gal-info { width: 300px; }
  #gal-view { width: 300px; height: 150px; }
  #gal-view span { font-size: 78px; }
}
/* Below the tablet break a chapter can no longer be trusted to fit one
   screen, and a clipped sticky box would swallow its own tail — so the
   stack relaxes into normal flow while keeping the layered lip. */
@media (max-width: 900px) {
  .hero.stack, .section.stack, .music.stack, .footer.stack {
    position: relative; height: auto; min-height: 100svh;
  }
  .stack { overflow: visible; }

  /* …except the sections that genuinely fit one screen. Dropping every
     chapter into normal flow also threw away the layered ride, so after the
     archive the whole page scrolled flat. `.can-pin` is set from JS after
     measuring, so a chapter whose content overruns the viewport still scrolls
     normally and cannot swallow its own tail. */
  #archive.stack,
  .stack.can-pin { position: sticky; top: 0; height: 100svh; min-height: 0; }
  /* taller chapters stick by their bottom edge — `top` is set from JS */
  .stack.pin-tall { position: sticky; height: auto; min-height: 100svh; }

  .about-figure { height: auto; aspect-ratio: 4/5; }
  .plist { max-height: none; overflow: visible; }
}

@media (max-width: 767px) {
  .hero { padding-top: 96px; }
  .hero-portrait { width: min(78vw, 46vh); }
  .hero-copy { position: static; max-width: none; margin-top: 34px; text-align: center; }
  .hero-meta, .scroll-cue { display: none; }
  .hero { flex-direction: column; justify-content: center; }
  .f-grid { grid-template-columns: 1fr; }
  .transport { flex-wrap: wrap; justify-content: center; }
  .tp-icons { display: none; }
  #gal-info { left: 0; right: 0; width: auto; bottom: 44px; }
  #gal-collection { font-size: 20px; }
  #gal-view { left: 16px; right: 16px; width: auto; height: 100px; bottom: 56px; }
  #gal-view span { font-size: 64px; }
  #gal-footer { left: 16px; right: 16px; justify-content: space-between; gap: 0; font-size: 11px; }
  .sec-head { flex-direction: column; align-items: flex-start; }

  /* ---- nav on a phone ----
     Brand + language + Contact would not fit a 375px bar: the button was
     landing past the right edge entirely. The label drops away and the CTA
     becomes the envelope alone, and the wordmark tightens to make room. */
  .nav { padding: 14px 16px; }
  .nav-right { gap: 8px; }
  .brand { font-size: 11px; letter-spacing: .07em; }
  .brand .dot { width: 6px; height: 6px; }
  .nav-cta {
    width: 40px; height: 40px; padding: 0;
    justify-content: center; gap: 0;
  }
  .nav-cta svg { display: block; width: 17px; height: 17px; }
  .nav-cta span { display: none; }

  /* ---- awards on a phone ---- */
  /* narrower than this and the longer honours run to four cramped lines */
  .aw-card { width: min(80vw, 320px); }
  .aw-title { font-size: 16.5px; }
  .aw-text { font-size: 14px; }
  .aw-body { padding: 18px 20px 24px; }
  .aw-hint { flex-wrap: wrap; gap: 12px; }
  #awards .sec-head { align-items: flex-start; }
  .aw-count { align-self: flex-start; }

  .cf-wrap { padding: 0 2px; gap: 2px; }
  .cf-arrow { width: 42px; height: 42px; }
  .cf-arrow svg { width: 19px; height: 19px; }
}

/* =============================================================
   MOBILE PERFORMANCE
   A phone repaints a backdrop-filter over the whole area behind it on every
   scrolled pixel, and a blurred SVG re-rasterises with it. Stacked, they are
   what made this page crawl. Below the tablet break the glass falls back to
   flat translucency and the soft-focus layers are dropped outright —
   the layout is untouched.
   ============================================================= */
@media (max-width: 900px) {
  /* Named selectors did not hold. Measured on a 390px viewport, 38 elements
     were still compositing a backdrop blur — eight of them `blur(22px)
     saturate(1.8)` — because the list below only covered the ones that
     existed when it was written, and every card added since brought its own.

     So the rule is inverted: nothing blurs its backdrop on a phone unless it
     is on the allowlist, and the allowlist is the navigation bar alone,
     because that is the one surface a reader sees against moving content.
     Everything else keeps its translucency, its border and its highlight —
     which is what the glass actually reads as at this size — and drops the
     one property that costs a full-area GPU repaint per scrolled pixel. */
  *:not(.nav) {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  .nav {
    backdrop-filter: blur(14px) !important;
    -webkit-backdrop-filter: blur(14px) !important;
  }

  /* the surfaces that lost their blur get a solid enough ground to stay
     legible over whatever passes behind them */
  .nav-links, .transport, .cf-arrow, .tp-now { background: rgba(255,255,255,.92); }
  .frame span { background: rgba(255,255,255,.86); }
  .cap { background: rgba(255,252,250,.92) !important; }
  .badge { background: rgba(255,252,250,.9) !important; }
  .gig, .f-card, .glass { background: rgba(255,252,250,.9); }

  /* soft-focus decoration: invisible at this size, expensive at any size */
  .hero-glow, .music-bg { filter: none; }
  #flowers .fl, #flowers-front .fl { filter: none !important; }
  .cover { filter: none !important; }

  /* Compositor layers are not free — each one is a texture held in GPU
     memory for as long as the hint is set. 52 were live at once, 21 of them
     archive cards that are three screens away and not moving. The hint now
     belongs only to things that are actually animating right now: the hero
     blooms and the pinned stack. */
  .about-figure, .film, .f-card, .gig, .bp-card, .cover,
  #gal-wrap, .chapter, .aw-card {
    will-change: auto;
  }
}

/* The archive card is promoted only while the gallery is the thing on
   screen; gallery.js adds `live` when its panel is in view and removes it
   again afterwards, so 21 permanent layers become 21 temporary ones. */
#gal-panel.live .bp-card { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}


/* =============================================================
   ARCHIVE VIEWER

   Warm ivory rather than the usual black scrim: these are photographs from
   different years and different cameras, and a black room makes them all
   look like one set. No filter, no tint, no blend mode touches the image —
   a black-and-white print stays black-and-white and a colour frame keeps
   its colour. The palette shows up in the chrome around it instead.
   ============================================================= */
html.vw-lock, html.vw-lock body { overflow: hidden; }

.vw {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(16px, 4vh, 54px) clamp(16px, 6vw, 96px);
  opacity: 0; pointer-events: none;
  transition: opacity .42s var(--ease);
}
.vw.on { opacity: 1; pointer-events: auto; }

.vw-scrim {
  position: absolute; inset: 0;
  background: rgba(255, 249, 246, .93);
  backdrop-filter: blur(26px) saturate(140%);
  -webkit-backdrop-filter: blur(26px) saturate(140%);
}

.vw-fig {
  position: relative; margin: 0;
  max-width: 100%; max-height: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  transform-origin: 50% 50%;
  transition: transform .52s var(--ease), opacity .42s var(--ease);
}
.vw-fig.in { transform: none; opacity: 1; }
.vw-fig img {
  display: block; max-width: 100%;
  max-height: calc(100vh - clamp(150px, 22vh, 230px));
  object-fit: contain;
  border-radius: 4px;
  /* the only decoration: a hairline and a soft drop, like a mounted print */
  box-shadow: 0 40px 90px -30px rgba(72, 26, 34, .38), 0 2px 10px rgba(72, 26, 34, .1);
}

.vw-cap { text-align: center; max-width: 62ch; }
.vw-meta {
  font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-45);
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.vw-meta b { color: var(--crimson); font-weight: 500; font-variant-numeric: tabular-nums; }
.vw-meta i { font-style: normal; color: var(--ink-25); }
.vw-text { margin-top: 9px; font-size: 14px; line-height: 1.55; color: var(--ink-70); }

.vw-x, .vw-nav {
  position: absolute; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; cursor: pointer; color: var(--ink);
  background: rgba(255, 255, 255, .74);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--sh-s);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  transition: background .3s var(--ease), transform .3s var(--ease), color .3s;
}
.vw-x:hover, .vw-nav:hover { background: #fff; color: var(--crimson); }
.vw-x { top: clamp(14px, 3vh, 30px); right: clamp(14px, 3vw, 34px); width: 44px; height: 44px; }
.vw-nav { top: 50%; margin-top: -26px; width: 52px; height: 52px; }
.vw-nav.prev { left: clamp(10px, 2vw, 30px); }
.vw-nav.next { right: clamp(10px, 2vw, 30px); }
.vw-nav:hover.prev { transform: translateX(-2px); }
.vw-nav:hover.next { transform: translateX(2px); }

.vw-count {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: clamp(14px, 3vh, 28px);
  font-size: 11px; letter-spacing: .2em; color: var(--ink-45);
  font-variant-numeric: tabular-nums;
}

/* a single petal crossing the frame as the picture changes — it starts and
   ends off the image, and never sits over a face */
.vw-petal {
  position: absolute; left: 50%; top: 0; width: 30px; height: 30px;
  opacity: 0; pointer-events: none; z-index: 3;
}
.vw.petal .vw-petal { animation: vw-drift 1.15s var(--ease); }
.vw-petal svg { width: 100%; height: 100%; display: block; }
@keyframes vw-drift {
  0%   { opacity: 0; transform: translate(-160%, -18vh) rotate(-30deg); }
  22%  { opacity: .85; }
  100% { opacity: 0; transform: translate(150%, 92vh) rotate(220deg); }
}

@media (max-width: 767px) {
  .vw { padding: 14px; }
  .vw-fig img { max-height: calc(100vh - 200px); }
  /* the arrows are a pointer affordance; the phone swipes instead */
  .vw-nav { display: none !important; }
  .vw-x { width: 40px; height: 40px; top: 12px; right: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .vw-fig { transition: opacity .3s linear; }
  .vw.petal .vw-petal { animation: none; }
}

/* an archive thumbnail is a control now */
.bp-card { cursor: zoom-in; }

/* =============================================================
   ARCHIVAL PRINTS IN THE BIOGRAPHY
   A mount and a hairline, not a scrapbook: ivory border, one soft shadow,
   a degree or two of rotation. No tape, no torn edges, no sepia.
   ============================================================= */
.ch-shot {
  background: var(--white);
  padding: 8px 8px 8px;
  border: 1px solid rgba(24, 19, 19, .07);
  border-radius: 3px;
  box-shadow: 0 22px 46px -22px rgba(72, 26, 34, .34), 0 1px 4px rgba(72, 26, 34, .07);
  cursor: zoom-in;
}
.ch-shot img { border-radius: 1px; }
.ch-shot figcaption {
  margin-top: 7px; font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-45); text-align: center;
  font-variant-numeric: tabular-nums;
}

/* the year on an archive card — only rendered when the date is known */
.bp-year {
  position: absolute; left: 10px; bottom: 9px; z-index: 2;
  font-size: 9.5px; letter-spacing: .18em; color: #fff;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 6px rgba(24,19,19,.6);
  opacity: 0; transition: opacity .5s var(--ease);
}
.bp-card:hover .bp-year { opacity: .92; }
.bp-card { position: relative; }

/* the footer's columns are generated now, so the grid has to hold whatever
   number of groups actually has content — one, or none at all */
.f-cols { display: contents; }

/* The artist's name, opening the H1 above the display lines. Small and
   letterspaced so the hero composition still reads as it did — the big
   type is still the tagline — but the page now states whose site this is
   in its own heading rather than only in the nav. */
.hero-name {
  display: block;
  font-size: clamp(11px, 1.05vw, 13px);
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--crimson);
  margin-bottom: clamp(12px, 1.6vh, 20px);
  line-height: 1.4;
}
@media (max-width: 767px) {
  .hero-name { font-size: 10.5px; letter-spacing: .2em; margin-bottom: 10px; }
}
