/* ============================================================
   sections
   ============================================================ */

/* ================= HERO ================= */
.hero{
  position:relative;
  min-height:100svh;
  display:grid;
  grid-template-rows:1fr auto auto;   /* face, name, meta */
  /* minmax(0,1fr), not auto: the name is sized from the width of this column,
     and an auto track widens to fit its own content — so a word set too large
     would stretch the column, which would then measure as room for a word set
     too large. the measurement has to be independent of what it measures. */
  grid-template-columns:minmax(0,1fr);
  padding-top:var(--nav-h);
  overflow:hidden;
}
.hero__stage{
  position:relative;z-index:1;
  display:grid;place-items:center;
  /* the row is 1fr of the viewport, but on a short wide screen the name and
     the standfirst eat it and the face is left a letterbox. give the portrait
     a floor and let the hero grow past one screen instead of crushing it. */
  min-height:min(70svh,46rem);
  overflow:hidden;
}
/* the plate — his portrait, full bleed, sitting in the dark. the photograph
   is already black at its edges, so it needs no vignette of its own; only a
   fade at the foot, to hand the frame over to the standfirst below it. */
/* exactly its frame: nothing moves it any more, so every pixel of height the
   frame has is a pixel of photograph rather than overhang waiting to be
   scrolled into view */
.hero__plate{
  position:absolute;inset:0;
  width:100%;height:100%;
  z-index:0;
  /* the blurred placeholder, inline from site.json, so the frame is never
     an empty black hole while the full plate is still arriving */
  background:var(--void) center/cover no-repeat;
}
.hero__plate canvas,
.hero__plate img,
.hero__plate picture{
  position:absolute;inset:0;
  width:100%;height:100%;
  /* fill the frame — the plate is meant to run to the edges of the screen */
  object-fit:cover;
  object-position:50% 50%;
  -webkit-mask-image:linear-gradient(to bottom,#000 58%,rgba(0,0,0,.35) 88%,transparent 100%);
          mask-image:linear-gradient(to bottom,#000 58%,rgba(0,0,0,.35) 88%,transparent 100%);
}
/* the fallback shows the photograph as shot — no grade of its own */
.hero__plate img{filter:none}
/* the one case filling cannot serve: a window so wide and short that any crop
   of the plate loses his head. the shader decides this from the two aspects
   directly (see `fit` in relight.js); this is the same call for the fallback
   <img>, which is all a browser without WebGL has. */
@media (min-aspect-ratio:5/2){
  .hero__plate img,
  .hero__plate picture{object-fit:contain}
}
.hero__plate.has-gl img{opacity:0}

/* the name sits under the face now, in its own row — never across it */
.hero__name{
  position:relative;z-index:3;
  display:grid;place-items:center;
  min-width:0;
  /* no top padding: app.js lifts this row into the foot of the portrait,
     and padding there would push it straight back down */
  padding:0 var(--gutter) clamp(1rem,3svh,2rem);
  pointer-events:none;
}
.hero__word{
  font-family:var(--f-display);font-weight:var(--w-display);
  font-size:clamp(2.25rem,13vw,12rem);   /* fitHeroName() overrides this */
  line-height:.95;
  letter-spacing:-.03em;
  text-transform:uppercase;
  white-space:nowrap;

  /* the letters are filled by the lamp rather than painted a flat colour: a
     radial gradient clipped to the glyphs, centred wherever the light is.
     lamp.js writes --vx/--vy per frame in this element's own pixels, already
     eased — which is the ripple, and its easing, without a second raf loop.
     it also drifts on its own with no pointer, so the name is never inert. */
  color:var(--bone);
  /* a circle's radius is a <length>, never a percentage — a percentage here
     invalidates the whole gradient, which with transparent fill means an
     invisible title. the lamp's own --lamp-r is a clamp() of lengths for the
     same reason. */
  --word-r:clamp(170px,24vw,520px);
  background-image:radial-gradient(
    circle var(--word-r) at var(--vx,50%) var(--vy,50%),
    var(--bone) 0%,
    var(--plaster) 38%,
    var(--word-far,#4A4740) 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
/* older engines keep the flat bone rather than an invisible title */
@supports not ((background-clip:text) or (-webkit-background-clip:text)){
  .hero__word{color:var(--bone);-webkit-text-fill-color:var(--bone)}
}
/* no lamp, no travel — hold the light in the middle of the word */
@media (prefers-reduced-motion:reduce){
  .hero__word{--word-r:2000px}
}

/* the furthest layer — a slow pool of light the parallax lags behind */
.hero__bg{
  position:absolute;inset:-12% 0;z-index:0;pointer-events:none;
  background:
    radial-gradient(60% 46% at 50% 34%,rgba(255,217,168,.055),transparent 70%),
    radial-gradient(90% 70% at 50% 50%,#0b0b0b,var(--void) 78%);
}


.hero__meta{
  position:relative;z-index:4;
  display:flex;justify-content:space-between;align-items:flex-end;
  gap:var(--s-4);
  padding:0 var(--gutter) clamp(1.25rem,3.5svh,2.25rem);
}
.hero__role{max-width:28rem}
.hero__standfirst{
  font-size:var(--t-body);color:var(--plaster);
  max-width:28rem;margin-top:var(--s-2);
}
.hero__stats{display:flex;gap:clamp(1.25rem,4vw,3.5rem)}
.hero__stat{display:grid;gap:.35rem;justify-items:end;text-align:right}
.hero__num{
  font-family:var(--f-display);font-weight:var(--w-display-sm);
  font-size:clamp(1.75rem,3.6vw,2.75rem);
  line-height:1;color:var(--bone);font-variant-numeric:tabular-nums;
}

/* the tall crop is framed tighter — a touch of headroom keeps the top of his
   hair inside the frame */
@media (max-width:52rem){
  .hero__meta{flex-direction:column;align-items:flex-start;gap:var(--s-4)}
  .hero__stats{width:100%;justify-content:space-between}
  .hero__stat{justify-items:start;text-align:left}
}

/* ================= ABOUT ================= */
.about__grid{
  display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(2rem,6vw,6rem);
  align-items:start;
}
.about__pull{
  font-family:var(--f-display);font-weight:var(--w-display);
  font-size:clamp(1.75rem,3.4vw,2.75rem);
  line-height:1.16;letter-spacing:-.025em;
  color:var(--bone);
  margin-bottom:var(--s-6);
  max-width:22ch;
}
.about__body{display:grid;gap:var(--s-4);max-width:38rem}
.about__body p{color:var(--plaster)}
.about__aside{display:grid;gap:var(--s-6);position:sticky;top:calc(var(--nav-h) + 2rem)}
/* the frame the card turns inside — ratio comes from the plate itself so the
   image is never squeezed to a shape it was not shot in */
.about__plate{position:relative;width:100%;aspect-ratio:0.7626;perspective:1100px}

.slabs{display:grid;gap:0;border-top:1px solid var(--hairline)}
.slab{
  display:flex;justify-content:space-between;align-items:baseline;gap:var(--s-3);
  padding-block:var(--s-3);
  border-bottom:1px solid var(--hairline-soft);
}
.slab__k{font-family:var(--f-display);font-weight:var(--w-display-sm);font-size:1.375rem;color:var(--bone);line-height:1.1}
.slab__v{font-family:var(--f-data);font-size:var(--t-data);text-transform:uppercase;letter-spacing:.2em;color:var(--clay);text-align:right}

.traits{display:grid;gap:var(--s-2)}
.traits li{
  display:grid;grid-template-columns:auto 1fr;gap:var(--s-3);align-items:baseline;
  font-size:1rem;color:var(--plaster);
}
.traits li::before{content:"";width:1.5rem;height:1px;background:var(--hairline);transform:translateY(-.35em)}

.counters{
  display:grid;
  /* auto-fit, not repeat(3): at 320px three fixed columns are 77px each and
     "5,000+" is 150px, so the third figure was being clipped by the body's
     overflow-x rather than wrapping */
  grid-template-columns:repeat(auto-fit,minmax(7.5rem,1fr));
  gap:var(--s-5) var(--s-4);
  margin-top:var(--s-8);padding-top:var(--s-6);
  border-top:1px solid var(--hairline);
}
.counter__n{
  font-family:var(--f-display);font-weight:var(--w-display);
  font-size:clamp(2.75rem,7vw,5.25rem);
  line-height:.95;color:var(--bone);font-variant-numeric:tabular-nums;
}
.counter__l{margin-top:var(--s-2)}

.press{display:flex;flex-wrap:wrap;gap:var(--s-2) var(--s-4);margin-top:var(--s-6)}
.press li{font-family:var(--f-data);font-size:var(--t-data);text-transform:uppercase;letter-spacing:.18em;color:var(--clay)}
.press li+li::before{content:"·";margin-right:var(--s-4);color:var(--hairline)}

@media (max-width:60rem){
  .about__grid{grid-template-columns:1fr}
  .about__aside{position:static}
}

/* ================= FILMS ================= */
/* the banner is one row now, not a five-deep grid: it needs neither the
   head's gap doubled underneath it nor a full section's worth of floor.
   the join above it is tightened from both sides — a section that ends on a
   line of press credits and one that opens on a kicker were putting 109px
   each into the same empty band, and it read as a hole in the page. */
.films{padding-block:var(--s-6)}
.about{padding-bottom:var(--s-6)}
.films__wall{position:relative;--poster-gap:clamp(.5rem,1.1vw,1.1rem)}
/* the window the belt runs behind. clip, not hidden: hidden is still a
   scroll container, so tabbing to a poster off the edge would scroll it
   and leave the belt out of step with its own transform.
   padding leaves room for the hover lift and its shadow. */
.films__viewport{
  overflow:hidden;
  overflow:clip;
  padding-block:1rem 1.4rem;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 7%,#000 93%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 7%,#000 93%,transparent 100%);
}
/* motion.js drives the transform — see belt() */
.films__belt{display:flex;width:max-content;will-change:transform}
.films__set{display:flex}
/* margin, not gap: every poster is the same total width, so one set
   measures N x pitch exactly and the wrap lands on the seam to the
   pixel. a flex gap would leave the join half a gap short. */
.poster{
  position:relative;flex:0 0 auto;
  width:clamp(11rem,17vw,17rem);
  margin-inline-end:var(--poster-gap);
}

/* no lift, no zoom: the posters open nothing, so nothing here should
   promise a click. the lamp is the only thing that answers the pointer. */
.poster__media{
  position:relative;display:block;width:100%;
  aspect-ratio:2/3;overflow:hidden;
  background:var(--slab) center/cover no-repeat;
}
.poster__media img{width:100%;height:100%;object-fit:cover}

.poster__cap{
  position:relative;z-index:3;
  display:grid;gap:.25rem;
  padding-top:.7rem;
}
.poster__t{
  font-family:var(--f-data);font-size:.75rem;font-weight:700;
  text-transform:uppercase;letter-spacing:.12em;color:var(--plaster);
  line-height:1.3;
}
.poster__y{font-family:var(--f-data);font-size:.6875rem;letter-spacing:.18em;color:var(--clay);text-transform:uppercase}

/* the veil: the wall is grey and dim except where the lamp falls */
.veil{
  position:absolute;inset:-8vh -3vw;z-index:2;pointer-events:none;
  --veil-mask:radial-gradient(circle var(--lamp-r) at var(--vx,50%) var(--vy,20%),
      transparent 0%,transparent 27%,
      rgba(0,0,0,.34) 49%,rgba(0,0,0,.8) 74%,#000 100%);
  -webkit-backdrop-filter:grayscale(1) brightness(.46) contrast(1.08);
          backdrop-filter:grayscale(1) brightness(.46) contrast(1.08);
  -webkit-mask-image:var(--veil-mask);
          mask-image:var(--veil-mask);
}

.no-bdf .veil{display:none}
.no-bdf .poster__media img{filter:grayscale(1) brightness(.7);transition:filter var(--d-mid) var(--e-out),transform var(--d-slow) var(--e-out)}
/* with no veil there is no lamp, so hover is the only way colour comes back.
   the posters are no longer buttons, so this hangs off the figure itself —
   without it they would sit grey for good in a no-backdrop-filter browser.
   the slider is unveiled, so it needs nothing here. */
.no-bdf .poster:hover .poster__media img{filter:none}

.films__wall .veil{inset:-8vh 0}

@media (prefers-reduced-motion:reduce){
  .veil{display:none}
  /* the plate still swaps in on hover, it just stops drifting */
  .reveal__plate{transition:opacity var(--d-fast) var(--e-out)}
  /* nothing moves on its own: one set, pushed by hand */
  .films__set + .films__set{display:none}
  .films__viewport{overflow:auto hidden;scroll-snap-type:x proximity}
  .films__viewport .poster{scroll-snap-align:center}
}

@media (max-width:34rem){.films__wall{--poster-gap:.5rem}}

/* ================= WORKS ================= */
/* ================= THE ARTWORKS WORD ================= */
/* set in the 800 cut — the heaviest thing on the site, because a plate seen
   through a glyph needs glyph to see it through. the display serif would
   leave nothing but hairlines. */
.reveal{
  display:flex;flex-wrap:wrap;
  /* it sits inside .head now, under the kicker — the head's own grid gap
     spaces it, so it carries no margin of its own */
  font-family:var(--f-body);
  font-weight:800;
  font-size:clamp(3rem,12.5vw,10rem);
  line-height:.92;
  letter-spacing:-.045em;
}
.reveal__l{position:relative;display:inline-block;cursor:default}

/* the base letter carries the layout; the other two ride on top of it, so the
   clipped plate lands on the glyph exactly without measuring anything */
.reveal__base{color:var(--bone);transition:opacity var(--d-fast) var(--e-out)}
.reveal__plate,
.reveal__sweep{position:absolute;inset:0;pointer-events:none}

.reveal__plate{
  opacity:0;
  /* background-image comes from the inline style — see render.revealWord() */
  background-size:cover;
  background-position:0% center;
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
  transition:opacity var(--d-fast) var(--e-out),
             background-position 3s var(--e-out);
}
.reveal__l:hover .reveal__base{opacity:0}
/* the plate drifts while you hold the letter — the same slow pan the lamp has */
.reveal__l:hover .reveal__plate{opacity:1;background-position:10% center}

/* the pass that runs through the word once it has landed. tungsten, because
   the site has no accent colour and the lamp is the only warmth on it. */
.reveal__sweep{color:var(--tungsten);opacity:0}

@media (max-width:34rem){.reveal{letter-spacing:-.03em}}

.works{position:relative}

/* ================= THE PLATE SLIDER ================= */
/* full-bleed, one sculpture at a time. the canvas draws the glass
   transition; the <img> under it is the no-WebGL and reduced-motion
   fallback, so something correct is always on screen. */
.slider{
  position:relative;
  margin-top:var(--s-7);
  height:min(100svh,54rem);
  overflow:hidden;
  background:var(--void);
  isolation:isolate;
}
.slider__still,
.slider__canvas{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  /* the plates are tall and this frame is wide, so most of the height is
     cropped. hold the top — that is where the heads are. the shader does the
     same with its `bias` uniform; this is the fallback's copy of that call. */
  object-position:50% 22%;
  display:block;
}
.slider__canvas{opacity:0;transition:opacity .6s var(--e-out)}
.slider.is-live .slider__canvas{opacity:1}
.slider.is-live .slider__still{opacity:0}
.slider.is-flat .slider__canvas{display:none}
.slider__still{transition:opacity .6s var(--e-out)}

/* the plate is a photograph and the type sits on it, so the type needs
   its own ground — a wash from the bottom left, where the words are */
.slider::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to top,rgba(0,0,0,.86) 0%,rgba(0,0,0,.5) 34%,transparent 68%),
    linear-gradient(to right,rgba(0,0,0,.7) 0%,transparent 52%);
}

/* it rides with the copy: at the top of the frame it sat behind the fixed nav,
   which floats over the slider whenever the section reaches the top */
.slider__count{
  display:flex;align-items:baseline;gap:.4rem;
  color:var(--bone);
}
.slider__slash{color:var(--clay)}

.slider__content{
  position:absolute;z-index:2;
  left:var(--gutter);bottom:var(--gutter);
  max-width:min(34rem,62%);
  display:grid;gap:var(--s-3);justify-items:start;
}
.slider__title{
  font-family:var(--f-display);font-weight:var(--w-display);
  font-size:clamp(2rem,5.2vw,4rem);
  line-height:1;letter-spacing:-.035em;
  color:var(--bone);
}
/* one span per letter for the entrance, boxed a word at a time so a line
   can only break between words */
.slider__w{display:inline-block;white-space:nowrap}
.slider__c{display:inline-block;will-change:transform,opacity}
.slider__desc{color:var(--plaster);max-width:30rem}
.slider__open{
  margin-top:var(--s-2);
  color:var(--plaster);
  text-transform:uppercase;letter-spacing:.2em;
  padding-bottom:.3rem;
  border-bottom:1px solid var(--hairline);
  transition:color var(--d-fast) var(--e-out),border-color var(--d-fast) var(--e-out);
}
.slider__open:hover,.slider__open:focus-visible{color:var(--bone);border-color:var(--bone)}

/* the list down the right, each with its own clock */
.snav{
  position:absolute;z-index:2;
  right:var(--gutter);bottom:var(--gutter);
  display:grid;gap:.55rem;justify-items:end;
  max-width:16rem;
}
.snav__item{
  display:grid;gap:.4rem;justify-items:end;width:100%;
  text-align:right;opacity:.42;
  transition:opacity var(--d-mid) var(--e-out);
}
.snav__item:hover,.snav__item:focus-visible,.snav__item.is-on{opacity:1}
.snav__line{display:block;width:100%;height:1px;background:var(--hairline);overflow:hidden}
.snav__fill{
  display:block;height:100%;width:0%;
  background:var(--bone);
  transition:width .1s linear;
}
.snav__t{
  font-family:var(--f-data);font-size:.6875rem;
  text-transform:uppercase;letter-spacing:.16em;
  color:var(--plaster);line-height:1.3;
}
.snav__item.is-on .snav__t{color:var(--bone)}

@media (max-width:60rem){
  .slider{height:min(86svh,44rem)}
  .slider__content{max-width:100%;right:var(--gutter)}
  /* the titles would crowd the plate, so the clocks run as one bar instead.
     offset by the nav height — the fixed chrome floats over the slider
     whenever the section reaches the top of the viewport. */
  .snav{max-width:none;left:var(--gutter);right:var(--gutter);
        grid-auto-flow:column;grid-auto-columns:1fr;gap:.4rem;
        bottom:auto;top:calc(var(--nav-h) + .75rem)}
  .snav__t{display:none}
  .snav__item{opacity:.32}
}

/* ================= VOICES ================= */
/* the columns already fade out at their foot — a full section's padding under
   that reads as a hole, not as breathing room */
#voices{padding-bottom:var(--s-6)}
.voices__cols{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(1rem,2vw,2rem);
  height:min(78vh,44rem);
  overflow:hidden;
  /* a shorter fade at the foot: at 12% it was clearing 84px of the column and
     reading as a gap rather than as cards going quiet */
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 8%,#000 95%,transparent);
          mask-image:linear-gradient(180deg,transparent,#000 8%,#000 95%,transparent);
}
.voices__col{display:grid;gap:clamp(1rem,2vw,2rem);align-content:start;will-change:transform}
.voices__col--b{margin-top:-6rem}
.voices__col--c{margin-top:-12rem}
.quote{
  border:1px solid var(--hairline-soft);
  background:linear-gradient(180deg,var(--slab-raised),var(--slab));
  padding:clamp(1.25rem,2.2vw,2rem);
  display:grid;gap:var(--s-4);
  transition:border-color var(--d-mid) var(--e-out),background var(--d-mid) var(--e-out);
}
.quote:hover{border-color:var(--hairline);background:linear-gradient(180deg,#2A2A2A,var(--slab-raised))}
.quote__mark{font-family:var(--f-display);font-weight:var(--w-display-sm);font-size:2.5rem;line-height:.6;color:var(--hairline);height:1rem}
.quote__t{font-size:1.0625rem;line-height:1.55;color:var(--bone);font-weight:300}
.quote__by{display:grid;gap:.25rem;padding-top:var(--s-2);border-top:1px solid var(--hairline-soft)}
.quote__n{font-family:var(--f-data);font-style:normal;font-size:.8125rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em;color:var(--plaster)}
.quote__r{font-family:var(--f-data);font-size:.75rem;text-transform:uppercase;letter-spacing:.16em;color:var(--clay)}
@media (max-width:60rem){
  .voices__cols{grid-template-columns:1fr 1fr;height:min(70vh,38rem)}
  .voices__col--c{display:none}
}
@media (max-width:44rem){
  .voices__cols{grid-template-columns:1fr;height:auto;mask-image:none;-webkit-mask-image:none}
  .voices__col--b,.voices__col--c{display:none}
}

/* ================= CONTACT ================= */
/* asymmetric on purpose: the top padding opens the section, but the same
   measure underneath is dead space — the foot is the end of the page, and
   nothing follows it that needs separating from. */
.contact{
  padding-block:clamp(4rem,9vh,6.5rem) var(--s-5);
  position:relative;overflow:hidden;
}
.contact__grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:clamp(2rem,5vw,5rem);align-items:center}
/* the card itself is .card3d in base.css — this is only its frame here */
.contact__plate{
  position:relative;aspect-ratio:4/5;width:100%;
  perspective:1100px;
}
@media (max-width:60rem){
  .contact__grid{grid-template-columns:1fr}
  .contact__plate{display:none}
}
.contact__title{
  font-family:var(--f-display);font-weight:var(--w-display);
  font-size:clamp(2.75rem,9vw,7.5rem);
  line-height:.95;letter-spacing:-.04em;color:var(--bone);
  max-width:16ch;
}
.contact__body{max-width:34rem;margin-top:var(--s-5)}
/* the button itself is .btn in base.css — this is only where it sits */
.contact__hello{margin-top:var(--s-7)}
.contact__links{display:flex;flex-wrap:wrap;gap:var(--s-5);margin-top:var(--s-7)}
.contact__link{
  font-family:var(--f-data);font-size:var(--t-data);
  text-transform:uppercase;letter-spacing:.2em;color:var(--plaster);
  padding-bottom:.3rem;border-bottom:1px solid transparent;
  transition:color var(--d-fast) var(--e-out),border-color var(--d-fast) var(--e-out);
}
.contact__link:hover{color:var(--bone);border-color:var(--hairline)}

.foot{
  display:flex;justify-content:space-between;align-items:center;gap:var(--s-4);
  padding:var(--s-5) 0 var(--s-4);
  border-top:1px solid var(--hairline-soft);
  flex-wrap:wrap;
}

/* ================= LIGHTBOX ================= */
.lb{
  position:fixed;inset:0;z-index:200;
  display:grid;grid-template-rows:auto minmax(0,1fr) auto;
  overflow:hidden;
  background:rgba(0,0,0,.94);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  opacity:0;visibility:hidden;
  transition:opacity .35s var(--e-out),visibility .35s;
}
.lb.is-open{opacity:1;visibility:visible}
.lb__bar{display:flex;justify-content:space-between;align-items:center;gap:var(--s-4);padding:var(--s-4) var(--gutter)}
.lb__stage{position:relative;min-height:0;overflow:hidden}
/* the plates are not one shape — portrait sculptures, landscape stills — and the
   stage is a fixed window, so the box is made to fill the window and the picture
   is fitted inside it. the stage's own height is computed `auto` (the grid row
   gives it a used height only), so a percentage height on a normal child has
   nothing to resolve against: that is why max-height:100% was silently dropped
   here and a 1382px plate laid out full height with the stage clipping it.
   positioned absolutely, percentages resolve against the stage's *used* box, so
   height:100% holds. the explicit width matters too — an absolutely positioned
   replaced element does not stretch to its insets, it falls back to intrinsic. */
.lb__img{
  position:absolute;
  top:0;left:50%;transform:translateX(-50%);
  width:min(calc(100% - var(--gutter) * 2),64rem);
  height:100%;
  object-fit:contain;
}
.lb__foot{display:flex;justify-content:space-between;align-items:flex-end;gap:var(--s-4);padding:var(--s-4) var(--gutter) var(--s-6);flex-wrap:wrap}
.lb__t{font-family:var(--f-display);font-weight:var(--w-display-sm);font-size:clamp(1.5rem,3vw,2.25rem);color:var(--bone);line-height:1.05}
.lb__meta{max-width:32rem;margin-top:var(--s-2)}
.lb__nav{display:flex;gap:var(--s-2)}
.lb__btn{
  width:3rem;height:3rem;display:grid;place-items:center;
  border:1px solid var(--hairline);color:var(--plaster);
  transition:border-color var(--d-fast),color var(--d-fast),background var(--d-fast);
}
.lb__btn:hover{border-color:var(--bone);color:var(--bone);background:rgba(255,255,255,.04)}
.lb__x{font-family:var(--f-data);font-size:var(--t-data);text-transform:uppercase;letter-spacing:.2em;color:var(--plaster);display:flex;align-items:center;gap:.6rem}
.lb__x:hover{color:var(--bone)}
