/* ============================================================================
   Violet Lobo — dark gallery
   ------------------------------------------------------------------------
   1. tokens & themes      5. work / gallery grid
   2. base & typography    6. index view
   3. chrome (bar, grain)  7. about & footer
   4. hero                 8. lightbox
   ========================================================================= */


/* ── 1. tokens & themes ─────────────────────────────────────────────────── */

:root {
  /* dark is the default dress for this gallery */
  --ink:        #0a070c;
  --ink-raise:  #120e15;
  --ink-sink:   #060409;
  --fg:         #f0eaf3;
  --fg-dim:     #9d95a7;
  --fg-faint:   #6a6274;
  --line:       rgb(255 255 255 / 10%);
  --line-soft:  rgb(255 255 255 / 6%);
  --accent:     #c48cff;
  --accent-deep:#7c3fc4;
  --scrim:      rgb(6 4 9 / 88%);
  --shadow:     0 24px 60px -20px rgb(0 0 0 / 80%);
  --grain-op:   .045;
  --foot-stroke: rgb(255 255 255 / 30%);
  --art-lift:   1.3;
  --art-wash:   rgb(244 238 247 / 30%);         /* brightness applied to art inside letterforms */

  /* type */
  --serif: "Fraunces", "Iowan Old Style", Palatino, "Times New Roman", serif;
  --sans:  "Inter", ui-sans-serif, system-ui, "Segoe UI", Helvetica, Arial, sans-serif;
  --hand:  "WhyMin", var(--serif);

  /* rhythm */
  --gutter: clamp(1.25rem, 5vw, 5.5rem);
  --shell:  1760px;
  --sec-gap: clamp(6rem, 14svh, 11rem);

  /* motion */
  --ease:      cubic-bezier(.22, 1, .36, 1);
  --ease-soft: cubic-bezier(.4, 0, .2, 1);
  --dur:       .55s;

  color-scheme: dark;
}

[data-theme="light"] {
  --ink:        #f5f1ec;
  --ink-raise:  #fffdfa;
  --ink-sink:   #ebe5dd;
  --fg:         #171319;
  --fg-dim:     #5f5866;
  --fg-faint:   #8b8391;
  --line:       rgb(23 19 25 / 14%);
  --line-soft:  rgb(23 19 25 / 8%);
  --accent:     #6b2fb0;
  --accent-deep:#4a1d80;
  --scrim:      rgb(245 241 236 / 92%);
  --shadow:     0 24px 60px -24px rgb(40 25 55 / 32%);
  --grain-op:   .03;
  --foot-stroke: rgb(23 19 25 / 32%);
  --art-lift:   1;
  --art-wash:   rgb(23 19 25 / 10%);

  color-scheme: light;
}

@font-face {
  font-family: "WhyMin";
  src: url("../fonts/WhyMin.ttf") format("truetype");
  font-display: swap;
}


/* ── 2. base & typography ───────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--fg);
  font-family: var(--sans);
  font-size: clamp(.95rem, .9rem + .2vw, 1.0625rem);
  font-weight: 350;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  transition: background-color .45s var(--ease-soft), color .45s var(--ease-soft);
}

body.is-locked { overflow: hidden; }

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  font-optical-sizing: auto;
  line-height: .95;
  letter-spacing: -.02em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1em; text-wrap: pretty; }
img { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; }

a { color: inherit; }

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 3px;
}

/* the small tracked-caps label used all over the gallery */
.eyebrow, .work__num, .hero__eyebrow, .hero__foot,
.viewtoggle button, .lb__count, .about__kicker, .foot__social {
  font-family: var(--sans);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
}

.skip {
  position: fixed;
  inset-inline-start: var(--gutter);
  inset-block-start: -6rem;
  z-index: 90;
  padding: .75rem 1.25rem;
  background: var(--accent);
  color: #12071d;
  font-weight: 600;
  text-decoration: none;
  border-radius: 999px;
  transition: inset-block-start .3s var(--ease);
}
.skip:focus { inset-block-start: 1rem; }


/* ── 3. chrome: grain, scroll rail, top bar ─────────────────────────────── */

/* a whisper of film grain so flat areas never look like flat CSS */
.grain {
  position: fixed;
  inset: -50%;
  z-index: 60;
  pointer-events: none;
  opacity: var(--grain-op);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain-shift 6s steps(6) infinite;
}
@media (hover: none) { .grain { animation: none; } }

@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-3%, 2%); }
  40%  { transform: translate(2%, -3%); }
  60%  { transform: translate(-2%, -2%); }
  80%  { transform: translate(3%, 1%); }
  100% { transform: translate(0, 0); }
}

.scroll-rail {
  position: fixed;
  inset: 0 0 auto;
  z-index: 55;
  height: 2px;
  pointer-events: none;
}
.scroll-rail__fill {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent));
  transform: scaleX(var(--progress, 0));
  transform-origin: 0 50%;
}

.topbar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 1.1rem var(--gutter);
  background: color-mix(in srgb, var(--ink) 72%, transparent);
  backdrop-filter: blur(18px) saturate(1.4);
  border-bottom: 1px solid transparent;
  transition: transform .45s var(--ease), border-color .45s var(--ease-soft),
              background-color .45s var(--ease-soft);
}
.topbar.is-stuck { border-bottom-color: var(--line-soft); }
.topbar.is-hidden { transform: translateY(-101%); }

.topbar__mark {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  margin-inline-end: auto;
  text-decoration: none;
}
.topbar__initials {
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .06em;
  transition: border-color .3s, background-color .3s, color .3s;
}
.topbar__mark:hover .topbar__initials {
  background: var(--accent);
  border-color: var(--accent);
  color: #12071d;
}
.topbar__name {
  font-family: var(--serif);
  font-size: 1.0625rem;
  letter-spacing: -.01em;
}

.topbar__nav {
  display: flex;
  gap: clamp(1rem, 3vw, 2.25rem);
  font-size: .8125rem;
  letter-spacing: .01em;
}
.topbar__nav a {
  position: relative;
  padding-block: .2rem;
  color: var(--fg-dim);
  text-decoration: none;
  transition: color .3s;
}
.topbar__nav a::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform .4s var(--ease);
}
.topbar__nav a:hover { color: var(--fg); }
.topbar__nav a:hover::after { transform: scaleX(1); transform-origin: 0 50%; }
.ext { font-size: .8em; vertical-align: .35em; margin-inline-start: .15em; }

.tswitch {
  display: grid;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: border-color .3s, transform .5s var(--ease);
}
.tswitch:hover { border-color: var(--accent); transform: rotate(-25deg); }
.tswitch__icon {
  grid-area: 1 / 1;
  width: 1rem;
  height: 1rem;
  fill: none;
  stroke: var(--fg);
  stroke-width: 1.6;
  stroke-linecap: round;
  transition: opacity .3s, transform .45s var(--ease);
}
.tswitch__icon--moon { fill: var(--fg); stroke: none; }
[data-theme="dark"] .tswitch__icon--sun,
[data-theme="light"] .tswitch__icon--moon { opacity: 0; transform: scale(.4) rotate(50deg); }


/* ── 4. hero ────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 7rem var(--gutter) 3rem;
  overflow: hidden;
  isolation: isolate;
}

/* a soft bloom of the colour currently showing through the letters */
.hero__aura {
  position: absolute;
  z-index: -1;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  width: min(120vw, 1500px);
  aspect-ratio: 1;
  translate: -50% -55%;
  border-radius: 50%;
  /* the painting's own colour, pulled back toward violet so the room stays hers */
  background: radial-gradient(circle,
    color-mix(in oklab, var(--aura, #6b2fb0) 62%, var(--accent-deep)) 0%,
    transparent 62%);
  opacity: .38;
  filter: blur(90px);
  transition: background 1.8s var(--ease-soft);
}
[data-theme="light"] .hero__aura { opacity: .22; }

.hero__inner {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
}

/* wide screens: name on the left, the pitch tucked into the crook on the right */
@media (min-width: 1000px) {
  .hero__inner {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(17rem, 25rem);
    column-gap: clamp(2rem, 5vw, 5rem);
    align-items: end;
  }
  .hero__eyebrow { grid-column: 1 / -1; }
  .hero__side { padding-block-end: clamp(1rem, 4svh, 3rem); }
  .hero__lede { margin-block-start: 0; }
}

.hero__eyebrow {
  display: flex;
  align-items: center;
  gap: .85rem;
  margin: 0 0 clamp(1.25rem, 4svh, 2.5rem);
  color: var(--fg-dim);
}
.hero__eyebrow i {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--accent);
}

/* the headline: real text underneath, artwork clipped to the letters on top */
.hero__title {
  position: relative;
  margin: 0;
  font-size: clamp(3.75rem, 22vw, 21rem);
  font-weight: 300;
  line-height: .82;
  letter-spacing: -.045em;
  text-transform: none;
}
.hero__title .line { display: block; overflow: hidden; }
.hero__title .line__in,
.bleedline {
  display: block;
  font-variation-settings: "wght" 300, "SOFT" 20, "WONK" 0;
}

/* Once the paintings are actually showing, the real headline goes transparent
   and the artwork letters carry the name on their own.
   Two separate copies of the same text cannot be relied on to register
   glyph-for-glyph on every engine — Safari rasterises text-clipped paint with
   very slightly different advances, and the error accumulates across the word,
   so the plain white copy underneath was peeking out as a ghost on iOS. There
   is no second copy to misalign if only one of them is ever visible.
   The text stays in the DOM: selectable, and read aloud as normal. */
.hero__title .line__in { transition: color 1.4s var(--ease-soft); }
.hero__title.has-bleed .line__in { color: transparent; }
.hero__title .line__in--wonk,
.bleedline--wonk {
  font-style: normal;
  font-variation-settings: "wght" 300, "SOFT" 60, "WONK" 1;
  padding-inline-start: .09em;   /* nudged off-axis, the way a signature sits */
}

.hero__bleed {
  position: absolute;
  inset: 0;
  pointer-events: none;
  display: none;
}
.bleedline { display: block; }

/* only ever shown where the browser can genuinely clip paint to glyphs */
@supports (-webkit-background-clip: text) or (background-clip: text) {
  .hero__bleed {
    display: block;
    opacity: 0;
    /* The two layers sit exactly on top of one another and trade places by
       z-index, never by moving in the DOM — moving a node drops the running
       transition, which is what made the change snap rather than dissolve. */
    transition: opacity 2.4s var(--ease-soft);
  }

  /* the clip lives here, on the boxes that hold the glyphs themselves */
  .bleedline {
    /* A wash sits over the painting, inside the very same element, so the
       darkest crops still read as letters. This is the lift the plain headline
       used to give from underneath — done here instead, where it cannot fall
       out of register with anything. */
    background-image:
      linear-gradient(var(--art-wash), var(--art-wash)),
      var(--art, none);
    /* deliberately oversized (script works out by how much) so there is always
       room to pan — see the note in main.js */
    background-size: auto, var(--art-size, 135%) auto;
    background-position: 0 0, 50% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    /* Safari needs the fill colour spelled out — `color` alone leaves the
       letters painted flat over the artwork */
    -webkit-text-fill-color: transparent;
    /* each line crops its own patch of the painting, and some patches are very
       dark — lift them so the name stays readable whichever piece is showing */
    filter: saturate(1.35) brightness(var(--art-lift)) contrast(1.02);
  }

  .hero__bleed.is-on { opacity: 1; }
  [data-theme="light"] .hero__bleed.is-on { opacity: 1; }

  /* a slow pan, so a painting is never quite still while it holds the name */
  @keyframes art-drift {
    from { background-position: 0 0, 22% 26%; }
    to   { background-position: 0 0, 78% 74%; }
  }
  .hero__bleed.is-on .bleedline {
    animation: art-drift 14s var(--ease-soft) forwards;
  }
  @media (prefers-reduced-motion: reduce) {
    .hero__bleed.is-on,
    .hero__bleed.is-on .bleedline { animation: none; }
  }
}

/* single-column hero: let the name run the full width of the screen */
@media (max-width: 999px) {
  .hero__title { font-size: clamp(3.5rem, 38vw, 12rem); }
}

.hero__lede {
  max-width: 34ch;
  margin: clamp(1.75rem, 5svh, 3rem) 0 0;
  font-size: clamp(1rem, .95rem + .35vw, 1.25rem);
  color: var(--fg-dim);
  line-height: 1.55;
}

.cta {
  display: inline-flex;
  align-items: center;
  gap: .9rem;
  margin-block-start: clamp(1.75rem, 4svh, 2.75rem);
  padding: .8rem 1.6rem .8rem 1.75rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--fg);
  font-size: .875rem;
  letter-spacing: .01em;
  text-decoration: none;
  overflow: hidden;
  position: relative;
  isolation: isolate;
  transition: color .35s var(--ease-soft), border-color .35s var(--ease-soft);
}
.cta::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent);
  translate: 0 101%;
  transition: translate .5s var(--ease);
}
.cta:hover { color: #12071d; border-color: var(--accent); }
.cta:hover::before { translate: 0 0; }
.cta__arrow { transition: translate .45s var(--ease); }
.cta:hover .cta__arrow { translate: 0 .2rem; }

/* pinned to the floor of the hero so the name stays optically centred */
.hero__foot {
  position: absolute;
  inset-block-end: clamp(1.25rem, 3.5svh, 2.75rem);
  inset-inline: var(--gutter);
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1rem;
  max-width: var(--shell);
  margin-inline: auto;
  color: var(--fg-faint);
}
.hero__foot b { color: var(--fg); font-weight: 500; }
.hero__scroll { display: flex; align-items: center; gap: .7rem; }
.hero__scroll i {
  display: block;
  width: 2.5rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--fg-faint));
  animation: rail 2.4s var(--ease-soft) infinite;
}
@keyframes rail { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }


/* ── 5. work / gallery grid ─────────────────────────────────────────────── */

.work-sec {
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--sec-gap) var(--gutter) 0;
}

.sec-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: end;
  padding-block-end: clamp(2.5rem, 6svh, 4.5rem);
  border-bottom: 1px solid var(--line-soft);
}
@media (min-width: 860px) {
  .sec-head { grid-template-columns: auto minmax(0, 26rem); justify-content: space-between; }
}

.sec-head__title {
  font-size: clamp(2.75rem, 8vw, 6.5rem);
  font-weight: 300;
  line-height: .88;
  font-variation-settings: "wght" 300, "SOFT" 30, "WONK" 0;
}
.sec-head__title em {
  font-style: normal;
  color: var(--accent);
  font-variation-settings: "wght" 300, "SOFT" 70, "WONK" 1;
}

.sec-head__side { display: grid; gap: 1.5rem; justify-items: start; }
@media (min-width: 860px) { .sec-head__side { justify-items: end; text-align: right; } }
.sec-head__note { margin: 0; color: var(--fg-dim); max-width: 30ch; }

.viewtoggle {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
}
.viewtoggle button {
  padding: .5rem 1.1rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--fg-faint);
  cursor: pointer;
  transition: color .3s, background-color .35s var(--ease-soft);
}
.viewtoggle button[aria-pressed="true"] {
  background: var(--fg);
  color: var(--ink);
}
.viewtoggle button:not([aria-pressed="true"]):hover { color: var(--fg); }

/* Masonry on a grid rather than CSS columns, so the numbered pieces read
   left-to-right the way people expect. JS gives each figure a row span;
   without JS this degrades to a plain, perfectly decent aligned grid. */
.gallery {
  --col-gap: clamp(1.25rem, 2.6vw, 2.75rem);
  --row-gap: clamp(2.25rem, 4.5vw, 4rem);
  --row-unit: 8px;

  display: grid;
  grid-template-columns: 1fr;
  align-items: start;
  gap: var(--row-gap) var(--col-gap);
  padding-block: clamp(2.5rem, 7svh, 5rem);
}
@media (min-width:  620px) { .gallery { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1120px) { .gallery { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1600px) { .gallery { grid-template-columns: repeat(4, 1fr); } }
.gallery[hidden] { display: none; }

/* In masonry mode the vertical gap moves onto the items themselves: a computed
   margin always resolves to px, whereas a clamp() in a custom property does
   not, and the row-span maths has to be able to read it. */
.gallery.is-masonry {
  grid-auto-rows: var(--row-unit);
  row-gap: 0;
}

/* Blink keeps the scroll position pinned to whatever element it decided is the
   "anchor", and re-adjusts when things around it resize. In a masonry grid
   whose row spans are assigned from script, that correction can throw the page
   to the top or the bottom mid-flick. WebKit has no scroll anchoring at all,
   which is why this only ever showed up on Android. Every figure already
   reserves its height through the image's width/height attributes, so there is
   nothing here worth anchoring to. */
.gallery,
.gallery .work { overflow-anchor: none; }
.gallery.is-masonry .work { margin-block-end: var(--row-gap); }

.work { margin: 0; }

.work__hit {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  position: relative;
  isolation: isolate;
}

.work__frame {
  display: block;
  position: relative;      /* so the frame, not the button, clips the View tab */
  overflow: hidden;
  border-radius: 2px;
  background: color-mix(in srgb, var(--swatch) 30%, var(--ink-sink));
  box-shadow: 0 1px 0 var(--line-soft);
  transition: box-shadow .6s var(--ease), transform .6s var(--ease);
}
.work__frame img {
  width: 100%;
  transition: transform 1.1s var(--ease), filter .6s var(--ease-soft);
  will-change: transform;
}

.work__hit:hover .work__frame,
.work__hit:focus-visible .work__frame {
  transform: translateY(-6px);
  box-shadow:
    0 30px 60px -28px color-mix(in srgb, var(--swatch) 70%, transparent),
    0 0 0 1px var(--line);
}
.work__hit:hover .work__frame img { transform: scale(1.045); }

/* the little "View" tab that slides up out of the bottom edge */
.work__zoom {
  position: absolute;
  inset-block-end: 0;
  inset-inline-end: 0;
  z-index: 2;
  padding: .55rem 1.1rem;
  background: var(--accent);
  color: #12071d;
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  translate: 0 100%;
  transition: translate .45s var(--ease);
}
.work__hit:hover .work__zoom,
.work__hit:focus-visible .work__zoom { translate: 0 -6px; }

.work__cap {
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: .25rem .5rem;
  padding-block-start: 1rem;
}
.work__num { color: var(--accent); padding-block-start: .28rem; }
.work__title {
  display: block;
  font-family: var(--serif);
  font-size: 1.1875rem;
  font-weight: 400;
  letter-spacing: -.015em;
  font-variation-settings: "opsz" 40, "wght" 400, "SOFT" 40, "WONK" 0;
}
.work__desc {
  display: block;
  margin-block-start: .3rem;
  font-size: .8125rem;
  line-height: 1.55;
  color: var(--fg-faint);
}


/* ── 6. index view ──────────────────────────────────────────────────────── */

.indexlist {
  list-style: none;
  margin: 0;
  padding-block: clamp(1.5rem, 4svh, 3rem) clamp(2.5rem, 7svh, 5rem);
  counter-reset: idx;
}
.indexlist[hidden] { display: none; }

.indexrow { border-bottom: 1px solid var(--line-soft); }
.indexrow:first-child { border-top: 1px solid var(--line-soft); }

.indexrow button {
  display: grid;
  grid-template-columns: 3.5rem 1fr auto;
  align-items: baseline;
  gap: 1rem;
  width: 100%;
  padding: clamp(1rem, 2.4svh, 1.6rem) 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  transition: padding-inline .5s var(--ease), color .35s var(--ease-soft);
}
.indexrow button:hover { padding-inline: 1.25rem; color: var(--accent); }

.indexrow__num { color: var(--fg-faint); font-size: .6875rem; letter-spacing: .18em; }
.indexrow button:hover .indexrow__num { color: inherit; }

.indexrow__title {
  font-family: var(--serif);
  font-size: clamp(1.4rem, 3.4vw, 2.6rem);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: -.02em;
  font-variation-settings: "wght" 300, "SOFT" 30, "WONK" 0;
}
.indexrow button:hover .indexrow__title { font-variation-settings: "wght" 300, "SOFT" 80, "WONK" 1; }

.indexrow__note {
  justify-self: end;
  max-width: 32ch;
  font-size: .75rem;
  color: var(--fg-faint);
  text-align: right;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
}
@media (max-width: 760px) { .indexrow__note { display: none; } }

/* a thumbnail that trails the cursor while scanning the index */
.indexpeek {
  position: fixed;
  z-index: 40;
  top: 0;
  left: 0;
  width: clamp(180px, 17vw, 300px);
  aspect-ratio: 4 / 3;
  pointer-events: none;
  opacity: 0;
  scale: .9;
  translate: -50% -50%;
  transition: opacity .4s var(--ease-soft), scale .5s var(--ease);
  box-shadow: var(--shadow);
  overflow: hidden;
  border-radius: 2px;
}
.indexpeek.is-on { opacity: 1; scale: 1; }
.indexpeek img { width: 100%; height: 100%; object-fit: cover; }
@media (hover: none) { .indexpeek { display: none; } }


/* ── 7. about & footer ──────────────────────────────────────────────────── */

.about {
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--sec-gap) var(--gutter);
}
.about__grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 4rem);
  padding-block-start: clamp(2.5rem, 6svh, 4rem);
  border-top: 1px solid var(--line-soft);
}
@media (min-width: 860px) { .about__grid { grid-template-columns: 10rem minmax(0, 62ch); } }

.about__kicker { color: var(--accent); font-weight: 500; }
.about__body p { font-size: clamp(1.0625rem, 1rem + .5vw, 1.5rem); line-height: 1.5; color: var(--fg); }
.about__body p + p { color: var(--fg-dim); }

/* scoped past `.about__body p`, which would otherwise win on specificity */
.about__body .sig {
  font-family: var(--hand);
  font-size: clamp(2.75rem, 7vw, 4.5rem);
  line-height: 1;
  color: var(--accent);
  margin: clamp(1.5rem, 4svh, 2.5rem) 0 0;
  rotate: -3deg;
  transform-origin: 0 50%;
  opacity: .9;
}

.about__links { display: flex; flex-wrap: wrap; gap: .75rem; margin-block-start: clamp(2rem, 5svh, 3rem); }
.btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .75rem 1.4rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--fg);
  color: var(--ink);
  font-size: .8125rem;
  text-decoration: none;
  transition: background-color .35s var(--ease-soft), color .35s var(--ease-soft),
              border-color .35s var(--ease-soft), translate .35s var(--ease);
}
.btn:hover { translate: 0 -2px; background: var(--accent); color: #12071d; }
.btn--ghost { background: transparent; color: var(--fg); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--accent); }

.foot {
  padding: clamp(3rem, 8svh, 6rem) var(--gutter) clamp(2rem, 5svh, 3rem);
  border-top: 1px solid var(--line-soft);
  background: var(--ink-sink);
  overflow: hidden;
}
.foot__word {
  max-width: var(--shell);
  margin: 0 auto clamp(2rem, 6svh, 4rem);
  font-family: var(--serif);
  font-size: clamp(3rem, 15vw, 15rem);
  font-weight: 300;
  line-height: .8;
  letter-spacing: -.05em;
  color: transparent;
  -webkit-text-stroke: 1.25px var(--foot-stroke);
  font-variation-settings: "wght" 300, "SOFT" 40, "WONK" 1;
  user-select: none;
}

.foot__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1.5rem;
  max-width: var(--shell);
  margin-inline: auto;
}
.foot__social {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.foot__social a {
  color: var(--fg-dim);
  text-decoration: none;
  transition: color .3s;
}
.foot__social a:hover { color: var(--accent); }

.foot__fine {
  display: grid;
  gap: .25rem;
  margin: 0;
  font-size: .75rem;
  color: var(--fg-faint);
  text-align: right;
}
.foot__fine a { color: var(--fg-dim); text-decoration: none; }
.foot__fine a:hover { color: var(--accent); }
@media (max-width: 620px) { .foot__fine { text-align: left; } }


/* ── 8. lightbox ────────────────────────────────────────────────────────── */

.lb {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
}
.lb[hidden] { display: none; }

.lb__scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  backdrop-filter: blur(24px) saturate(1.2);
  opacity: 0;
  transition: opacity .45s var(--ease-soft);
}
.lb.is-open .lb__scrim { opacity: 1; }

.lb__stage {
  position: relative;
  display: grid;
  gap: clamp(1rem, 3svh, 1.75rem);
  justify-items: center;
  margin: 0;
  max-width: min(100%, 1400px);
  opacity: 0;
  translate: 0 18px;
  scale: .985;
  transition: opacity .5s var(--ease-soft), translate .55s var(--ease), scale .55s var(--ease);
}
.lb.is-open .lb__stage { opacity: 1; translate: 0 0; scale: 1; }

.lb__imgwrap {
  display: grid;
  place-items: center;
  min-height: 0;
}
.lb__img {
  max-width: 100%;
  max-height: min(72svh, 900px);
  width: auto;
  border-radius: 2px;
  box-shadow: var(--shadow);
  transition: opacity .3s var(--ease-soft);
}
.lb.is-swapping .lb__img { opacity: 0; }

.lb__cap {
  display: grid;
  gap: .4rem;
  justify-items: center;
  max-width: 56ch;
  text-align: center;
}
.lb__count { color: var(--accent); }
.lb__count b { color: var(--fg); font-weight: 500; }
.lb__title {
  font-size: clamp(1.35rem, 3vw, 2rem);
  font-weight: 300;
  font-variation-settings: "wght" 300, "SOFT" 40, "WONK" 1;
}
.lb__text { margin: 0; font-size: .875rem; color: var(--fg-dim); line-height: 1.6; }

.lb__x, .lb__nav {
  position: absolute;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 2.9rem;
  height: 2.9rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: color-mix(in srgb, var(--ink) 55%, transparent);
  backdrop-filter: blur(10px);
  cursor: pointer;
  transition: background-color .3s, border-color .3s, scale .3s var(--ease);
}
.lb__x:hover, .lb__nav:hover {
  background: var(--accent);
  border-color: var(--accent);
  scale: 1.08;
}
.lb__x svg, .lb__nav svg {
  width: 1.1rem;
  height: 1.1rem;
  fill: none;
  stroke: var(--fg);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.lb__x:hover svg, .lb__nav:hover svg { stroke: #12071d; }

.lb__x { top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem); }
.lb__nav { top: 50%; translate: 0 -50%; }
.lb__nav--prev { left: clamp(.5rem, 2.5vw, 2rem); }
.lb__nav--next { right: clamp(.5rem, 2.5vw, 2rem); }

@media (max-width: 700px) {
  .lb__nav { top: auto; bottom: clamp(1rem, 4svh, 2rem); translate: 0; }
  .lb__nav--prev { left: 25%; }
  .lb__nav--next { right: 25%; }
  .lb__stage { padding-block-end: 4rem; }
  .lb__img { max-height: 56svh; }
}


/* ── scroll reveal ──────────────────────────────────────────────────────── */

/* Every rule here hides something until script says otherwise, so all of them
   hang off .js — set on <html> by the inline head script. If JavaScript never
   arrives, nothing is hidden and the page simply renders. */
.js :is(.reveal, .work, .indexrow) {
  opacity: 0;
  translate: 0 22px;
  transition: opacity .8s var(--ease-soft), translate .9s var(--ease);
  transition-delay: var(--d, 0ms);
}
.js :is(.reveal, .work, .indexrow).is-in { opacity: 1; translate: 0 0; }

/* headline lines wipe up from their own overflow box on load */
.js .hero__title .line__in {
  translate: 0 105%;
  transition: translate 1.1s var(--ease), color 1.4s var(--ease-soft);
}
.js .is-ready .hero__title .line__in { translate: 0 0; }
.js .is-ready .hero__title .line:nth-child(2) .line__in { transition-delay: .1s; }

/* the layout toggle is script-driven; without it there is only the grid */
html:not(.js-ready) .viewtoggle { display: none; }

/* ── reduced motion ─────────────────────────────────────────────────────────
   Travel goes; fades stay. What causes trouble is movement — things sliding,
   scaling, drifting, or the page scrolling itself. A change in opacity is not
   a motion trigger, and blanket-killing every transition made the site look
   inert to anyone whose phone merely happens to be in Low Power Mode, which
   iOS reports here exactly as if Reduce Motion were switched on. */
@media (prefers-reduced-motion: reduce) {
  /* the page must never scroll itself — this one is squarely a motion trigger */
  html { scroll-behavior: auto; }

  /* reveals still fade, they just no longer travel to get there */
  .js :is(.reveal, .work, .indexrow) { translate: 0 0; transition-duration: .4s; }
  .js .hero__title .line__in { translate: 0 0; }

  /* every ambient or hover movement, stopped */
  .grain,
  .hero__scroll i,
  .hero__bleed.is-on { animation: none; }

  .work__hit:hover .work__frame,
  .work__hit:hover .work__frame img,
  .tswitch:hover { transform: none; }

  .btn:hover,
  .cta:hover .cta__arrow { translate: 0; }

  .indexrow button:hover { padding-inline: 0; }
  .indexpeek { display: none; }
}
