/* ==========================================================================
   Nico Vero — nightlife & live photography
   Ink and chalk. Two accents, taken from the two lighting registers in the
   work itself: flare (club red) and haze (festival violet).
   ========================================================================== */

:root {
  --ink:        #0b0b0c;
  --ink-rise:   #141417;
  --ink-sink:   #050506;
  --chalk:      #f2efe9;
  --chalk-dim:  #8a8880;
  --chalk-mute: #56554f;
  --flare:      #ff3b14;
  --haze:       #6e5bff;
  --line:       rgba(242, 239, 233, 0.13);
  --line-soft:  rgba(242, 239, 233, 0.07);

  --accent: var(--chalk);

  --display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --mono: 'Azeret Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --gutter: clamp(1.15rem, 4.2vw, 4.5rem);
  --measure: 1720px;
  --header-h: 4.5rem;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

[data-accent='flare'] { --accent: var(--flare); }
[data-accent='haze']  { --accent: var(--haze); }
[data-accent='chalk'] { --accent: var(--chalk); }

/* --------------------------------------------------------------- reset -- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--chalk);
  font-family: var(--display);
  font-variation-settings: 'wdth' 100;
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.075rem);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

img, svg { display: block; max-width: 100%; }
img { height: auto; }

a { color: inherit; text-decoration: none; }

h1, h2, h3, p, figure, ul { margin: 0; }
ul { padding: 0; list-style: none; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--chalk);
  outline-offset: 3px;
}

::selection { background: var(--flare); color: var(--ink); }

.skip {
  position: absolute;
  left: var(--gutter);
  top: -100%;
  z-index: 200;
  padding: 0.75rem 1.1rem;
  background: var(--chalk);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.skip:focus { top: 1rem; }

/* ------------------------------------------------------------ typography -- */

.display {
  font-family: var(--display);
  font-weight: 800;
  font-variation-settings: 'wdth' 125, 'wght' 800;
  text-transform: uppercase;
  line-height: 0.84;
  letter-spacing: -0.022em;
  margin: 0;
}

.d-xl { font-size: clamp(2.9rem, 11.5vw, 10.5rem); }
.d-lg { font-size: clamp(2.4rem, 8vw, 6.5rem); }
.d-md { font-size: clamp(1.75rem, 4.4vw, 3.4rem); }

.eyebrow {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}

.meta {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.7rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}

.lead {
  font-size: clamp(1.2rem, 1.02rem + 0.85vw, 1.75rem);
  line-height: 1.36;
  letter-spacing: -0.012em;
  max-width: 30ch;
}

.prose p + p { margin-top: 1.1em; }
.prose { color: #cfccc5; max-width: 62ch; }

/* ------------------------------------------------------------ structure -- */

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: clamp(4.5rem, 10vw, 9.5rem); }
.section--tight { padding-block: clamp(3rem, 6vw, 5.5rem); }

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding-bottom: 1.4rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(1.75rem, 4vw, 3.25rem);
}

/* --------------------------------------------------------------- header -- */

.header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: linear-gradient(to bottom, rgba(11, 11, 12, 0.92), rgba(11, 11, 12, 0));
}

/* the popup brings its own ground, so the scrim gets out of its way */
body.is-menu .header { background: none; }

.header__inner {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.brand {
  display: flex;
  align-items: center;
}

.brand__mark {
  width: 2.15rem;
  height: 2.15rem;
  transition: transform 0.5s var(--ease-out);
}
.brand:hover .brand__mark { transform: rotate(-6deg) scale(1.06); }

/* --------------------------------------------------------------- trigger -- */

.nav__toggle {
  display: flex;
  align-items: center;
  /* the glyph is all that is left, so pad it out to a thumb-sized target */
  padding: 1rem 0 1rem 1.25rem;
  color: var(--chalk);
}

.nav__toggle__bars {
  position: relative;
  width: 1.75rem;
  height: 0.6rem;
}

.nav__toggle__bars i {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transition: transform 0.45s var(--ease-out);
}
.nav__toggle__bars i:first-child { top: 0; }
.nav__toggle__bars i:last-child { bottom: 0; }

.nav__toggle:hover .nav__toggle__bars i:last-child { transform: scaleX(0.55); transform-origin: right; }

.nav__toggle[aria-expanded='true'] .nav__toggle__bars i:first-child {
  transform: translateY(0.3rem) rotate(19deg);
}
.nav__toggle[aria-expanded='true'] .nav__toggle__bars i:last-child {
  transform: translateY(-0.3rem) rotate(-19deg);
}

/* the chinagraph mark: the site's one ornament, drawn in the same hand as the
   logo. Reserved for the page you are on and the work index. */
.mark-underline path,
.mark-circle path {
  fill: none;
  stroke: currentColor;
  stroke-width: 6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* ------------------------------------------------------------ menu popup -- */

.menu {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--header-h) + 0.25rem) var(--gutter) clamp(1rem, 2.5vh, 3rem);
  background: rgba(5, 5, 6, 0.94);
  backdrop-filter: saturate(120%) blur(18px);
  -webkit-backdrop-filter: saturate(120%) blur(18px);
  opacity: 0;
  visibility: hidden;
  /* visible the instant it opens, so the panel can take focus; on the way out
     it waits for the fade to finish */
  transition: opacity 0.45s var(--ease), visibility 0s linear 0.45s;
}
.menu.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.45s var(--ease), visibility 0s;
}

.menu__panel {
  width: 100%;
  max-height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  opacity: 0;
  transform: translateY(1.5rem);
  transition: transform 0.65s var(--ease-out), opacity 0.4s var(--ease);
}
.menu.is-open .menu__panel { opacity: 1; transform: none; }
.menu__panel:focus { outline: none; }

/* rides the header band, on the same line as the logo and the trigger. Sits
   outside the panel because the panel starts below the header and clips. */
.menu__now {
  position: absolute;
  inset: 0 0 auto;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--gutter);
  text-align: center;
}
.menu__mark { position: relative; color: var(--chalk); }
.menu__mark .mark-underline {
  position: absolute;
  left: -6%;
  bottom: -0.55rem;
  width: 112%;
  height: 0.7rem;
}

.menu__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1.75rem;
  padding-top: clamp(1.25rem, 3vw, 2rem);
  border-top: 1px solid var(--line-soft);
  text-align: center;
}
.menu__foot a:hover { color: var(--chalk); }

/* ---------------------------------------------------------- layered text -- */

/* Each slab clips a two-item stack. Hovering the list rolls every stack up by
   one line, so the words climb the staircase together; the alternating
   60/-30 and 0/-30 skews are what make the pile read as a solid object. */
.lt {
  --lt-size: clamp(1.5rem, min(7.6vw, 6.6svh), 4rem);
  --lt-line: calc(var(--lt-size) * 0.8);
  --lt-step: calc(var(--lt-size) * 0.62);
  --lt-gap: calc(var(--lt-size) * 0.44);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* the -30deg shear throws each word well outside its own box: this reserves
     the room it needs so the pile never lands on the eyebrow or the footer.
     Lopsided because the top slab reads empty until the stack rolls. */
  padding-top: var(--lt-size);
  padding-bottom: calc(var(--lt-size) * 2.2);
  font-family: var(--display);
  font-variation-settings: 'wdth' 118, 'wght' 900;
  font-size: var(--lt-size);
  letter-spacing: -0.03em;
  text-transform: uppercase;
}

.lt__row {
  height: var(--lt-line);
  overflow: hidden;
  transform: translateX(calc(var(--lt-i) * var(--lt-step)))
    skew(var(--lt-sx), -30deg)
    scaleY(var(--lt-sy));
}
.lt__row + .lt__row { margin-top: var(--lt-gap); }
.lt__row:nth-child(odd) { --lt-sx: 60deg; --lt-sy: 0.66667; }
.lt__row:nth-child(even) { --lt-sx: 0deg; --lt-sy: 1.33333; }

.lt__stack {
  display: block;
  transition: transform 0.62s var(--ease-out);
  transition-delay: calc(var(--lt-dr) * 55ms);
}

.lt__cell {
  display: block;
  height: var(--lt-line);
  line-height: var(--lt-line);
  padding-inline: 0.22em;
  white-space: nowrap;
  color: var(--chalk);
  transition: color 0.3s var(--ease);
}
.lt__cell[data-current] { color: var(--accent); }
/* the pile recedes as a whole and the word under the pointer stays white, so
   the pick reads against the rest. Same specificity, so source order decides. */
.lt:hover .lt__cell { color: var(--chalk-mute); }
.lt .lt__cell:hover { color: var(--chalk); }

/* the slab clips any outline, so focus inverts the whole face instead */
.lt__cell:focus-visible { outline: none; color: var(--ink); background: var(--chalk); }

@media (hover: hover) and (pointer: fine) {
  .lt:hover .lt__stack {
    transform: translateY(-50%);
    transition-delay: calc(var(--lt-d) * 55ms);
  }
}

/* ----------------------------------------------------------------- hero -- */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--ink-sink);
}

.hero__stage { position: absolute; inset: 0; }

.hero__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.045);
  transition: opacity 1.6s var(--ease), transform 8s linear;
}
.hero__frame.is-live { opacity: 1; transform: scale(1); }

.hero__veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(5, 5, 6, 0.95) 0%, rgba(5, 5, 6, 0.74) 20%, rgba(5, 5, 6, 0.3) 45%, rgba(5, 5, 6, 0.04) 64%, rgba(5, 5, 6, 0.4) 100%);
}

.hero__body {
  position: relative;
  width: 100%;
  padding-bottom: clamp(2rem, 5vw, 4rem);
}

/* the eyebrow sits straight on the photograph, so it needs more weight than
   the eyebrows that sit on flat ink */
.hero__eyebrow {
  margin-bottom: clamp(0.9rem, 2vw, 1.6rem);
  color: var(--chalk);
  text-shadow: 0 1px 12px rgba(5, 5, 6, 0.75);
}

.hero__title { position: relative; margin-bottom: clamp(1rem, 2.4vw, 1.75rem); }

/* the warped title is painted by the canvas on top; the heading keeps its
   box so nothing below it moves, and its text stays for readers and crawlers */
.hero__title.is-warped { color: transparent; }
.hero__warp { position: absolute; pointer-events: none; }

.hero__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem 2rem;
  padding-top: clamp(1rem, 2.2vw, 1.6rem);
  border-top: 1px solid var(--line);
}

.hero__line { max-width: 34ch; color: #d8d5ce; font-size: clamp(1rem, 0.95rem + 0.35vw, 1.2rem); line-height: 1.45; }

.hero__ticker { display: flex; align-items: center; gap: 0.8rem; white-space: nowrap; }
.hero__count { color: var(--chalk-mute); font-variant-numeric: tabular-nums; }
.hero__label { color: var(--chalk); }

.hero__aside {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.5vw, 2rem);
}

.hero__cue {
  flex: none;
  width: 1.1rem;
  color: var(--chalk-dim);
  animation: cue 2.6s var(--ease) infinite;
}
.hero__cue path {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

@keyframes cue {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50%      { transform: translateY(0.35rem); opacity: 1; }
}

/* ----------------------------------------------------------- work index -- */

.index { border-top: 1px solid var(--line); }

.index__row {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 1rem 2rem;
  padding-block: clamp(1.4rem, 3.4vw, 2.6rem);
  border-bottom: 1px solid var(--line);
  isolation: isolate;
  overflow: hidden;
}

.index__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.index__bg img { width: 100%; height: 100%; object-fit: cover; }
.index__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(11, 11, 12, 0.9), rgba(11, 11, 12, 0.55));
}

.index__row:hover .index__bg,
.index__row:focus-within .index__bg,
.index__row.is-active .index__bg { opacity: 0.55; }

.index__title {
  display: flex;
  align-items: baseline;
  gap: clamp(0.75rem, 2vw, 1.75rem);
  flex-wrap: wrap;
  transition: transform 0.55s var(--ease-out);
}
.index__row:hover .index__title,
.index__row:focus-within .index__title,
.index__row.is-active .index__title { transform: translateX(clamp(0.4rem, 1.2vw, 1.1rem)); }

.index__name { color: var(--chalk); }
.index__row:hover .index__name,
.index__row.is-active .index__name { color: var(--accent); }

.index__blurb { color: var(--chalk-dim); max-width: 34ch; }

.index__side { display: flex; align-items: center; gap: clamp(1rem, 2.5vw, 2rem); }

.index__count { position: relative; display: inline-block; padding: 0.5rem 1.2rem; isolation: isolate; }

.index__count .mark-circle {
  position: absolute;
  inset: -0.7rem 0;
  z-index: -1;
  /* both axes explicit: leave either one auto and the viewBox ratio drives it,
     pushing the ellipse off the label instead of around it */
  width: 100%;
  height: calc(100% + 1.4rem);
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.25s var(--ease);
}
.index__count .mark-circle path {
  stroke-width: 5;
  stroke-dasharray: 640;
  stroke-dashoffset: 640;
}
.index__row:hover .mark-circle,
.index__row:focus-within .mark-circle,
.index__row.is-active .mark-circle { opacity: 1; }
.index__row:hover .mark-circle path,
.index__row:focus-within .mark-circle path,
.index__row.is-active .mark-circle path {
  animation: draw 0.7s var(--ease-out) forwards;
}

@keyframes draw { to { stroke-dashoffset: 0; } }

.index__arrow {
  width: 2.4rem;
  color: var(--chalk-dim);
  transition: color 0.3s var(--ease);
}
.index__arrow svg { width: 1.9rem; transition: transform 0.5s var(--ease-out); }
.index__arrow path {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.index__row:hover .index__arrow,
.index__row.is-active .index__arrow { color: var(--accent); }
.index__row:hover .index__arrow svg,
.index__row.is-active .index__arrow svg { transform: translateX(0.5rem); }

.index__link { position: absolute; inset: 0; z-index: 2; }

/* ------------------------------------------------------------ justified -- */
/* Build-time justified rows: each figure's flex-grow is its aspect ratio, so
   every frame in a row lands on the same height with no cropping. */

.justified { display: flex; flex-direction: column; gap: var(--frame-gap, 6px); }

.justified__row { display: flex; gap: var(--frame-gap, 6px); }

.frame {
  position: relative;
  display: block;
  flex: 1 1 0;
  min-width: 0;
  background: var(--ink-rise);
  overflow: hidden;
}

.frame img {
  width: 100%;
  height: auto;
  display: block;
  transition: opacity 0.5s var(--ease), transform 0.7s var(--ease-out);
}

.frame::after {
  content: '';
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 0 1px rgba(242, 239, 233, 0);
  transition: box-shadow 0.3s var(--ease);
  pointer-events: none;
}

.frame:hover img { opacity: 0.72; transform: scale(1.015); }
.frame:hover::after { box-shadow: inset 0 0 0 1px rgba(242, 239, 233, 0.35); }

.collection + .collection { margin-top: clamp(3rem, 7vw, 6rem); }

.collection__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.9rem;
  margin-bottom: clamp(0.9rem, 2vw, 1.4rem);
  border-bottom: 1px solid var(--line);
}


/* --------------------------------------------------------------- ribbon -- */
/* Showcase ribbon: one horizontal strip, one viewport tall. The page itself
   never scrolls — the track is translated instead, with inertia. Frames all
   share a height, so the strip reads like a contact sheet laid end to end.
   Touch gets the same strip, only shorter — see the breakpoint further down. */

body.is-ribbon { overflow: hidden; height: 100svh; }
body.is-ribbon .cta,
body.is-ribbon .footer { display: none; }

.ribbon {
  position: fixed;
  inset: var(--header-h) 0 0;
  overflow: hidden;
  cursor: grab;
  /* nothing here scrolls vertically, so every gesture belongs to the strip */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.ribbon img { -webkit-user-drag: none; }
.ribbon.is-grabbed { cursor: grabbing; }

.ribbon__track {
  display: flex;
  align-items: center;
  height: 100%;
  gap: clamp(0.4rem, 1.1vw, 0.9rem);
  padding: 0 var(--gutter) 4.25rem;
  will-change: transform;
}

.ribbon .frame {
  flex: none;
  width: auto;
  height: 86%;
}
.ribbon .frame img {
  width: auto;
  height: 100%;
  max-width: none;
  transform: translate3d(var(--lag, 0px), 0, 0) scale(1.06);
}
.ribbon .frame:hover img { opacity: 0.78; }

/* opening card — the page title lives inside the strip, not above it */
.ribbon__card {
  flex: none;
  width: max-content;
  max-width: min(78vw, 62rem);
  padding-right: clamp(1.5rem, 4vw, 4rem);
}
.ribbon__card .prose { margin-block: clamp(0.9rem, 2vw, 1.5rem); max-width: 42ch; }
.ribbon__hint { display: flex; align-items: center; gap: 0.7rem; }
.ribbon__hint svg { width: 2.2rem; color: var(--accent); }
.ribbon__hint svg path {
  fill: none; stroke: currentColor; stroke-width: 4;
  stroke-linecap: round; vector-effect: non-scaling-stroke;
}

/* collection divider, set along the strip like a marking on a film rebate */
.ribbon__label {
  flex: none;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  padding: 0 clamp(0.75rem, 2.2vw, 2.25rem);
  writing-mode: vertical-rl;
}
.ribbon__label b {
  font-family: var(--display);
  font-variation-settings: 'wdth' 118, 'wght' 800;
  font-size: clamp(1.1rem, 2vw, 1.6rem);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.ribbon__end {
  flex: none;
  width: max-content;
  max-width: min(74vw, 44rem);
  padding-left: clamp(1.5rem, 4vw, 4rem);
}
.ribbon__end .cta__link { margin-top: 0.6rem; }

/* head-up display: caption, seek bar, counter */
.ribbon__hud {
  position: fixed;
  inset: auto 0 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 3vw, 2.5rem);
  padding: 1.1rem var(--gutter) 1.35rem;
  background: linear-gradient(to top, var(--ink) 55%, rgba(11, 11, 12, 0));
}
.ribbon__hud .meta { white-space: nowrap; }
.ribbon__caption { color: var(--chalk); }

.ribbon__bar {
  position: relative;
  flex: 1;
  height: 2px;
  background: var(--line);
  cursor: pointer;
}
.ribbon__bar::before { content: ''; position: absolute; inset: -14px 0; }
.ribbon__bar i {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

/* Touch keeps the same strip. The shared height drops to whatever leaves a
   landscape frame inside the screen, so no frame has to be dragged in half. */
@media (max-width: 47.5rem) {
  .ribbon__track { padding-bottom: 3.5rem; }
  .ribbon .frame { height: min(64vw, 58svh); }
  .ribbon__card,
  .ribbon__end { max-width: 84vw; }
  .ribbon__label { gap: 0.9rem; }
  .ribbon__hud { gap: 0.75rem; padding-bottom: 1.1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .ribbon .frame img { transform: none; }
}


/* ----------------------------------------------------------- page header -- */

.pagehead {
  padding-top: calc(var(--header-h) + clamp(3rem, 9vw, 8rem));
  padding-bottom: clamp(2rem, 5vw, 4rem);
}

.pagehead--bare { padding-bottom: clamp(1rem, 2.5vw, 2rem); }

.pagehead__title { margin-block: clamp(0.75rem, 2vw, 1.4rem); }

.pagehead__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.25rem 2rem;
  padding-top: clamp(1rem, 2.2vw, 1.6rem);
  border-top: 1px solid var(--line);
}
.pagehead__foot .prose { max-width: 46ch; color: #cfccc5; }

/* ---------------------------------------------------------------- about -- */

.about {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
.about__portrait { grid-column: span 12; }
.about__portrait img { width: 100%; }
.about__text { grid-column: span 12; }

@media (min-width: 56rem) {
  .about__portrait { grid-column: 1 / span 5; }
  .about__text { grid-column: 7 / span 6; }
}

.about__lead { margin-bottom: 1.5rem; }

.deets { margin-top: clamp(2rem, 4vw, 3rem); border-top: 1px solid var(--line); padding-top: 1.25rem; }
.deets ul { margin-top: 0.8rem; display: grid; gap: 0.35rem; }
.deets li { color: #cfccc5; }
.deets li::before { content: '— '; color: var(--chalk-mute); }

/* ----------------------------------------------------------------- zoom -- */
/* Seven frames on a single scroll-driven scale. --p (0 -> 1) is written to the
   rail by site.js and is the only thing that moves: each layer reads it and
   ends at its own scale, so the six satellites are thrown out of frame while
   the portrait grows to fill it. With no JS the rail collapses to one screen
   and --p stays at 1 — the portrait full-bleed with the text over it, which is
   also what reduced motion gets. */

.zoom { padding-bottom: 0; }

.zoom__rail { --p: 1; height: 100svh; }
.zoom__rail.is-live { height: 300svh; }

.zoom__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: var(--ink-sink);
}

.zoom__layer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: scale(calc(1 + (var(--s) - 1) * var(--p)));
}

/* the satellites end far outside the frame, so a flat raster costs them
   nothing; the portrait is left to re-raster or it lands on screen soft */
.zoom__layer:not(.zoom__layer--lead) { will-change: transform; }

.zoom__cell {
  position: relative;
  top: var(--t, 0);
  left: var(--l, 0);
  height: var(--h, 25vh);
  width: var(--w, 25vw);
  overflow: hidden;
  background: var(--ink-rise);
}
.zoom__cell img { height: 100%; width: 100%; object-fit: cover; }

/* the portrait is the one frame that has to stay sharp when it lands, so it
   scales the cell instead of the layer: same motion, since it sits dead centre,
   but Chrome paints a viewport-sized surface rather than 4.2 times one */
.zoom__layer--lead { --s: 4.2; transform: none; }
.zoom__layer--lead .zoom__cell { transform: scale(calc(1 + (var(--s) - 1) * var(--p))); }
.zoom__layer--lead img { object-position: 50% 28%; }

.zoom__layer:nth-child(2) { --s: 5; --t: -30vh;  --l: 5vw;     --h: 30vh; --w: 35vw; }
.zoom__layer:nth-child(3) { --s: 6; --t: -10vh;  --l: -25vw;   --h: 45vh; --w: 20vw; }
.zoom__layer:nth-child(4) { --s: 5;              --l: 27.5vw;  --h: 25vh; --w: 25vw; }
.zoom__layer:nth-child(5) { --s: 6; --t: 27.5vh; --l: 5vw;     --h: 25vh; --w: 20vw; }
.zoom__layer:nth-child(6) { --s: 8; --t: 27.5vh; --l: -22.5vw; --h: 25vh; --w: 30vw; }
.zoom__layer:nth-child(7) { --s: 9; --t: 22.5vh; --l: 25vw;    --h: 15vh; --w: 15vw; }

.zoom__veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to top, rgba(5, 5, 6, 0.94) 4%, rgba(5, 5, 6, 0.62) 30%, rgba(5, 5, 6, 0) 64%);
  opacity: calc((var(--p) - 0.62) * 3.2);
}

.zoom__note {
  position: absolute;
  z-index: 3;
  inset: auto var(--gutter) clamp(2rem, 6vh, 4.5rem);
  max-width: 44rem;
  opacity: calc((var(--p) - 0.72) * 4.6);
}
.zoom__note .prose { margin-top: 1rem; max-width: 54ch; }
.zoom__more { display: inline-block; margin-top: 1.5rem; transition: color 0.25s var(--ease); }
.zoom__more:hover { color: var(--chalk); }

/* an invisible link is still a click target: hand it back only once it reads */
.zoom__rail.is-live .zoom__note { pointer-events: none; }
.zoom__rail.is-live.is-read .zoom__note { pointer-events: auto; }

/* two fewer layers on a phone — they are barely on screen and each one is a
   full-viewport composited surface */
@media (max-width: 47.5rem) {
  .zoom__layer:nth-child(n + 6) { display: none; }
  .zoom__note { max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
  .zoom__layer:not(.zoom__layer--lead) { display: none; }
}

/* -------------------------------------------------------------- contact -- */

.contact__mail {
  display: inline-block;
  margin-block: clamp(1.25rem, 3vw, 2.25rem);
  font-size: clamp(1.55rem, 5vw, 4.1rem);
  letter-spacing: -0.03em;
  overflow-wrap: anywhere;
  transition: color 0.3s var(--ease);
}
.contact__mail:hover { color: var(--flare); }

.contact__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  border-top: 1px solid var(--line);
  padding-top: clamp(1.5rem, 3vw, 2.5rem);
}
.contact__cell { grid-column: span 12; }
@media (min-width: 56rem) { .contact__cell { grid-column: span 4; } }
.contact__cell p { margin-top: 0.6rem; color: #cfccc5; }

/* ------------------------------------------------------------------ cta -- */

.cta { border-top: 1px solid var(--line); }
.cta__inner { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 1.5rem 2rem; }
.cta__link { display: inline-flex; align-items: center; gap: 1rem; transition: color 0.3s var(--ease); }
.cta__link:hover { color: var(--flare); }
.cta__link svg { width: 2.4rem; flex: none; }
.cta__link svg path { fill: none; stroke: currentColor; stroke-width: 4; stroke-linecap: round; vector-effect: non-scaling-stroke; }

/* --------------------------------------------------------------- footer -- */

.footer { border-top: 1px solid var(--line); padding-block: clamp(2rem, 4vw, 3rem); }
.footer__inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.25rem 2rem; }
.footer__mark { width: 1.9rem; opacity: 0.65; }
.footer__links { display: flex; flex-wrap: wrap; gap: 0.4rem 1.75rem; }
.footer__links a { transition: color 0.25s var(--ease); }
.footer__links a:hover { color: var(--chalk); }

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.4rem 2rem;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  padding-top: 1.15rem;
  border-top: 1px solid var(--line-soft);
  color: var(--chalk-mute);
}
.footer__legal a { color: var(--chalk-dim); transition: color 0.25s var(--ease); }
.footer__legal a:hover { color: var(--chalk); }

/* ------------------------------------------------------------- lightbox -- */

.lb {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: var(--ink-sink);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s var(--ease), visibility 0.35s;
}
.lb.is-open { opacity: 1; visibility: visible; }

.lb__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem var(--gutter);
}

.lb__stage {
  position: relative;
  padding-inline: clamp(0.5rem, 3vw, 3rem);
  min-height: 0;
}

.lb__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.lb__img.is-ready { opacity: 1; }

.lb__nav {
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(3.5rem, 12vw, 8rem);
  display: grid;
  place-items: center;
  color: var(--chalk-dim);
  transition: color 0.25s var(--ease);
}
.lb__nav:hover { color: var(--chalk); }
.lb__nav--prev { left: 0; }
.lb__nav--next { right: 0; }
.lb__nav svg { width: 1.6rem; }
.lb__nav svg path { fill: none; stroke: currentColor; stroke-width: 4; stroke-linecap: round; vector-effect: non-scaling-stroke; }

.lb__foot { padding: 1rem var(--gutter) 1.5rem; display: flex; justify-content: space-between; gap: 1rem; }

.lb__close { display: flex; align-items: center; gap: 0.6rem; }
.lb__close svg { width: 0.85rem; }
.lb__close svg path { fill: none; stroke: currentColor; stroke-width: 5; stroke-linecap: round; vector-effect: non-scaling-stroke; }

/* --------------------------------------------------------------- reveal -- */

.reveal { opacity: 0; transform: translateY(1.25rem); }
.reveal.is-in { opacity: 1; transform: none; transition: opacity 0.9s var(--ease), transform 0.9s var(--ease-out); }

/* ------------------------------------------------------------ responsive -- */

@media (max-width: 60rem) {
  .index__row { grid-template-columns: 1fr; }
  .index__side { justify-content: space-between; }
}

@media (max-width: 30rem) {
  .lt { --lt-step: calc(var(--lt-size) * 0.4); }
  .menu__foot { gap: 0.35rem 1rem; }
}

/* landscape phones: close the staircase up rather than let it scroll away */
@media (max-height: 34rem) {
  .lt {
    --lt-gap: calc(var(--lt-size) * 0.3);
    padding-top: calc(var(--lt-size) * 0.9);
    padding-bottom: calc(var(--lt-size) * 1.4);
  }
}

@media (max-width: 47.5rem) {
  .justified__row { display: block; }
  .frame + .frame { margin-top: var(--frame-gap, 6px); }
  .hero__cue { display: none; }
  .lb__nav { width: 3rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .hero__frame { transform: none; }
  .lt:hover .lt__stack { transform: none; }
  .index__count .mark-circle path { stroke-dashoffset: 0; }
}
