/* ============================================================
   SECTION 1 — HERO
   The background field and the portrait are both painted by the
   canvas, so this file only positions things around them.
   ============================================================ */
/* --vh, not vh: on a phone the address bar changes 100vh mid-scroll, and a
   track that follows it drags the whole document under the reader */
.sticky-track.home-hero { height: calc(var(--vh, 1vh) * 200); }
.sticky-item.home-hero  { position: sticky; top: 0; }

.s.home-hero { z-index: 10; }

.c.home-hero {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  max-width: none;
  min-height: calc(var(--vh, 1vh) * 100);
  overflow: clip;
  /* the ground comes from the fixed field behind the page */
  background-color: transparent;
}

/* ---------- canvas stage ---------- */
/* the field is a fixed layer behind every section — it starts on the hero's
   light ground and cools with the fold, so the shapes keep running under the
   marquee and the statement instead of scrolling away with section 1 */
.gl-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* what shows if WebGL never comes up */
  background-color: var(--hero-bg);
}

.hero-stage {
  position: absolute;
  inset: 0;
  z-index: 20;
  transform-origin: 50% center;
  pointer-events: none;
}

/* the signature lands across the middle of the panel */
.hero-signature {
  position: absolute;
  z-index: 25;
  /* deliberately unclipped: the scrawl runs past the panel edges.
     Physical left/top here on purpose — the logical properties flip under
     RTL and would park this off to one side. */
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  /* 1.68× the panel, the ratio the desktop crop was signed off at; the cap
     keeps it inside the window on a phone, where that ratio would run off */
  width: min(var(--sig-w), 96vw);
  max-width: none;
  height: auto;
  overflow: visible;
  opacity: 0;
  pointer-events: none;
}


.gl-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: calc(var(--vh, 1vh) * 100);
  transform-origin: 50% center;
  pointer-events: none;
}
.gl-canvas canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* ---------- tablet / mobile strapline ---------- */
.home-hero-tablet-hero-text {
  position: absolute;
  z-index: 20;
  inset-inline: 0;
  top: calc(var(--nav-block) + 1.4rem);
  display: none;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  color: var(--color--black);
}
@media screen and (max-width: 991px) {
  .c.home-hero { align-items: flex-start; }
  .home-hero-tablet-hero-text { display: flex; }
}

@media screen and (max-width: 479px) {
  .gl-canvas { height: 100svh; }
  /* the full lockup in the nav already says it — the strapline is noise here */
  .home-hero-tablet-hero-text { display: none; }
}

/* the panel crop. hero.js rebuilds these from the window on load and on every
   resize — the values here are only what the first paint reads. */
:root { --panel-v: 19.5; --panel-h: 31.5; --sig-w: 57rem; }

/* ============================================================
   SECTION 2 — MARQUEE
   Sits over the hero inside the same sticky track and arrives as the
   portrait folds into its panel.
   ============================================================ */
.s.home-marquee {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  pointer-events: none;
  opacity: 0;
}

.c.is-marquee {
  position: relative;
  max-width: none;
  width: 100%;
  /* the running copy is full bleed — the container's side padding was
     clipping it a rem short of each edge */
  padding-inline: 0;
}

/* ---- the two counter-running lines ---- */
.marquee-band {
  display: flex;
  flex-direction: column;
  /* the band lays its tracks left-to-right; without this the RTL flow pins
     each track to the right edge and translating it left empties the window */
  direction: ltr;
  gap: .4rem;
  width: 100%;
  overflow: clip;
}
.marquee-row {
  display: flex;
  flex: 0 0 auto;
  width: max-content;
  /* the track runs left-to-right so it starts flush left and can travel;
     each copy keeps its own RTL so the Hebrew reads correctly */
  direction: ltr;
  font-family: var(--font--display);
  font-size: 8rem;
  font-weight: var(--wght--display-bold);
  line-height: 1;
  white-space: nowrap;
  will-change: transform;
}
.marquee-row span { display: block; direction: rtl; padding-inline-end: 2rem; }
/* the lime line runs light, the off-white one bold — the display family's
   two weights, the way the reference sets them */
.marquee-row.is-1 { color: var(--color--lime); font-weight: var(--wght--display-light); }
.marquee-row.is-2 { color: var(--color--green-off-white-1); }

/* the copy runs at a constant share of the window's width — 8rem lands on
   7.4% of it above 992px, and so does 6.4rem in the tablet band below, where
   the fluid root is anchored to a narrower window */
@media screen and (max-width: 991px) {
  .marquee-row { font-size: 6.4rem; }
}
@media screen and (max-width: 479px) {
  .marquee-row { font-size: 4.6rem; }
}

/* ---- portrait windows: the copy sits under the panel ----
   hero.js sets data-marquee-mode="below" on <html> for anything under 992px
   that isn't clearly landscape. A panel at portrait proportions leaves no
   readable room beside it, so the two lines move underneath it. */
/* .c is a positioning anchor on desktop only; here the band measures itself
   against the section, which is the full window */
[data-marquee-mode="below"] .c.is-marquee { position: static; }

[data-marquee-mode="below"] .marquee-band {
  position: absolute;
  inset-inline: 0;
  /* centred in the gap between the panel's bottom edge and the window's */
  top: calc(75% + var(--panel-v) * .5%);
  translate: 0 -50%;
}

/* ============================================================
   SECTION 3 — STATEMENT
   One paragraph, centred, on the dark ground the marquee leaves
   behind. The mark and the eyebrow sit above it; two words carry
   the lime. The lines wipe in one after another on the way in.
   ============================================================ */
.s.home-impact {
  display: flex;
  justify-content: center;
  align-items: center;
  /* the reference gives this section a little over three quarters of the
     window — enough air around the sentence to make it the only thing there */
  min-height: calc(var(--vh, 1vh) * 80);
  padding-block: var(--padding--xlarge);
  /* transparent on purpose — the fixed field carries the dark ground here */
  background-color: transparent;
}

.c.is-impact {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.6rem;
}

.impact-icon-w {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  color: var(--color--green-off-white-1);
}
/* the mesh carries its own alpha now — white lines, everything else clear.
   It used to be white-on-black leaning on mix-blend-mode: screen to drop the
   black, which cost a re-composite and left a visible square anywhere the
   ground was not pure black. */
.impact-icon {
  width: auto;
  height: 9rem;
}

.text-impact {
  /* the measure, not the copy, decides the stack: 14ch lands the sentence on
     five lines, the same tall centred block shape the reference gets from
     seven English ones */
  max-width: 14ch;
  /* the display face — the text face is only right for small copy, and the
     rest of the Hebrew on the site is set in liebling */
  font-family: var(--font--display);
  font-size: var(--text--impact);
  font-weight: var(--wght--display-bold);
  line-height: .9;
  letter-spacing: -.01em;
  text-align: center;
  color: var(--color--green-off-white-1);
}
/* the two words that carry the sentence swap to the display face and the
   lime, and lime runs light — the rule the marquee follows */
.text-impact strong {
  font-family: var(--font--display);
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}

/* the sentence grows relative to the window as the window narrows — the
   reference runs 7rem on a desktop and half that on a phone */
@media screen and (max-width: 991px) {
  .text-impact { font-size: 6.5rem; }
  .s.home-impact { min-height: calc(var(--vh, 1vh) * 76); }
}
@media screen and (max-width: 479px) {
  /* the container is already narrower than the measure here */
  .text-impact { max-width: none; font-size: 4rem; letter-spacing: -.018em; }
  .impact-icon { height: 6rem; }
  .c.is-impact { gap: 2rem; }
}

/* ============================================================
   SECTION 4 — THE TWO SIDES
   The ground turns light again here, so everything in this
   section is set in the dark green. Two columns around the
   centre, two photographs cut off by the window's edges.
   ============================================================ */
/* the hold is half a screen, not a whole one. At 200vh the last stretch of
   the pin had nothing left to animate — a full screen of wheel input against
   a frozen frame, which reads as the page being stuck. */
.sticky-track.home-work { height: calc(var(--vh, 1vh) * 150); }
.sticky-item.home-work  { position: sticky; top: 0; }

.s.home-work {
  display: flex;
  justify-content: center;
  align-items: center;
  height: calc(var(--vh, 1vh) * 100);
  overflow: clip;
  color: var(--color--dark-green);
}

.c.is-work {
  position: relative;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ---- the pair of columns ---- */
.work-layout {
  position: relative;
  z-index: 2;
  display: flex;
  gap: 3.75rem;
}

.work-col {
  display: flex;
  flex-direction: column;
  width: 21.2rem;
  will-change: transform;
}

.work-title { margin: 0; }
.work-title-line {
  display: block;
  font-family: var(--font--display);
  line-height: .81;
  letter-spacing: -.03em;
}
/* the word that separates the two sides runs light, the shared one heavy —
   the pair reads as one phrase with the weight on what they have in common */
.work-title-line.is-a { font-size: 7.3rem; font-weight: var(--wght--display-light); }
.work-title-line.is-b { font-size: 7rem;   font-weight: var(--wght--display-bold); }

.work-p {
  margin: 1.6rem 0 0;
  max-width: 20rem;
  font-family: var(--font--sans);
  font-size: 1.75rem;
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -.007em;
}
.work-p strong { font-weight: 800; }

.btn-w.is-icon {
  width: 3.7rem;
  height: 3.7rem;
  margin-top: 1.6rem;
  padding-inline: 0;
  border-radius: 50%;
  align-self: flex-start;
}
.btn-icon.is-arrow { width: 1.5rem; height: 1.5rem; }

/* the right-hand column faces the other way: type, paragraph and button all
   run to its left edge, and its arrow turns to match */
.work-col.is-1 { text-align: left; }
.work-col.is-1 .work-p { margin-inline-start: auto; }
.work-col.is-1 .btn-w.is-icon { align-self: flex-end; }
.work-col.is-1 .btn-icon.is-arrow { scale: -1 1; }

/* ---- the two photographs, cut off by the window ---- */
.work-bg {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.work-img-w {
  position: absolute;
  top: 37%;
  bottom: 0;
  width: 28rem;
  overflow: clip;
}
/* on a desktop the pair stands taller, so the faces come up to the height of
   the copy the way the reference frames its photographs. The width is capped
   against the viewport so a wide-and-short window can never push a figure
   into the columns. */
@media screen and (min-width: 992px) {
  .work-img-w { top: 21%; width: min(36rem, 27vw); }
}
.work-img-w.is-1 { inset-inline-start: 0; }
.work-img-w.is-2 { inset-inline-end: 0; }
/* the window's height decides how big a figure stands — its width only
   decides how much of the figure the screen keeps. Each one is anchored to
   the side it faces, so what the edge takes is the back of the head and the
   back, never the face. */
.work-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* the reset caps images at their container */
  max-width: none;
  object-fit: cover;
  will-change: transform;
}
.work-img-w.is-1 .work-img { object-position: left bottom; }
.work-img-w.is-2 .work-img { object-position: right bottom; }

/* the reveal bar rides in the dark tint here — lime would burn on a light
   ground, and the reference wipes this section in the tint too */
.s.home-work .high-line-reveal { background-color: var(--color--dark-green-tint-1); }

@media screen and (max-width: 991px) {
  .work-layout { gap: 2.4rem; }
  .work-col { width: 18rem; }
  .work-title-line.is-a { font-size: 6rem; }
  .work-title-line.is-b { font-size: 5.8rem; }

  .work-img-w { top: 24%; width: 22rem; }
}
/* ============================================================
   SECTION 5 — THE STILL
   One frame, full bleed, no copy. The image is taller than the
   window on purpose: the parallax lifts it as the section passes
   and there has to be something under the bottom edge.
   ============================================================ */
.s.home-still {
  position: relative;
  height: calc(var(--vh, 1vh) * 100);
  overflow: clip;
}
.still-img {
  position: absolute;
  inset-inline: 0;
  /* hung 10% above the window and 130% tall: the lift travels 20% of the
     window, so the bottom edge lands exactly on it at the end of the pass.
     At 120% it stopped 10% short and the field showed through under the
     frame. Every extra percent beyond that is width the cover crop takes
     off the sides of a landscape frame, so this is the floor, not a margin. */
  top: -10%;
  height: 130%;
  width: 100%;
  max-width: none;
  object-fit: cover;
  object-position: center;
  will-change: transform;
}

/* ============================================================
   SECTION 6 — THE GALLERY
   Four columns on the dark ground. The cells ride in staggered
   and settle flat, and each one swaps to its second picture under
   an ellipse that opens from the top.
   ============================================================ */
.s.home-gallery {
  padding-block: var(--padding--xlarge) var(--padding--large);
  /* this section takes the page off the moving field and onto flat black */
  background-color: var(--color--near-black);
  color: var(--color--white);
}

.gallery-head {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
  margin-bottom: 3.4rem;
}
.gallery-title {
  grid-column: span 2;
  margin: 0;
  font-family: var(--font--display);
  font-size: var(--text--h2);
  font-weight: var(--wght--display-bold);
  line-height: .886;
  letter-spacing: -.028em;
}
.gallery-title-line { display: block; }
/* the second line runs light and yellow — lime always runs light here */
.gallery-title-line:last-child {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}

.gallery-lead {
  margin: 0;
  font-family: var(--font--sans);
  font-size: 1.25rem;
  line-height: 1.25;
  color: var(--color--grey-on-track);
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
}

/* the cell is not a rectangle: the reference cuts a step out of one bottom
   corner and hangs the label in it. The mask below clips the card to that
   shape and the outline draws it — both mirrored, because we read right to
   left, so the step lands in the bottom-left corner. */
.card {
  position: relative;
  display: block;
  /* the reference's cell is a hair off square */
  aspect-ratio: 406.89 / 411;
  color: var(--color--dark-green-tint-2);
  transition: color var(--animation-default);
}

/* the card: everything that has to stop at the cut edge */
.card-media {
  position: absolute;
  inset: 0;
  display: block;
  overflow: clip;
  background-color: var(--color--near-black);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 407 411' preserveAspectRatio='none'%3E%3Cpath transform='scale(-1 1) translate(-407 0)' d='M8 .5h390.89a7.5 7.5 0 0 1 7.5 7.5v356.983a7.5 7.5 0 0 1-7.5 7.5H263.329a23.502 23.502 0 0 0-18.375 8.849l-16.499 20.695a22.502 22.502 0 0 1-17.593 8.473H8A7.5 7.5 0 0 1 .5 403V8A7.5 7.5 0 0 1 8 .5Z' fill='%23fff'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 407 411' preserveAspectRatio='none'%3E%3Cpath transform='scale(-1 1) translate(-407 0)' d='M8 .5h390.89a7.5 7.5 0 0 1 7.5 7.5v356.983a7.5 7.5 0 0 1-7.5 7.5H263.329a23.502 23.502 0 0 0-18.375 8.849l-16.499 20.695a22.502 22.502 0 0 1-17.593 8.473H8A7.5 7.5 0 0 1 .5 403V8A7.5 7.5 0 0 1 8 .5Z' fill='%23fff'/%3E%3C/svg%3E");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.gallery-base,
.gallery-reveal {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}
.gallery-base { transition: transform var(--animation-default); }

/* the second picture waits behind an ellipse with no height, pinned to the
   top edge; on hover it opens past the bottom and un-zooms as it lands */
.gallery-reveal {
  background: url('../assets/work/gallery-hover.webp') center / cover no-repeat;
  clip-path: ellipse(100% 0% at 50% 0%);
  transform: scale(1.05);
  transition: clip-path var(--animation-default), transform var(--animation-default);
}

/* the outline sits above the card and takes its colour from the cell */
.card-frame {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.card-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* the label hangs in the step, outside the card */
.card-meta {
  position: absolute;
  z-index: 3;
  bottom: 1%;
  /* physical left on purpose: the step is mirrored to that corner, and the
     logical property would flip it back under RTL */
  left: 0;
  /* the shelf the step cuts is measured to the longest caption at runtime —
     gallery.js writes --card-shelf and redraws the outline to match. 36% is
     the reference's own cut, and the floor this never goes below. */
  width: var(--card-shelf, 36%);
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding-inline: .9rem;
  font-family: var(--font--sans);
  font-size: max(12px, .9rem);
  line-height: 1.25;
  white-space: nowrap;
}
/* the client carries the caption, the discipline answers it in the lime.
   Names, not roles: card-date used to hold a year, and a class called date
   holding "Branding" is a class that lies to the next person reading it. */
.card-client   { font-weight: 300; color: var(--color--white); }
.card-category { font-weight: 700; color: var(--color--lime); }

.card:hover .gallery-base,
.card.is-hover .gallery-base   { transform: scale(1.1); }
.card:hover .gallery-reveal,
.card.is-hover .gallery-reveal { clip-path: ellipse(100% 120% at 50% 0%); transform: scale(1); }
.card:hover,
.card.is-hover { color: var(--color--lime); }

/* ---- how the section signs off ---- */
.gallery-close {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.5rem;
  padding-block: 7rem 2rem;
  text-align: center;
}
.gallery-close-mark {
  width: auto;
  height: 5.6rem;
}
.gallery-close-text {
  margin: 0;
  font-family: var(--font--display);
  font-size: 2rem;
  font-weight: 400;
  /* the split puts every line in its own block, so the leading is set here
     and nowhere else — 1.04 is what the reference runs */
  line-height: 1.04;
  letter-spacing: .025em;
  color: var(--color--white);
}
.gallery-close-text .line { line-height: 1.04; }
.btn-w.is-close { align-self: center; }
.btn-w.is-close .btn-icon.is-arrow { width: 1.1rem; height: 1.1rem; }

/* The step is cut out of the bottom-left corner, so the card below shows
   through it and the caption sits right on that boundary. Measured: the rows
   never actually touch — the closest they come is the gap itself — but at
   1.25rem the two read as one collision rather than as two cards.

   The column count was a red herring. An iPad Pro upright is 1024 and gets
   four columns; a Mini is 768 and gets three. Both land on a 241px card with
   an 11px gap, because everything here is rem and the ratio never changes —
   what changes is whether that gap is still big enough to see. So the band
   is 1199, the width this project already treats as the end of tablet, and
   the gap clears the step's own depth (9.4% of the card's height) instead. */
@media screen and (max-width: 1199px) {
  .gallery-grid { row-gap: 2.5rem; }
}

@media screen and (max-width: 991px) {
  .gallery-head, .gallery-grid { grid-template-columns: repeat(3, 1fr); }
  .gallery-title { font-size: 5.4rem; }
}

/* A cell that would sit alone on the last row steps out — still in the DOM for
   the backend to fill, just not drawn. Which cell that is depends on how many
   are on screen and how many columns they are in, so gallery.js counts it
   rather than a media query naming one; the works page filters the grid down
   to four, and the fixed nth-child(16) this replaces hid one of the four the
   visitor had just asked to see. */
.gallery-item.is-orphan { display: none; }
@media screen and (max-width: 479px) {
  /* one column on a phone, so the pair reads as a centred block rather than
     two ragged edges against the right margin */
  .gallery-head { grid-template-columns: 1fr; gap: 1.6rem; text-align: center; }
  .gallery-title { grid-column: auto; font-size: 4.6rem; }
  .gallery-lead { font-size: 1.5rem; }
  .gallery-grid { grid-template-columns: repeat(2, 1fr); gap: 1rem; }
  .gallery-close { gap: 1.8rem; padding-block: 5rem 1rem; }
  .gallery-close-text { font-size: 2.4rem; }
  .gallery-close-mark { height: 4.6rem; }
  /* the step is only a third of a small cell — the pair has to fit in it */
  .card-meta { font-size: max(12px, .9rem); gap: .3rem; padding-inline: .6rem; }
}

@media screen and (max-width: 479px) {
  /* the pair stays side by side on a phone too — it just moves up under the
     nav and hands the bottom two thirds to the photographs, which bleed off
     both edges. Stacking the columns buried the copy behind them. */
  .c.is-work { align-items: flex-start; padding-top: calc(var(--nav-block) + 1rem); }
  .work-layout { gap: 1.2rem; }
  .work-col { width: 15.5rem; }
  .work-title-line.is-a { font-size: 4.2rem; }
  .work-title-line.is-b { font-size: 4rem; }
  .work-p { font-size: 1.5rem; max-width: none; margin-top: 1.2rem; }
  .btn-w.is-icon { width: 4rem; height: 4rem; margin-top: 1.2rem; }
  /* narrow enough that the two figures don't meet in the middle */
  .work-img-w { width: 17rem; }
}

/* ============================================================
   SECTION 7 — SOCIALS
   Measured off the reference at 1440: the ground turns light again
   (#f4f4f4, near-black type), the cards are a static fan and not a
   stack, and a line of copy sits between the fan and the platform row.
   ============================================================ */
@property --oval {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

.s.home-socials {
  /* the light ground returns for this one — the section paints it itself */
  background-color: var(--color--white);
  color: var(--color--black);
  padding-block: 8rem 7rem;
}

.c.is-socials {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.socials-mark { width: auto; height: 3.5rem; }

.socials-title {
  margin: 2.5rem 0 0;
  font-family: var(--font--display);
  font-size: var(--text--h2);
  font-weight: var(--wght--display-bold);
  line-height: .886;
  letter-spacing: -.028em;
  color: var(--color--black);
}
/* each line rides inside its own ellipse. The shape is animated through a
   registered custom property — GSAP interpolates a number reliably and gives
   up on an ellipse() written as a whole string. */
.socials-clip {
  display: block;
  clip-path: ellipse(70% var(--oval) at 50% 0%);
}
.socials-title-line { display: block; }
/* the reference sets its second line in the other display face; we have one
   family, so the contrast is carried by the weight */
.socials-title-line.is-alt { font-weight: var(--wght--display-light); }

/* ---- the fan ----
   a hand of cards: the middle one upright and full size, each step out
   turned a little further, scaled down and pushed lower */
.socials-fan {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 80rem;
  max-width: 100%;
  height: 36rem;
  margin-top: 2.5rem;
}
.socials-card {
  position: absolute;
  cursor: pointer;
  width: 20rem;
  height: 35rem;
  overflow: clip;
  border-radius: 3.3rem;
  background-color: #000;
  transform-origin: 50% 50%;
}
.socials-img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}

/* JS owns these once it runs — they deal out of a gathered pile. What is
   written here is the resting fan, which is also what shows without JS. */
.socials-card:nth-child(1) { transform: translate(-30rem, 7.3rem) rotate(-21deg) scale(.7756); z-index: 1; }
.socials-card:nth-child(2) { transform: translate(-22rem, 4rem)   rotate(-14deg) scale(.8498); z-index: 2; }
.socials-card:nth-child(3) { transform: translate(-11rem, 1.3rem) rotate(-7deg)  scale(.9346); z-index: 3; }
.socials-card:nth-child(4) { transform: none;                                                  z-index: 10; }
.socials-card:nth-child(5) { transform: translate(11rem, 1.3rem)  rotate(7deg)   scale(.9346); z-index: 3; }
.socials-card:nth-child(6) { transform: translate(22rem, 4rem)    rotate(14deg)  scale(.8498); z-index: 2; }
.socials-card:nth-child(7) { transform: translate(30rem, 7.3rem)  rotate(21deg)  scale(.7756); z-index: 1; }

/* ---- the line above the platforms ---- */
.socials-intro {
  margin: 6.2rem 0 0;
  font-family: var(--font--display);
  font-size: 2rem;
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: .025em;
  color: var(--color--black);
}

/* ---- the platform row ---- */
.socials-links {
  display: flex;
  justify-content: center;
  gap: 1.875rem;
  margin-top: 2.5rem;
}
.socials-link {
  position: relative;
  display: block;
  cursor: pointer;
  font-family: var(--font--sans);
  font-size: max(13px, 1.05rem);
  font-weight: 400;
  line-height: 1.25;
  color: var(--color--black);
}
/* the window the characters roll through, the same one the nav button uses */
.socials-link-clip {
  position: relative;
  display: block;
  overflow: clip;
}
.socials-link .btn-text {
  display: block;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: normal;
  color: inherit;
}
.socials-link .btn-text.is-ghost { position: absolute; inset: 0; }

@media screen and (max-width: 1199px) {
  .s.home-socials { padding-block: 5rem 4rem; }
}
@media screen and (max-width: 991px) {
  .s.home-socials { padding-block: 4rem 3rem; }
  .socials-title { font-size: 5.4rem; }
  .socials-fan { height: 32rem; }
  .socials-card { width: 18rem; height: 31rem; border-radius: 2.8rem; }
}
@media screen and (max-width: 479px) {
  .s.home-socials { padding-block: 6rem 5rem; }
  .socials-title { font-size: 4.6rem; }
  .socials-intro { font-size: 2.4rem; margin-top: 4rem; }
  .socials-links { gap: 1.4rem; font-size: 1.3rem; }
  .socials-link { font-size: max(13px, 1.3rem); }
  /* the full seven-card spread is wider than a phone: the outer two pairs
     step out and the rest close in */
  .socials-fan { width: 100%; height: 30rem; }
  .socials-card { width: 15rem; height: 26rem; border-radius: 2.4rem; }
  .socials-card:nth-child(1),
  .socials-card:nth-child(2),
  .socials-card:nth-child(6),
  .socials-card:nth-child(7) { display: none; }
  .socials-card:nth-child(3) { transform: translate(-7rem, 1.3rem) rotate(-9deg) scale(.9); }
  .socials-card:nth-child(5) { transform: translate(7rem, 1.3rem)  rotate(9deg)  scale(.9); }
}

/* ============================================================
   SECTION 8 — FOOTER
   Measured off the reference at 1440 and rebuilt number for number.
   The ground stays light and a lime glow rises from below it; over that
   sits one dark panel, 56rem tall, cut by a mask: a tab bulges out of the
   top edge and a shallow ledge hangs off the bottom. Everything inside is
   pinned to the panel, so the panel is the only thing that has to be right.
   The mask is mirrored against the reference — the page reads right to left.
   ============================================================ */
.s.home-footer {
  /* section 7 already left the ground light; the footer keeps it and adds
     the glow on top, so the two read as one stretch of daylight */
  background-color: var(--color--white);
  color: var(--color--black);
  /* the figure hangs past the panel on purpose, but the page ends here: left
     alone it stretches the document a few pixels past the last painted row
     and the background field shows through the seam. clip, not hidden —
     hidden would make this a scroll container. */
  overflow: clip;
}

/* the lime comes from a circle centred far above the section, so nothing of
   it shows at the top and it floods the bottom corners. 68%→83% of that
   radius is the whole fade. */
.footer-glow {
  position: absolute;
  inset: 0;
  overflow: clip;
  background-image: radial-gradient(circle at 50% -190%,
                                    var(--color--lime-zero) 68%,
                                    var(--color--lime) 83%);
  pointer-events: none;
}

.c.is-footer {
  position: relative;
  /* the reference's container breathes 1.25rem top and bottom; everything
     inside the panel is measured from the panel, so this is the one offset
     that moves the whole footer at once */
  padding-block: var(--padding--container);
}

/* the run-up above the panel: the glow needs somewhere to be seen */
.footer-spacer { height: 14rem; }

.footer-layout { position: relative; }

.footer-panel {
  --footer-mask: url("../assets/footer/panel-mask.svg");
  position: relative;
  /* the reference holds the panel at the mask's own proportions at every
     width — that is why `cover` never crops it. 1688/896 is the outline. */
  aspect-ratio: 1688 / 896;
  background-color: var(--color--dark-green);
  /* cover, not 100% 100%: the shape keeps its aspect and the ends crop,
     so the corner radii stay round at every width */
  -webkit-mask-image: var(--footer-mask);
          mask-image: var(--footer-mask);
  -webkit-mask-size: cover;
          mask-size: cover;
  -webkit-mask-position: 50% 50%;
          mask-position: 50% 50%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* the contour texture, sunk behind everything inside the panel */
.footer-pattern {
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: .07;
  pointer-events: none;
}
.footer-pattern img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---- the statement ----
   pinned 12rem down the panel; the measure is 48rem and the two lines break
   inside it */
.footer-statement-w {
  position: absolute;
  inset: 12rem 0 auto;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}
.footer-statement-layout {
  position: relative;
  width: 48rem;
}
.footer-statement {
  margin: 0;
  font-family: var(--font--display);
  font-size: 5.25rem;
  font-weight: var(--wght--display-bold);
  line-height: .856;
  letter-spacing: -.001em;
  text-align: center;
  color: var(--color--white);
}
/* the reference sets the second half in its other display face; we have one
   family, so light weight and the lime carry the same contrast */
.footer-statement .is-alt {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}

/* the signature rides above the first line, overlapping it */
.footer-sign {
  position: absolute;
  inset: -6.8rem 0 auto;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.footer-sign img {
  width: 13.06rem;
  height: 8.5rem;
  object-fit: contain;
}

/* ---- the figure ----
   flush to the panel's bottom edge, centred, above the copy */
.footer-figure-w {
  position: absolute;
  inset: 16.125rem 0 0;
  z-index: 5;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  pointer-events: none;
}
.footer-figure-layout {
  position: relative;
  width: 48.75rem;
}
.footer-figure {
  display: block;
  width: 21.92rem;
  height: 39.9rem;
  max-width: none;
  /* the character is portrait where the reference's helmet was landscape, so
     the box sets the height and the figure keeps its own width */
  margin-inline: auto;
  object-fit: contain;
  /* measured: the figure hangs 3rem past the panel's bottom edge, so it
     stands on the ledge instead of being cut by it */
  position: relative;
  top: 3rem;
}

/* the call sits on the figure's chest, inside the figure's own box so it
   travels with it */
.footer-cta-w {
  position: absolute;
  inset: 35.125rem 17.975rem auto;
  display: flex;
  justify-content: center;
  pointer-events: auto;
}
/* the call is as wide as its slot, not as wide as its label — 12.8rem in
   the reference, whatever the words inside are */
.footer-cta-w .btn-w { width: 100%; }

/* ---- the two link columns ---- */
.footer-links-w {
  position: absolute;
  inset: 28.875rem 0 auto;
  display: flex;
  justify-content: space-between;
  padding-inline: 12.8rem;
}
.footer-links-col {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.footer-links-col .text-eyebrow { color: var(--color--green-off-white-2); }

.footer-links-layout {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .25rem;
  /* the lime call that used to sit under this column is the gold button now */
  margin-top: 1rem;
}

.footer-link {
  position: relative;
  display: block;
  cursor: pointer;
  font-family: var(--font--sans);
  font-size: 1.875rem;
  font-weight: 800;
  line-height: 1;
  color: var(--color--white);
}
/* the window the characters roll through — the nav's mechanism, unchanged */
.footer-link-clip {
  position: relative;
  display: block;
  overflow: clip;
}
.footer-link .btn-text {
  display: block;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  letter-spacing: normal;
  color: inherit;
}
.footer-link .btn-text.is-ghost { position: absolute; inset: 0; }

/* ---- the ledge strip ----
   the tab hanging off the panel's bottom edge is cut for this row. Two
   identical tracks sit side by side, so travelling exactly half the row and
   repeating lands on the same frame — the hero marquee's trick, unchanged. */
.footer-strip {
  position: absolute;
  inset: 49.625rem 0 auto;
  display: flex;
  height: 2.625rem;
  overflow: clip;
  /* the two tracks have to sit in travel order — under the page's RTL flow
     the first one lands on the right and the loop opens a hole behind it */
  direction: ltr;
  /* the marks are painted through a mask, so the row's colour is one token */
  color: var(--color--lime);
}
.footer-strip-track {
  display: flex;
  flex: 0 0 auto;
  gap: 2.5rem;
  width: max-content;
  padding-inline-end: 2.5rem;
  will-change: transform;
}
/* the mark is a mask and not an <img>: the file carries its own lime, and a
   dozen of them at full strength would take the panel over */
.footer-strip-mark {
  flex: 0 0 auto;
  width: 6.79rem;
  height: 2.625rem;
  background-color: currentColor;
  -webkit-mask: url("../assets/logo/cortex-stroke.svg") center / contain no-repeat;
          mask: url("../assets/logo/cortex-stroke.svg") center / contain no-repeat;
}

/* ---- the legal line ----
   below the panel's masked body, so it sits on the lime and takes the
   dark type */
.footer-legal {
  position: absolute;
  inset: 55rem 0 auto;
  display: flex;
  justify-content: space-between;
  font-family: var(--font--sans);
  font-size: max(11px, .75rem);
  font-weight: 600;
  line-height: 1.25;
  color: var(--color--dark-green);
}
.footer-legal-col {
  display: flex;
  gap: 1.25rem;
}
.footer-legal a { color: inherit; }
.footer-legal a:hover { color: var(--color--black); }

@media screen and (max-width: 1199px) {
  .footer-links-w { padding-inline: 6rem; }
}

/* ---- tablet ----
   the order stays as it is on desktop but everything closes in. Read off the
   reference at 834px, where our fluid root lands on the same 9.65px. */
@media screen and (max-width: 991px) {
  .footer-statement-w      { inset: 10rem 0 auto; }
  .footer-statement-layout { width: 42rem; }
  .footer-statement        { font-size: 5rem; }

  .footer-links-w { inset: 17.24rem 0 auto; padding-inline: 4.1rem; }

  .footer-figure-w      { inset: 13.53rem 0 0; }
  .footer-figure-layout { width: 37.9rem; }
  .footer-figure        { width: 17.03rem; height: 31rem; }
  .footer-cta-w         { inset: 26.25rem 12.52rem auto; }

  .footer-strip { inset: 38.16rem 0 auto; }
  /* the legal line hangs below the panel here, so the layout has to carry
     the room for it — the panel's own height stops at the mask */
  .footer-layout { padding-bottom: 3.25rem; }
  .footer-legal  { inset: 46.53rem 0 auto; }
}

/* ---- phone ----
   the reference deals the panel out again here and the order changes with it:
   the ledge strip moves to the top, the two columns stay side by side under
   it, and the signature, the statement and the figure follow. Read off the
   reference at 390px, where our fluid root lands on the same 10.83px. */
@media screen and (max-width: 479px) {
  .footer-panel {
    /* cover would stretch the landscape outline past recognition on a
       portrait panel, so the phone gets one drawn at its own proportions */
    --footer-mask: url("../assets/footer/panel-mask-mobile.svg");
    aspect-ratio: 382 / 628;
  }

  .footer-strip { inset: 3rem 0 auto; }

  .footer-links-w      { inset: 9rem 0 auto; padding-inline: 4.1rem; }
  .footer-link         { font-size: 1.6rem; }

  .footer-statement-w      { inset: 26.2rem 0 auto; }
  .footer-statement-layout { width: 30.15rem; }
  .footer-statement        { font-size: 3.6rem; }
  .footer-sign             { inset: -3.6rem 0 auto; }
  .footer-sign img         { width: 10rem; height: 6.5rem; }

  .footer-figure-w      { inset: 31rem 0 0; }
  .footer-figure-layout { width: 29.34rem; }
  .footer-figure        { width: 13.19rem; height: 24rem; }
  .footer-cta-w { inset: 19.9rem 8.1rem auto; }
  /* the nav's button drops its label at this width and keeps the icon; the
     footer's is the one call on the page, so it keeps both */
  .footer-cta-w .btn-inner-text-w { display: block; }
  .footer-cta-w .btn-icon { width: 1.2rem; height: 1.26rem; }

  .footer-layout { padding-bottom: 2rem; }
  .footer-legal  { inset: 56rem 0 auto; }
}

/* ============================================================
   THE MENU
   Measured off the reference at 1440, where its root lands on the
   same 13.33px ours does, so every rem transfers straight across.
   The panel opens through an ellipse the way the preloader does —
   one number drives both the radius and the centre, because the
   reference keeps the centre at exactly a fifth of the radius.
   Mirrored: the images sit on the right under RTL, links on the left.
   ============================================================ */
@property --menu-oval {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

.menu-w {
  position: fixed;
  inset: 0;
  z-index: 25;
  display: none;
  justify-content: center;
  align-items: center;
  overflow: clip;
  background-color: var(--color--dark-green);
  color: var(--color--white);
  /* the centre rides at a fifth of the radius — measured, and the reason the
     opening reads as a wipe from the top rather than a growing circle */
  clip-path: ellipse(120% var(--menu-oval) at 50% calc(var(--menu-oval) / 5));
}
.menu-w.is-open { display: flex; }

/* the panel is not flat: it carries the site's own contour field, the same
   drawing the footer panel sits on */
.menu-pattern {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: .07;
  pointer-events: none;
}
.menu-pattern img { width: 100%; height: 100%; object-fit: cover; }
.menu-inner { position: relative; z-index: 1; }

/* the page behind, dimmed under the panel */
.menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 24;
  display: none;
  background-color: #000;
  opacity: 0;
}
.menu-backdrop.is-open { display: block; }

.menu-inner {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  max-width: var(--fluid-container);
  height: 100%;
  padding: 2.5rem 1.25rem 2rem;
}

.menu-grid {
  display: flex;
  /* row-reverse against the RTL flow: the links land on the right, where a
     Hebrew reader's eye starts, and the frames take the left */
  flex-direction: row-reverse;
  justify-content: space-between;
  align-items: stretch;
  gap: 1.25rem;
  width: 100%;
  height: 63rem;
  max-height: 100%;
  /* the reference breathes wide on the images side and narrow on the links
     side; the logical properties carry the mirror */
  padding-inline: 8rem 2.25rem;
}

/* ---- the images ----
   two columns, five frames each, but a column is only ever two frames tall —
   the rest waits below the cut for the pages that come later */
.menu-images {
  display: flex;
  align-items: center;
  gap: 3.75rem;
  width: 49.75rem;
  overflow: clip;
}
/* five frames in a window two frames tall — the overflow is what the mouse
   travels through */
.menu-images-col {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  align-items: center;
  gap: 3.75rem;
  width: 23rem;
  will-change: transform;
}
.menu-images-col-w {
  height: 53.75rem;
  overflow: clip;
}
.menu-img-w {
  position: relative;
  flex: 0 0 auto;
  width: 23rem;
  height: 25rem;
  overflow: clip;
  background-color: var(--color--near-black);
}
.menu-img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}
/* The reference stacks four live blend layers over every frame to sink it
   into the ground. That is a recomposite of everything beneath, every frame,
   ten times over — the cost this project already documents. A greyscale and
   one tint reach the same reading for a fraction of it, and the clean copy
   still waits on top for the hover. */
.menu-img.is-base { filter: saturate(0) brightness(.72); }
.menu-img.is-clean {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--animation-default);
}
.menu-img-tint {
  position: absolute;
  inset: 0;
  background-color: var(--color--dark-green);
  opacity: .45;
  transition: opacity var(--animation-default);
  pointer-events: none;
}
.menu-img-w:hover .menu-img.is-clean { opacity: 1; }
.menu-img-w:hover .menu-img-tint    { opacity: 0; }

/* ---- the links ---- */
.menu-links-w {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  width: 27.27rem;
}
.menu-links-list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.5rem;
  /* Centred in the space above the socials, not pushed down by a fixed
     16.47rem. The fixed value was read off the reference at one window
     height, so the taller the window the lower the list sat inside it; auto
     margins absorb whatever free space there is instead.

     Then lifted a little off true centre. A block of type centred by the
     numbers reads as sitting low — the eye puts the middle of a stack above
     its geometric middle — and this is that correction, in vh so it holds at
     any height. */
  margin-block: auto;
  transform: translateY(-4vh);
}

.menu-link {
  position: relative;
  display: block;
  cursor: pointer;
  font-family: var(--font--display);
  font-size: 5.25rem;
  font-weight: var(--wght--display-bold);
  line-height: .94;
  letter-spacing: -.02em;
  white-space: nowrap;
  color: var(--color--green-off-white-1);
  /* the reference's own curve, an expo-out over six tenths */
  transition: color .6s cubic-bezier(0.19, 1, 0.22, 1);
}
.menu-link:hover { color: var(--color--white); }
/* the window the characters roll through — the socials' mechanism, unchanged */
.menu-link-clip {
  position: relative;
  display: block;
  overflow: clip;
}
.menu-link .btn-text {
  display: block;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
}
.menu-link .btn-text.is-ghost { position: absolute; inset: 0; }
.menu-link .word { display: inline-block; will-change: transform; }
/* the page you are already on steps back rather than forward — measured, and
   the opposite of what you would guess */
.menu-link.is-current { color: var(--color--green-off-white-2); }

/* the lime scrawl under the link. One path, drawn by pulling its dash offset
   back to zero; it is stretched to each link's width, so the stroke has to
   keep its own weight through the stretch. */
/* the line runs THROUGH the word, not under it: a near-straight stroke with
   one soft dip, crossing at the middle of the letters and carrying on past
   them to both edges */
.menu-link-mark {
  position: absolute;
  inset-inline: 0;
  top: 50%;
  translate: 0 -50%;
  width: 100%;
  height: 1.6rem;
  overflow: visible;
  pointer-events: none;
  z-index: 2;
}
.menu-link-mark path {
  fill: none;
  stroke: var(--color--lime);
  stroke-width: 6;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: var(--mark-len, 440);
  stroke-dashoffset: var(--mark-len, 440);
  transition: stroke-dashoffset .55s cubic-bezier(0.19, 1, 0.22, 1);
}
/* the line marks the page you are on, and nothing else — hover has the roll
   and the colour lift to say what it needs */
.menu-link.is-current .menu-link-mark path { stroke-dashoffset: 0; }

/* ---- the socials, along the bottom of the links column ---- */
.menu-social {
  display: flex;
  justify-content: center;
  gap: 1.875rem;
  padding-bottom: 1rem;
}
.menu-social .socials-link { color: var(--color--green-off-white-1); }

@media screen and (max-width: 1199px) {
  .menu-grid { padding-inline: 3rem 2rem; }
  .menu-images { width: 40rem; gap: 2.5rem; }
  .menu-images-col { width: 18.5rem; height: 43rem; gap: 2.5rem; }
  .menu-img-w { width: 18.5rem; height: 20.25rem; }
  .menu-links-w { width: 24rem; }
  .menu-links-list { gap: 2rem; }
  .menu-link { font-size: 4.6rem; }
}

/* a phone has no room for the frames beside the words */
@media screen and (max-width: 767px) {
  .menu-images { display: none; }
  .menu-grid { justify-content: center; padding-inline: 1.5rem; }
  .menu-links-w { width: 100%; }
}

@media screen and (max-width: 479px) {
  .menu-inner { padding: 2rem 1rem 1.5rem; }
  .menu-links-list { gap: 1.6rem; }
  .menu-link { font-size: 3.6rem; }
  .menu-social { gap: 1.4rem; }
}

/* ============================================================
   ABOUT · FIRST SCROLL
   Read off the reference at 1440 and mirrored, so the skull and the
   small word sit on the right and the giant word, the line and the
   numbers run down the left. Every inset here is logical — the mirror
   is the flow's job, not a second set of numbers.
   ============================================================ */
.s.about-hero {
  position: relative;
  min-height: calc(var(--vh, 1vh) * 100);
  /* Sideways only. The skull hangs past the reading edge and has to be cut
     there, but `clip` on both axes also cut the section's own copy: the
     layout is absolute, so it adds no height, and on a short window the
     second row of numbers and the disciplines fell past 100vh and vanished. */
  overflow-x: clip;
  /* Transparent, because the model is drawn on a canvas between this section
     and the ground. An opaque section here sits at z-index 2 and paints
     straight over it — the skull renders and is never seen. The ground moves
     to the field's own fallback colour instead, which is behind both. */
  background-color: transparent;
}

.c.is-about-hero {
  position: relative;
  /* min, not a fixed height — the copy decides when it needs more */
  min-height: calc(var(--vh, 1vh) * 100);
  padding-block: 5.4rem 4rem;
}

.about-hero-layout {
  /* in flow, so the section grows with it instead of clipping it */
  position: relative;
  display: flex;
  flex-direction: column;
}

/* ---- the title: a small word beside a very large one ---- */
.about-title-w {
  /* Measured, not guessed: at the reference's 22.3rem the two words covered
     1434px of the 1876px measure — 76.5%, with a hole in the middle that
     space-between could only widen. 29.3rem is what fills it. */
  --about-title-size: 29.3rem;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
}
/* One size for both words — the contrast is carried by weight and colour,
   the way it is everywhere else on this site, and the line runs the full
   measure instead of stepping down mid-phrase. */
.about-title-small,
.about-title-big {
  display: block;
  font-family: var(--font--display);
  font-size: var(--about-title-size);
  line-height: .887;
  color: var(--color--white);
}

.about-title-small {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}
.about-title-big {
  font-weight: var(--wght--display-bold);
  letter-spacing: -.03em;
}

/* ---- the line and the numbers share the half the skull leaves ---- */
/* .about-stats-grid and the rules under it are kept for the numbers section
   that is still to be defined — they are not on this page any more. */
.about-sub-grid,
.about-stats-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.about-sub-grid   { margin-top: 3rem; }
.about-stats-grid { position: relative; margin-top: 2rem; }

/* three paragraphs where the reference runs a single line — the copy earns
   the room the stats block was leaving empty */
.about-bio {
  grid-column: 2;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  max-width: 46rem;
}
.about-bio p {
  margin: 0;
  font-family: var(--font--sans);
  font-size: 1.15rem;
  line-height: 1.55;
  color: var(--color--grey-2);
}
/* the introduction carries the weight; what follows is the detail behind it */
.about-bio p.about-bio-lead {
  font-size: 1.45rem;
  line-height: 1.4;
  color: var(--color--white);
}

.about-stats {
  grid-column: 2;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  /* the rows have to part further than a number parts from its own label, or
     the eye pairs each number with whatever sits nearest across the gap */
  gap: 3.6rem 2rem;
  margin: 0;
}
.about-stat {
  display: flex;
  flex-direction: column;
  /* box-to-box, not ink-to-ink: line-height 1 leaves the digits' descent space
     empty under the baseline, so the optical gap runs bigger than the number */
  gap: .05rem;
}
.about-stat-num {
  /* hugs its digits instead of spanning the column, so the pair reads as one
     block wherever the grid puts it */
  width: max-content;
  font-family: var(--font--display);
  font-size: 4.6rem;
  font-weight: var(--wght--display-bold);
  line-height: 1;
  color: var(--color--white);
}
.about-stat-label {
  width: max-content;
  margin: 0;
  font-family: var(--font--sans);
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .08em;
  color: var(--color--green-off-white-2);
}

.about-fields {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  gap: .6rem 1.4rem;
  margin: 3rem 0 0;
  padding: 0;
  list-style: none;
  font-family: var(--font--sans);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--color--lime);
}

/* ---- where the skull is drawn ----
   pos1 is an empty box. about.js copies its geometry onto the skull, the way
   the reference frames its helmet off a marker instead of styling it twice. */
.about-skull-pos {
  position: absolute;
  pointer-events: none;
  visibility: hidden;
}
/* 13.1rem down the document and hung off the reading edge. Under RTL the
   inline START is the right, which is the side the reference's helmet enters
   from once the page is mirrored. */
.about-skull-pos.is-pos1 {
  inset-block-start: 13.1rem;
  inset-inline-start: -27.8rem;
  width: 77.6rem;
  height: 66rem;
}

.about-skull {
  position: absolute;
  z-index: -1;
  pointer-events: none;
}
.about-skull img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* The whole tablet band, not just the narrow half of it: an iPad Pro sits at
   1024 and read the desktop rules, so every fix written at 991 missed the one
   device this page is looked at on most. */
@media screen and (min-width: 480px) and (max-width: 1199px) {
  /* space-between parks the small word on the reading edge, which on a tablet
     is exactly where the skull enters — it was reading as part of the model
     rather than as part of the phrase. Packed to the far edge instead, so the
     two words stay one phrase and the skull has the margin to itself. */
  .about-title-w { justify-content: flex-end; gap: 1.6rem; }
}
@media screen and (max-width: 1199px) {
  .about-title-w { --about-title-size: 21rem; }
  /* the section sized to its copy instead of to the window: a forced 100vh
     here left a screen of empty ground between the hero and the statement */
  .s.about-hero, .c.is-about-hero { min-height: 0; }
  .c.is-about-hero { padding-block: 9rem 4rem; }
  .about-hero-layout { inset-block-start: 0; }
  /* the skull kept to the share of the measure it holds on the desktop — 45%.
     Left at 77.6rem it ran 736px wide on a 1024 window and swallowed the
     title it is meant to sit beside. */
  .about-skull-pos.is-pos1 {
    inset-block-start: 12rem;
    inset-inline-start: -12rem;
    width: 48rem;
    height: 38rem;
  }
}
@media screen and (max-width: 991px) {
  .about-title-w { --about-title-size: 17rem; }
  .about-skull-pos.is-pos1 {
    inset-block-start: 13rem;
    inset-inline-start: -10rem;
    width: 42rem;
    height: 36rem;
  }
  .about-bio p       { font-size: 1.35rem; }
  .about-bio p.about-bio-lead { font-size: 1.7rem; }
  .about-stat-num    { font-size: 4rem; }
}
@media screen and (max-width: 479px) {
  /* Both words share one size now, so the phrase is wider than it was when
     this breakpoint was written and it ran 393px into a 363px measure. Sized
     from that measurement, with room for a longer word than the current one. */
  /* one line, no hole in the middle, and packed to the reading edge — which
     under RTL is flex-START, the right */
  .about-title-w {
    --about-title-size: 8.6rem;
    gap: .6rem;
    justify-content: flex-start;
  }
  /* A phone has no column to spare beside the copy, so the model comes out of
     the text and goes under it — which is where the reference puts its helmet
     at this width: below the paragraph and the stats, centred, a little under
     three quarters of the measure. The room is reserved on the layout, since
     the marker itself is absolute and adds no height. */
  .about-hero-layout { padding-block-end: 34rem; }
  /* The box is not the model: the renderer fits it inside at 0.78 of the box's
     SHORTER side, so a 26rem box drew 172px of skull where the reference draws
     295, and height past the width was reserved and then left empty. Sized off
     the width that reads, and kept square so none of it is wasted. */
  .about-skull-pos.is-pos1 {
    inset-block-start: auto;
    inset-block-end: 0;
    inset-inline: 0;
    width: 34rem;
    height: 33rem;
    margin-inline: auto;
  }
  /* one column on a phone: the skull's half is gone, so nothing is left of it
     to leave empty */
  .about-sub-grid,
  .about-stats-grid { grid-template-columns: 1fr; }
  .about-bio,
  .about-stats,
  .about-fields     { grid-column: 1; }
  .about-bio        { max-width: none; }
  .about-bio p      { font-size: 1.25rem; }
  .about-bio p.about-bio-lead { font-size: 1.5rem; }
  .about-stats      { gap: 2rem 1.4rem; }
  .about-stat-num   { font-size: 3.4rem; }
}

/* ============================================================
   ABOUT · SECOND SCROLL + THE MODEL
   The statement is section 3's shape on a new page: a small mark, an
   eyebrow, then one sentence. What is new is that the skull passes
   through it — behind the text at pos2, and stopped at pos3, which
   lands where the reference puts the mark that closes the section.
   ============================================================ */
.skull-gl {
  position: fixed;
  inset: 0;
  /* Over the copy, not under it. The reference runs its helmet behind the
     text; this one passes in front, so the object stays whole as it travels
     instead of being cut in half by every paragraph it crosses. The nav sits
     at 50 and still clears it. */
  z-index: 3;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.s.about-hero,
.s.about-say { z-index: 2; }

/* the pages without a hero never start the field, so its fallback colour is
   the ground — and on this page that ground is the dark one */
[data-page="about"] .gl-bg,
[data-page="work"] .gl-bg { background-color: var(--color--dark-green); }

.s.about-say {
  position: relative;
  /* 82.5rem in the reference carries a statement 49.3rem tall. Ours is two
     lines, so the same height left a screen and a half of nothing under it —
     and the last stop of the journey stranded far below the words. */
  height: 58rem;
  /* transparent for the same reason the hero is */
  background-color: transparent;
}
.c.is-about-say {
  position: relative;
  height: 100%;
}

.about-say-icon {
  position: absolute;
  inset-block-start: 18rem;
  inset-inline: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.2rem;
  color: var(--color--green-off-white-1);
}
.about-say-mark { width: auto; height: 4.5rem; }

/* the reference gives the sentence 78rem of measure; ours is shorter copy in
   the same room, so the size carries it rather than the word count */
.about-say-text {
  position: absolute;
  inset-block-start: 28.1rem;
  inset-inline: 0;
  max-width: 54rem;
  margin-inline: auto;
  font-family: var(--font--display);
  font-size: 6.4rem;
  font-weight: var(--wght--display-bold);
  line-height: .9;
  letter-spacing: -.02em;
  text-align: center;
  color: var(--color--white);
}
.about-say-text strong {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}

/* ---- the waypoints ----
   All three are boxes with nothing in them. about.js reads them and hands the
   model the one it should be filling, so the journey is written in the layout
   and not a second time in script. */
.about-skull-pos.is-pos2 {
  inset-block-start: 26rem;
  inset-inline: 0;
  width: 32rem;
  height: 27.6rem;
  margin-inline: auto;
}
.about-skull-pos.is-pos3 {
  /* Clear of the sentence, not over it. Measured: at 40rem the model still
     crossed the last line by 93px, so this carries that plus air. */
  inset-block-start: 47.5rem;
  inset-inline: 0;
  width: 6.9rem;
  height: 5.1rem;
  margin-inline: auto;
}

/* A tablet has no room beside the sentence, so the model was landing straight
   on top of it — measured at 1024, the two boxes covered each other almost
   exactly. Stacked instead: mark, then model, then sentence. The empty band
   that used to sit above the mark is what the model now occupies, so nothing
   is hidden and almost nothing is added. */
@media screen and (max-width: 1199px) {
  .s.about-say { height: 70rem; }
  .about-say-icon { inset-block-start: 4rem; }
  .about-say-text { inset-block-start: 38rem; font-size: 6rem; max-width: 42rem; }
  .about-skull-pos.is-pos2 {
    inset-block-start: 13rem;
    width: 28rem;
    height: 23.5rem;
  }
  /* clear of the sentence's last line, which ends at 60rem here */
  .about-skull-pos.is-pos3 { inset-block-start: 62rem; }
}
@media screen and (max-width: 991px) {
  .s.about-say { height: 58rem; }
  .about-say-icon { inset-block-start: 3rem; }
  .about-say-text { inset-block-start: 32rem; font-size: 5rem; max-width: 34rem; }
  .about-skull-pos.is-pos2 {
    inset-block-start: 11rem;
    width: 22rem;
    height: 18.5rem;
  }
  .about-skull-pos.is-pos3 { inset-block-start: 51rem; }
}
@media screen and (max-width: 479px) {
  /* Not stacked here. The reference runs its helmet straight across the
     sentence at this width, and the stack that keeps a tablet legible left a
     224px band of nothing between the mark and the words. The sentence sits
     under the mark and the model passes over it, the way it does there. */
  .s.about-say { height: 44rem; }
  .about-say-icon { inset-block-start: 3rem; }
  .about-say-text { inset-block-start: 14rem; font-size: 3.6rem; max-width: none; }
  .about-skull-pos.is-pos2 { inset-block-start: 13rem; width: 18rem; height: 15rem; }
  /* the last stop, clear of the sentence's third line */
  .about-skull-pos.is-pos3 { inset-block-start: 32rem; }
}

/* ============================================================
   ABOUT · NUMBERS
   Read off a screen recording of the reference, after four rounds of
   measuring the wrong block. The figure that carries this section is
   114rem — wider than the window and cut by its edges — not the 17.5rem
   one further down the page. Hovering it opens an image that then
   follows the pointer, which is why every hover probe against a fixed
   layer came back showing nothing at all.
   ============================================================ */
.s.about-numbers {
  position: relative;
  z-index: 2;
  padding-block: 10rem 8rem;
  /* the figure runs past both edges on purpose */
  overflow-x: clip;
  background-color: transparent;
}

/* ---- the figure that fills the screen ---- */
.numbers-giant {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: right;
  cursor: default;
}
.numbers-giant-value {
  display: block;
  width: max-content;
  font-family: var(--font--display);
  font-size: 114rem;
  font-weight: var(--wght--display-bold);
  line-height: .74;
  letter-spacing: -.04em;
  white-space: nowrap;
  color: var(--color--white);
  user-select: none;
}
.numbers-giant-label {
  margin-top: .6rem;
  font-family: var(--font--display);
  /* the reference sets `podiums` at 17.5rem, the same scale as its figures —
     measured, then read as small and rebuilt at 2.75 by mistake */
  font-size: 17.5rem;
  font-weight: var(--wght--display-light);
  line-height: .84;
  letter-spacing: -.03em;
  color: var(--color--lime);
}

/* ---- the image that chases the pointer ----
   Fixed, so the follow is measured against the window and not against a
   scrolling box. about.js lerps it toward the pointer; the ellipse is the
   same one the preloader, the menu and the gallery cards all open through. */
.numbers-chaser {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 4;
  width: 20.6rem;
  height: 24.6rem;
  opacity: 0;
  pointer-events: none;
  will-change: transform;
  transition: opacity .3s var(--cubic-default);
}
.numbers-chaser.is-open { opacity: 1; }
.numbers-chaser-clip {
  display: block;
  width: 100%;
  height: 100%;
  overflow: clip;
  border-radius: var(--radius--small);
  background-color: var(--color--near-black);
  clip-path: ellipse(120% 0% at 50% 0%);
  transition: clip-path .55s var(--cubic-default);
}
.numbers-chaser.is-open .numbers-chaser-clip {
  clip-path: ellipse(120% 120% at 50% 100%);
}
.numbers-chaser img,
.numbers-intro-media img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}

/* ---- the heading and its pictures against the grid ---- */
.numbers-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
  margin-top: 10rem;
}
.numbers-intro { display: flex; flex-direction: column; align-items: flex-start; }

.numbers-title {
  margin: 0;
  font-family: var(--font--display);
  font-size: 4.5rem;
  line-height: .95;
  color: var(--color--white);
}
.numbers-title-line { display: block; width: max-content; font-weight: var(--wght--display-bold); }
/* the reference sets its second line hollow; one family here, so the weight
   carries that drop and the colour is the site's own — lime on the light
   second line, the way every other two-line title on the site runs */
.numbers-title-line.is-alt {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}
.numbers-intro-media {
  width: 25.4rem;
  height: 28.6rem;
  margin-top: 3rem;
  overflow: clip;
  border-radius: var(--radius--small);
  background-color: var(--color--near-black);
}

/* ---- the two by two ---- */
.numbers-grid {
  display: grid;
  /* Columns sized to their content, not to equal fractions.
     With 1fr each, a figure wider than its share simply overflowed it — 180+
     ran 66px into the column beside it, and shrinking the type only made the
     overlap smaller instead of removing it. max-content cannot overflow. */
  grid-template-columns: max-content max-content;
  justify-content: space-between;
  gap: 6rem 4rem;
  align-content: start;
}
.numbers-cell { position: relative; }
.numbers-cell-label {
  display: block;
  /* two lines' worth whether the label needs them or not: without it a
     one-line label lifts its figure a whole line above the one beside it,
     and the row stops reading as a row */
  min-height: 2.7rem;
  font-family: var(--font--sans);
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: .06em;
  color: var(--color--green-off-white-2);
}
.numbers-cell-value {
  display: block;
  /* hugs its digits so the cell's own direction places it, instead of the
     block stretching and its ltr content sliding to the far edge */
  width: max-content;
  margin-top: .6rem;
  font-family: var(--font--display);
  /* 17.5 is the reference's own size, but its figures sit in wider columns —
     at ours 180 and 4 ran into each other */
  font-size: 14rem;
  font-weight: var(--wght--display-bold);
  line-height: .82;
  letter-spacing: -.03em;
  color: var(--color--white);
}
/* The plus rides small and high, the way the reference sets its decimals —
   and in lime, so what it means (there are more than this) is carried by the
   brand colour rather than by a mark the eye reads as part of the number. */
.numbers-cell-plus {
  font-size: 2.75rem;
  vertical-align: super;
  line-height: 1;
  color: var(--color--lime);
}

@media screen and (max-width: 1199px) {
  .numbers-giant-value { font-size: 84rem; }
  .numbers-cell-value  { font-size: 11.5rem; }
  .s.about-numbers     { padding-block: 4rem 3.5rem; }
  .numbers-body        { margin-top: 4rem; }
}
@media screen and (max-width: 991px) {
  .s.about-numbers     { padding-block: 3.5rem 3rem; }
  .numbers-giant-value { font-size: 58rem; }
  .numbers-giant-label { font-size: 2.2rem; }
  .numbers-body        { margin-top: 3.5rem; }
  .numbers-title       { font-size: 3.4rem; }
  .numbers-cell-value  { font-size: 11rem; }
  .numbers-intro-media { width: 100%; height: 24rem; }
}
@media screen and (max-width: 479px) {
  /* the reference runs its figure edge to edge on a phone; at 30rem ours
     covered 318px of 412 and read as a heading rather than as the section */
  .numbers-giant-value { font-size: 38rem; }
  .numbers-body        { grid-template-columns: 1fr; gap: 4rem; }
  .numbers-grid        { gap: 3.4rem 1.4rem; }
  .numbers-title       { font-size: 2.8rem; }
  .numbers-cell-value  { font-size: 7.6rem; }
}

/* ============================================================
   WORK · THE HEAD
   The works page opens on its own phrase rather than on the home
   page's section heading. Same two-line pattern the site uses for
   every title — white line, then a light lime one — with the lead
   and the running count carried on the opposite half so the title
   keeps the whole of its own.
   ============================================================ */
.s.work-head {
  padding-block: 11rem 4rem;
  /* transparent: the field behind the page is the ground here, the way it is
     on the about page's opening */
  background-color: transparent;
  color: var(--color--white);
}

.work-head-layout {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
  align-items: end;
}

.work-head-title {
  grid-column: span 2;
  margin: 0;
  font-family: var(--font--display);
  font-size: var(--text--h2);
  font-weight: var(--wght--display-bold);
  line-height: .886;
  letter-spacing: -.028em;
}
.work-head-line { display: block; }
.work-head-line:last-child {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}

.work-head-side {
  grid-column: 4 / span 1;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}
.work-head-lead {
  margin: 0;
  font-family: var(--font--sans);
  font-size: 1.25rem;
  line-height: 1.45;
  color: var(--color--green-off-white-2);
}
.work-head-count {
  margin: 0;
  font-family: var(--font--sans);
  font-size: max(12px, .8rem);
  font-weight: 600;
  letter-spacing: .1em;
  color: var(--color--grey-on-track);
}

/* the grid section on this page opens straight onto the filter, so it does
   not need the head padding the home page's copy sits in */
.s.home-gallery.is-work-gallery { padding-block: 3rem var(--padding--large); }

/* ============================================================
   WORK · THE FILTER
   One lime pill travels between the buttons; the buttons themselves
   carry nothing but their outline. Reasons, in order:

   1. Five separate on/off states read as five controls. One thing
      that moves reads as one control with five stops, which is what
      it is — and the movement is what tells you the grid below is
      about to change.
   2. The pill is measured off the active button and written to two
      custom properties, so it mirrors under RTL for free and needs
      no second set of numbers.
   3. It is drawn BEHIND the labels, so the active label sits on the
      lime rather than beside it. That is what makes the state read
      at a glance on a dark ground, where a border alone does not.
   ============================================================ */
.work-filter {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: 3.4rem;
}

.work-filter-pill {
  position: absolute;
  z-index: 0;
  /* Physical left/top, not logical insets. The pill's four numbers come off
     a measured rectangle, and a measured rectangle is already in physical
     coordinates — mirroring them a second time with a logical inset would
     put the pill on the wrong side of the row. Everything else on this page
     is logical; this is measured, so it is not. */
  left: 0;
  top: 0;
  width: var(--pill-w, 0px);
  /* the height comes from the button too, so a row that wraps onto a second
     line gets a pill the size of one button rather than of the whole block */
  height: var(--pill-h, 0px);
  border-radius: var(--radius--large);
  background-color: var(--color--lime);
  transform: translate3d(var(--pill-x, 0px), var(--pill-y, 0px), 0);
  /* the site's own easing: quick out of the old stop, settled into the new */
  transition: transform .42s cubic-bezier(.22, 1, .36, 1),
              width     .42s cubic-bezier(.22, 1, .36, 1),
              height    .42s cubic-bezier(.22, 1, .36, 1);
}
/* nothing to slide from on the first paint — it would fly in from the edge */
.work-filter.is-cold .work-filter-pill { transition: none; }

.work-filter-btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: baseline;
  gap: .45rem;
  margin: 0;
  padding: .72rem 1.5rem;
  border: 1px solid var(--color--dark-green-tint-2);
  border-radius: var(--radius--large);
  background: transparent;
  color: var(--color--green-off-white-2);
  font-family: var(--font--sans);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: color .22s ease, border-color .22s ease;
}
.work-filter-btn:hover { color: var(--color--white); border-color: var(--color--green-off-white-2); }

/* the active one goes transparent-bordered and dark-inked: the pill under it
   is the fill, so a border here would draw a second edge around it */
.work-filter-btn.is-on,
.work-filter-btn.is-on:hover {
  color: var(--color--near-black);
  border-color: transparent;
}
.work-filter-btn:focus-visible {
  outline: 2px solid var(--color--lime);
  outline-offset: 3px;
}

.work-filter-n {
  font-size: max(12px, .8rem);
  font-weight: 700;
  letter-spacing: .04em;
  opacity: .55;
}

/* a cell on its way out of the filter, and back in */
.gallery-item.is-filtered { display: none; }

.work-empty {
  margin: 0;
  padding-block: 6rem;
  text-align: center;
  font-family: var(--font--sans);
  font-size: 1.4rem;
  color: var(--color--green-off-white-2);
}

@media screen and (max-width: 1199px) {
  .s.work-head { padding-block: 9rem 3rem; }
}
@media screen and (max-width: 991px) {
  .work-head-layout { grid-template-columns: repeat(3, 1fr); }
  .work-head-title { font-size: 5.4rem; }
  .work-head-side { grid-column: 3 / span 1; }
  .work-filter { margin-bottom: 2.6rem; }
}
@media screen and (max-width: 479px) {
  .s.work-head { padding-block: 8rem 2rem; }
  .work-head-layout { grid-template-columns: 1fr; gap: 1.6rem; text-align: center; }
  .work-head-title { grid-column: auto; font-size: 4.6rem; }
  .work-head-side { grid-column: auto; align-items: center; }
  .work-head-lead { font-size: 1.5rem; }
  /* the row is wider than a phone, so it scrolls sideways rather than
     wrapping into three ragged lines — and the pill travels with it */
  .work-filter {
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
    margin-inline: calc(var(--padding--container) * -1);
    padding-inline: var(--padding--container);
    padding-block-end: .4rem;
  }
  .work-filter::-webkit-scrollbar { display: none; }
  .work-filter-btn { flex: 0 0 auto; padding: .7rem 1.2rem; font-size: 1.2rem; }
  .work-filter-n { font-size: max(12px, .95rem); }
}

/* ============================================================
   CONTACT
   The home page's ground, live rather than flat, with one card on
   top of it holding both halves: the ways to reach a person on the
   reading side, the form on the other.

   The fields are the 21st.dev floating-label pattern rebuilt in plain
   CSS. The idea worth taking is that the label never disappears — it
   starts inside the empty field and rises into a slot ABOVE it, and
   the slot is reserved from the start so nothing below ever moves.
   No script: :placeholder-shown answers "is this empty", which is why
   every input carries a blank placeholder.
   ============================================================ */
/* 70% of the window on the desktop band, per the brief — narrower than the
   site's own container, which is what lets the two panels sit apart without
   the pair reading as a stripe across the screen. Only here: below 1200 the
   measure is already the constraint. */
@media screen and (min-width: 1200px) {
  .c.is-contact { max-width: 70%; }
}

.s.contact {
  /* Sized to one screen. The page holds one section and a footer, so a
     scrollbar here is asking somebody to travel for nothing — the paddings,
     the head's gap and the form's row gap were all cut against a 900px
     window until the section fitted inside it.

     And then held AT one screen, centred. Fitting is not the same as sitting
     well: on a 1024-tall tablet the same content stopped at 710px and left a
     314px void under it, which reads as unfinished rather than as roomy. The
     min-height is inert wherever the copy is already taller — a phone — so
     this costs nothing there. */
  min-height: calc(var(--vh, 1vh) * 100);
  display: flex;
  align-items: center;
  /* The padding follows the window, not just the type scale. On a short
     laptop a fixed 8rem top is a fixed cost the content cannot afford, and it
     was what pushed the panel's bottom edge off the screen. The floor still
     clears the nav bar. */
  padding-block: clamp(5.4rem, 11vh, 8rem) clamp(2rem, 4vh, 3rem);
  /* transparent — the field is the ground, the way it is under the hero */
  background-color: transparent;
  color: var(--color--dark-green);
}

.c.is-contact { width: 100%; }

.contact-head {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
  align-items: end;
  margin-bottom: 2rem;
}
.contact-title {
  grid-column: span 2;
  margin: 0;
  font-family: var(--font--display);
  font-size: var(--text--h2);
  font-weight: var(--wght--display-bold);
  line-height: .886;
  letter-spacing: -.028em;
}
.contact-title-line { display: block; }
.contact-title-line:last-child {
  font-weight: var(--wght--display-light);
  /* lime on a light ground would vanish; the second line carries its weight
     in the type instead, the way the work page's does in colour */
  color: var(--color--dark-green-tint-2);
}
.contact-lead {
  grid-column: 4 / span 1;
  margin: 0;
  font-family: var(--font--sans);
  font-size: 1.25rem;
  line-height: 1.45;
  color: var(--color--dark-green-tint-2);
}

/* ---- the two panels ---- */
/* Two cards, not one split down the middle. A shared frame with a rule
   through it says the halves are one thing you read across; apart, each says
   what it is on its own — here is a person to call, and here is a form. */
.contact-card {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1.35fr;
  gap: 1.25rem;
}

.contact-side,
.contact-form {
  position: relative;
  --pad-i: 2.4rem;
  --pad-b: 1.8rem;
}

/* The panel is the FORM's, not the pair's. The details are three lines and a
   row of names — they need no surface to sit on, and giving them one made two
   competing cards where the page only has one thing to fill in. They sit on
   the field itself now; the field shows through the form's own panel too, so
   the two still belong to the same ground. */
.contact-form {
  border: 1px solid rgb(42 42 42 / .14);
  border-radius: var(--radius--small);
  background-color: rgb(248 248 248 / .72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}


/* ---- the reading side ---- */
.contact-side {
  display: flex;
  flex-direction: column;
  gap: 1.3rem;
  /* nothing to be inset from any more: the block starts at the column's own
     edge, so it lines up with the head above it rather than with a border
     that is not there */
  padding-block: 0 var(--pad-b);
  padding-inline: 0;
}
.contact-side-eyebrow { color: var(--color--dark-green-tint-2); }

.contact-line {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: .9rem;
  color: inherit;
  text-decoration: none;
}
.contact-line-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.6rem;
  height: 2.6rem;
  border: 1px solid rgb(42 42 42 / .16);
  border-radius: .7rem;
  transition: background-color var(--animation-default),
              border-color var(--animation-default),
              color var(--animation-default);
}
.contact-line-icon svg { width: 1.15rem; height: 1.15rem; }
.contact-line:hover .contact-line-icon {
  border-color: var(--color--lime);
  background-color: var(--color--lime);
}
.contact-line-body { display: flex; flex-direction: column; gap: .12rem; min-width: 0; }
.contact-line-key {
  font-family: var(--font--sans);
  font-size: max(12px, .8rem);
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--color--dark-green-tint-2);
}
.contact-line-val {
  font-family: var(--font--sans);
  font-size: 1.15rem;
  font-weight: 600;
  /* an address is one word that must not be broken across the card */
  white-space: nowrap;
}

.contact-side-social { position: relative; z-index: 1; display: flex; flex-direction: column; gap: .7rem; }
.contact-social-row { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
.contact-social {
  position: relative;
  font-family: var(--font--sans);
  font-size: 1.05rem;
  font-weight: 600;
  color: inherit;
  text-decoration: none;
}


/* ---- the form ---- */
/* A grid, so a row can hold two fields. Two columns is the whole mechanism:
   everything spans both by default and only the pair that shares a line asks
   for one. That way adding a field later is a row, not a rethink. */
.contact-form {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .9rem 1.25rem;
  align-content: start;
  padding: var(--pad-b) var(--pad-i);
}
.contact-form > * { grid-column: 1 / -1; }

.f-row { display: flex; flex-direction: column; }
/* name and phone: one line, half each */
.f-row.is-half { grid-column: span 1; }

/* The reserved slot. It is always this tall, whether the label is sitting in
   it or still down inside the field — that is what keeps the form from
   jumping a line every time somebody starts typing. */
.f-slot { height: 1.1rem; }

.f-label {
  display: inline-block;
  font-family: var(--font--sans);
  font-size: .85rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--color--dark-green-tint-2);
  /* at rest it is pushed down into the field and scaled up to the size the
     text will be typed at, so it reads as a placeholder until it is not */
  transform: translateY(1.95rem) scale(1.35);
  transform-origin: right center;
  transition: transform .24s cubic-bezier(.22, 1, .36, 1),
              color .24s ease;
  pointer-events: none;
}
.f-req { margin-inline-start: .15rem; color: var(--color--orange); }

.f-input {
  width: 100%;
  padding: .55rem 0;
  border: 0;
  border-bottom: 1px solid rgb(42 42 42 / .22);
  border-radius: 0;
  background: transparent;
  color: var(--color--dark-green);
  font-family: var(--font--sans);
  font-size: 1.15rem;
  line-height: 1.4;
  transition: border-color .24s ease;
}
.f-input:focus { outline: none; border-bottom-color: var(--color--dark-green); }
/* Three rows, not five. The five-row box was 123px of the 546 the form cost,
   and on a 700-tall laptop that was the difference between the panel ending
   inside the window and being cut by it. It still grows: resize is on, and a
   long message scrolls. */
textarea.f-input { resize: vertical; min-height: 3.4rem; }
/* a select, for forms that define one: same underline as every field, with its own arrow */
select.f-input {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  padding-inline-end: 1.6rem;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23999' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m1 1.5 5 5 5-5'/%3E%3C/svg%3E") no-repeat left .1rem center / .75rem;
}
select.f-input option { color: #111; background: #fff; }

/* The label rises on focus, and stays up once there is something in the field
   — the two states a floating label answers to. Focus is pure CSS; "has
   something in it" is not, because the label sits BEFORE the input in the
   markup and CSS cannot look backwards. contact.js sets is-filled. */
.f-row:focus-within .f-label,
.f-row.is-filled .f-label {
  transform: translateY(0) scale(1);
  color: var(--color--dark-green);
}

.f-note {
  margin: .3rem 0 0;
  /* Reserved, so a message appearing does not push the form down a line — but
     only just: at 1rem the four of them cost a fifth of the panel. */
  min-height: .9rem;
  font-family: var(--font--sans);
  font-size: .85rem;
  line-height: 1.2;
  color: var(--color--dark-green-tint-2);
}

/* invalid, and only after the visitor has had a turn — see contact.js */
.f-row.is-bad .f-input { border-bottom-color: var(--color--orange); }
.f-row.is-bad .f-label,
.f-row.is-bad .f-note  { color: var(--color--orange); }

/* ---- the last line: the consent and the button ----
   One row, because they are one decision: the sentence you have to agree with
   and the control that acts on it. The button sits at the far edge and both
   are centred against each other, so the eye crosses from the words to the
   thing that sends them. */
.f-foot {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: .2rem;
}
.f-foot .f-row.is-check { flex: 1 1 auto; min-width: 0; }
.f-foot .btn-w.is-submit { flex: 0 0 auto; }

.f-row.is-check { margin-top: 0; }
.f-check {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  cursor: pointer;
}
/* the real box is kept in the layout for the keyboard and hidden from the
   eye, so focus still lands somewhere the outline can be drawn */
.f-check-box {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}
.f-check-mark {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 1.35rem;
  height: 1.35rem;
  margin-top: .1rem;
  border: 1px solid rgb(42 42 42 / .3);
  border-radius: .4rem;
  color: var(--color--dark-green);
  transition: background-color var(--animation-default),
              border-color var(--animation-default);
}
.f-check-mark svg { width: .9rem; height: .9rem; opacity: 0; transition: opacity .18s ease; }
.f-check-box:checked + .f-check-mark {
  border-color: var(--color--lime);
  background-color: var(--color--lime);
}
.f-check-box:checked + .f-check-mark svg { opacity: 1; }
.f-check-box:focus-visible + .f-check-mark { outline: 2px solid var(--color--dark-green); outline-offset: 2px; }
.f-row.is-bad .f-check-mark { border-color: var(--color--orange); }

.f-check-text {
  font-family: var(--font--sans);
  font-size: 1rem;
  line-height: 1.4;
  color: var(--color--dark-green-tint-2);
}
.f-check-text a { color: var(--color--dark-green); text-underline-offset: .2em; }

/* justify-self, not align-self: the form is a grid now, and align- is its
   block axis — the button was being pinned to the top of its row, not to the
   reading edge of it. */
.btn-w.is-submit { border: 1px solid var(--color--lime); cursor: pointer; }
.btn-w.is-submit[disabled] { opacity: .55; cursor: default; }

.f-status {
  margin: 0;
  min-height: 1.2rem;
  font-family: var(--font--sans);
  font-size: 1rem;
  color: var(--color--dark-green-tint-2);
}
.f-status.is-ok  { color: var(--color--dark-green); font-weight: 600; }
.f-status.is-bad { color: var(--color--orange); }

/* ============================================================
   CONTACT · THE DARK GROUND
   The field is run at the far end of its own crossfade here, so every
   surface on top of it is restated against dark. Kept in one block
   rather than spread through the rules above: the light version is
   still the shape of the page, and this is the same page in the other
   palette — one place to read, one place to undo.
   ============================================================ */
.s.contact { color: var(--color--white); }
/* lime, the way the second line runs everywhere else on the site — it was
   held back to grey only while this page's ground was light */
.contact-title-line:last-child { color: var(--color--lime); }
.contact-lead { color: var(--color--green-off-white-2); }

.contact-form {
  /* a shade lighter than the ground it sits on, so the panel reads apart
     without a border doing all the work */
  border-color: rgb(244 244 244 / .16);
  background-color: rgb(21 20 21 / .5);
}

.contact-side-eyebrow  { color: var(--color--green-off-white-2); }
.contact-line-icon     { border-color: rgb(244 244 244 / .22); }
.contact-line:hover .contact-line-icon { color: var(--color--near-black); }
.contact-line-key      { color: var(--color--green-off-white-2); }

.f-label { color: var(--color--green-off-white-2); }
.f-input {
  border-bottom-color: rgb(244 244 244 / .26);
  color: var(--color--white);
}
.f-input:focus { border-bottom-color: var(--color--lime); }
.f-row:focus-within .f-label,
.f-row.is-filled .f-label { color: var(--color--white); }
.f-note   { color: var(--color--green-off-white-2); }
.f-status { color: var(--color--green-off-white-2); }
.f-status.is-ok { color: var(--color--lime); }

.f-check-mark { border-color: rgb(244 244 244 / .3); color: var(--color--near-black); }
.f-check-box:focus-visible + .f-check-mark { outline-color: var(--color--white); }
.f-check-text   { color: var(--color--green-off-white-2); }
.f-check-text a { color: var(--color--white); }

/* the orange still reads on dark, but only just — the error state moves to
   the lime the rest of the site already answers to, and carries its weight
   in the note rather than in the hue */
.f-row.is-bad .f-input      { border-bottom-color: var(--color--orange); }
.f-row.is-bad .f-label,
.f-row.is-bad .f-note       { color: var(--color--orange); }

/* ---- the seam into the footer ----
   The dark ground stops and the footer's white begins. Butted, that is a hard
   line the width of the page. This carries the dark down over the join and
   fades it out, so the two grounds meet over 14rem instead of at an edge. */
.contact-fade {
  position: absolute;
  z-index: 1;
  inset-inline: 0;
  /* it hangs BELOW the section, over the footer's own top, which is the half
     of the join that has to be crossed */
  inset-block-start: 100%;
  height: 14rem;
  background-image: linear-gradient(to bottom,
    var(--color--dark-green) 0%,
    rgb(42 42 42 / .86) 22%,
    rgb(42 42 42 / .55) 46%,
    rgb(42 42 42 / .22) 72%,
    rgb(42 42 42 / 0) 100%);
  pointer-events: none;
}

@media screen and (max-width: 1199px) {
  /* enough to clear the bar. At 7rem the title sat against it — the section
     was not too tall on a tablet, it was pushed to the top of one. */
  /* Its content plus room to breathe, NOT a forced screen. Holding the
     section at 100vh on a 1024-tall tablet wrapped 565px of content in 459px
     of nothing — split above and below, which reads emptier than being
     top-loaded did. A page that ends where its content ends is not short, it
     is finished; the footer simply arrives sooner. */
  .s.contact { min-height: 0; padding-block: 9.5rem 5rem; }

  /* The measure, not the window. Left at full width the page read as empty,
     and it was: a 700px underline under a 25px label is mostly nothing, and
     three items strung across a 746px strip are mostly the gaps between them.
     Narrowing the column does two things at once — the content gets denser
     across, and it gets taller down, which is the vertical room that was
     going spare. Same idea as the desktop's 70%, one notch wider because
     there is less width to give away. */
  .c.is-contact { max-width: 78%; }

  /* The head stops sharing a row. On a desktop the title takes half the
     measure and the lead takes a quarter of the other half; on a tablet those
     same two fractions leave a 493px title fighting a 241px paragraph inside
     85px of height. Each gets its own line and the room a tablet actually
     has. */
  .contact-head {
    grid-template-columns: 1fr;
    gap: 1.4rem;
    align-items: start;
  }
  .contact-title { grid-column: auto; font-size: 6.6rem; }
  .contact-lead  { grid-column: auto; max-width: none; }

  /* the two panels stack: the pair is narrower than either one needs long
     before the copy inside it is */
  .contact-card { grid-template-columns: 1fr; gap: 1.4rem; }

  /* Stacked, the reading panel is a 746×137 letterbox with three items down
     the middle of it. Across instead: the two ways to reach a person side by
     side, the network row under them. */
  .contact-side {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1.4rem 2rem;
    align-items: center;
  }
  /* Two by two. Phone and WhatsApp pair off on the first line, the address
     and the network row on the second — four cells on a square, which is what
     makes the block read as one thing rather than as a list that ran out. */
}
@media screen and (max-width: 991px) {
  .contact-title { font-size: 5.8rem; }
}
@media screen and (max-width: 479px) {
  /* Every one of these is a few pixels bought back off a phone screen the
     content was overrunning by 120. Nothing here is decorative — the type is
     still at reading size and the fields are still at tapping size. */
  .s.contact { padding-block: 6.4rem 2rem; }
  .contact-head { gap: 1.2rem; text-align: center; }
  .contact-title { font-size: 4.2rem; }
  .contact-lead  { font-size: 1.3rem; max-width: none; }
  .contact-card  { gap: 1rem; }
  .contact-side  { gap: 1rem; }
  /* Back to one column — two lines side by side on a phone puts a whole email
     address in half a screen.

     And the block centres, its contents do not. Centring each line separately
     would break the icons out of their column and leave three ragged edges;
     shrinking the group to its widest line and centring THAT keeps the icons
     stacked and the values aligned to them, while the whole thing sits under
     the centred head instead of pinned to the reading edge. */
  .contact-side {
    grid-template-columns: 1fr;
    align-items: stretch;
    width: max-content;
    max-width: 100%;
    margin-inline: auto;
  }
  .c.is-contact { max-width: none; }
  .contact-side, .contact-form { --pad-i: 1.4rem; --pad-b: 1.5rem; }
  /* a half-width field on a phone is a field nobody can type in */
  .contact-form { grid-template-columns: 1fr; }
  .f-row.is-half { grid-column: 1 / -1; }
  .contact-line-val { font-size: 1.3rem; }
  .f-input { font-size: 1.35rem; }
  .f-label { font-size: 1rem; }
  .f-check-text { font-size: 1.15rem; }
  .btn-w.is-submit { align-self: stretch; }
}

/* ============================================================
   404
   Three characters on one line: a four, the studio's own skull in
   the zero's place, and another four. The skull is the same optical
   size as the digits and it never leaves that slot — the turning
   happens inside it, in skull-track.js.
   ============================================================ */
.s.notfound {
  position: relative;
  min-height: calc(var(--vh, 1vh) * 100);
  display: flex;
  align-items: center;
  padding-block: clamp(5.2rem, 9.5vh, 7.5rem) clamp(1.8rem, 4vh, 3rem);
  background-color: transparent;
  color: var(--color--white);
}
.c.is-notfound { width: 100%; }

.nf-layout {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  text-align: center;
}

.nf-code {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Measured, not eyeballed: across the whole clip the drawing never comes
     closer than 17.6% of the square to the left edge or 16.9% to the right,
     so the video carries about a sixth of its width in empty margin on each
     side. That margin is the gap — the digits are pulled back over it below
     rather than a smaller gap being set here. */
  gap: 0;
  margin: 0;
  font-family: var(--font--display);
  /* Big enough to be the page, then eased back once the shout arrived under
     it: at 34vw the mark and the line below were competing rather than
     reading in order.

     Sized off the SHORTER side of the window, not just the width. What cut
     the button off a 1920x929 screen was the HEIGHT, and a width-only rule
     cannot see that — so it had to stay small everywhere to survive the one
     shape where it was too tall, which is what left a tablet with a screen
     of dead space around it. The vh term handles the short window, the vw
     term is then free to be generous, and the floor is what a phone gets. */
  font-size: clamp(15rem, min(30vw, 42vh), 30rem);
  font-weight: var(--wght--display-bold);
  line-height: .82;
  letter-spacing: -.03em;
}
.nf-digit { display: block; }

/* Sized off the digits, not set in rem: 1em keeps the skull the height of
   the number it stands in for at any width, and the aspect ratio comes from
   the drawing's own viewBox so nothing is squeezed. */
.nf-skull {
  display: block;
  height: 1.16em;
  aspect-ratio: 1;
  /* the drawing carries its own margin inside the square, so the skull is
     given more height than a digit to arrive at the same optical size — and
     the digits step back over that margin instead of sitting outside it */
  margin-block-start: .02em;
  /* Past the empty margin and into the digits: the fours tuck BEHIND the
     skull rather than sitting beside it, which is what makes the three read
     as one mark instead of a row of three things. */
  margin-inline: -.34em;
  /* the head has to paint over them for the tuck to be a tuck */
  position: relative;
  z-index: 1;
}
/* The animation is a VP9 video with an alpha channel, so the head turns over
   the page's own moving ground rather than sitting on a black square. */
.nf-skull-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

.nf-say {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
}
/* The character's own voice, so it takes the display face and the brand
   colour rather than the quiet grey the explanation runs in. It sits under
   the mark and above the explanation, which is the order the page is read
   in: what happened, how it feels, what to do. */
.nf-shout {
  margin: 0;
  font-family: var(--font--display);
  font-size: clamp(3.2rem, 9vw, 6.4rem);
  font-weight: var(--wght--display-bold);
  line-height: .95;
  letter-spacing: -.02em;
  color: var(--color--lime);
  text-wrap: balance;
}

.nf-lead {
  margin: 0;
  max-width: 34rem;
  font-family: var(--font--sans);
  font-size: 1.35rem;
  line-height: 1.5;
  color: var(--color--green-off-white-2);
  /* The browser evens the lines out rather than filling the first and
     leaving one word alone on the second. A max-width can only guess where
     the break lands; this asks for the shape directly, and it re-answers at
     every width instead of being tuned for one. */
  text-wrap: balance;
}

@media screen and (max-width: 1199px) {
  /* A full screen, deliberately: the error is the whole message here and the
     footer arriving under it undercuts that. The desktop keeps its own
     min-height for the same reason. */
  .s.notfound { min-height: calc(var(--vh, 1vh) * 100); padding-block: 9rem 5rem; }
  .nf-layout { gap: 2rem; }
}
@media screen and (max-width: 479px) {
  .s.notfound { padding-block: 7rem 3rem; }
  .nf-lead { font-size: 1.5rem; }
  .nf-say { gap: 1.4rem; }
}

/* ============================================================
   PROJECT · SECTION 1
   Read off chriskalafatis.com/project/taylormade at 1440 and
   mirrored. Their proportions, as shares of the 1340px measure:
   image column 66% at 887:1109, statement 59% overlapping the image
   by a quarter of its width, title on the image column's outer edge.

   A grid rather than absolute positions, because the overlap is the
   point: the statement and the image share two columns, and the
   statement sits above by z-index rather than by a hand-placed inset
   that would have to be re-guessed at every width.
   ============================================================ */
.s.project-hero {
  position: relative;
  padding-block: clamp(6rem, 11vh, 8.5rem) clamp(3rem, 6vh, 5rem);
  background-color: transparent;
  color: var(--color--white);
}

.ph-layout {
  display: grid;
  /* twelve columns: the image takes eight of them, the statement seven, and
     the three they share are the overlap */
  grid-template-columns: repeat(12, 1fr);
  column-gap: 1.25rem;
  align-items: start;
}

/* Column 1 is the RIGHT one here, so the reference's sides come out as they
   were rather than mirrored unless the spans say otherwise. The image takes
   the eight columns furthest from the reading edge, the statement the seven
   nearest it, and the three they share are the overlap — 25% of the measure,
   which is what the reference's 336px is. */

/* ---- the title sits on the image column's inner edge, not the page's ---- */
.ph-title {
  grid-column: 5 / span 8;
  grid-row: 1;
  margin: 0 0 1.9rem;
  font-family: var(--font--display);
  font-size: clamp(4.4rem, 6.3vw, 6.75rem);
  font-weight: var(--wght--display-bold);
  line-height: .95;
  letter-spacing: -.028em;
}

/* ---- the rule and the numbered row ---- */
.ph-index {
  grid-column: 5 / span 8;
  grid-row: 2;
  margin-bottom: 1.5rem;
}
.ph-rule {
  display: block;
  height: 1px;
  background-color: rgb(244 244 244 / .32);
}
.ph-index-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-top: .9rem;
  font-family: var(--font--sans);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--color--green-off-white-2);
}
/* the two counters read left to right whichever way the page does */
.ph-index-nbr,
.ph-index-of { direction: ltr; unicode-bidi: isolate; color: var(--color--lime); }

/* ---- the image ---- */
.ph-media {
  grid-column: 5 / span 8;
  grid-row: 3;
  /* the reference's own frame: 887 wide by 1109 tall */
  aspect-ratio: 887 / 1109;
  overflow: clip;
  border-radius: var(--radius--small);
  background-color: var(--color--near-black);
}
.ph-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- the statement, over the image ---- */
.ph-say {
  grid-column: 1 / span 7;
  grid-row: 3;
  z-index: 1;
  margin: 0;
  /* down the image's own height, where the reference puts it: their statement
     starts 134px into a 1109px frame */
  margin-block-start: 12%;
  font-family: var(--font--display);
  /* the base size the section was designed at, scaled down by project.js
     when a project's own copy is longer than the column — see fitSay */
  font-size: calc(clamp(6.4rem, 11.1vw, 12rem) * var(--ph-say-fit, 1));
  font-weight: var(--wght--display-bold);
  line-height: .77;
  letter-spacing: -.034em;
}
.ph-say .is-alt {
  font-weight: var(--wght--display-light);
  color: var(--color--lime);
}

/* ---- the roles, low on the reading side ---- */
.ph-roles {
  grid-column: 1 / span 5;
  grid-row: 3;
  z-index: 1;
  align-self: end;
  margin: 0 0 12%;
  padding: 0;
  list-style: none;
  font-family: var(--font--sans);
  font-size: 1.35rem;
  line-height: 1.5;
  color: var(--color--green-off-white-2);
}

@media screen and (max-width: 1199px) {
  .s.project-hero { padding-block: 9rem 4rem; }
  .ph-title { font-size: 6.4rem; }
  .ph-say   { font-size: 10rem; }
}

@media screen and (max-width: 767px) {
  /* The overlap is a desktop idea. At this width the statement would cover
     the picture rather than cross it, so the three stack in reading order:
     what it is, what it looks like, what was done. */
  .ph-layout { grid-template-columns: 1fr; }
  .ph-title, .ph-index, .ph-media, .ph-say, .ph-roles {
    grid-column: 1;
    grid-row: auto;
  }
  .ph-media { aspect-ratio: 4 / 5; }
  .ph-say   { margin-block-start: 2.4rem; font-size: 6.4rem; }
  .ph-roles { margin: 2.2rem 0 0; align-self: auto; }
}

@media screen and (max-width: 479px) {
  .s.project-hero { padding-block: 7.5rem 3rem; }
  .ph-title { font-size: 5.2rem; }
  .ph-say   { font-size: 5.4rem; }
  .ph-roles { font-size: 1.5rem; }
  .ph-index-row { font-size: 1.15rem; }
}

/* ============================================================
   PROJECT · SECTION 2
   Two labelled blocks. Read off the reference at 1440: the label
   sits at the reading edge, the paragraph is indented a third of
   the measure and runs 65% of it, and 230px separates the pair.
   ============================================================ */
.s.project-say {
  padding-block: clamp(4rem, 8vh, 7rem) clamp(5rem, 10vh, 9rem);
  background-color: transparent;
  color: var(--color--white);
}

.pd-block {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 1.25rem;
  align-items: start;
}
/* 230px between the two at 1440 — as a share of the measure so it holds */
.pd-block + .pd-block { margin-top: 4.6rem; }

.pd-label {
  grid-column: 1 / span 2;
  margin: 0;
  padding-top: .9em;       /* onto the paragraph's first baseline */
  color: var(--color--lime);
  /* A floor in PIXELS, not rem. The eyebrow it inherits computed to 8.33px
     at 1440, which fails any reasonable reading of the accessibility
     standard — and rem alone cannot fix it here, because the fluid root
     SHRINKS on a tablet: .625rem is 8.3px at 1440 and 5.6px at 768. The
     clamp gives it a real floor and lets it grow where there is room. */
  font-size: clamp(15px, 1.2rem, 18px);
  line-height: 1.3;
}

.pd-body {
  /* columns 5–12: a third of the measure in, 66% of it wide */
  grid-column: 5 / span 8;
  margin: 0;
  font-family: var(--font--display);
  font-size: clamp(1.9rem, 2.9vw, 3rem);
  font-weight: var(--wght--display-light);
  line-height: 1.22;
  letter-spacing: -.012em;
}

@media screen and (max-width: 1199px) {
  .pd-body { font-size: 2.6rem; }
  .pd-block + .pd-block { margin-top: 3.6rem; }
}

@media screen and (max-width: 767px) {
  /* the indent is a desktop idea: at this width it leaves the paragraph a
     column too narrow to read. Label over paragraph instead. */
  .pd-block { grid-template-columns: 1fr; }
  .pd-label { grid-column: 1; padding-top: 0; margin-bottom: .9rem; }
  .pd-body  { grid-column: 1; font-size: 2.4rem; }
  .pd-block + .pd-block { margin-top: 3rem; }
}

@media screen and (max-width: 479px) {
  .s.project-say { padding-block: 3rem 4.5rem; }
  .pd-body { font-size: 2.2rem; }
}

/* ============================================================
   PROJECT · THE BODY ROWS
   Two row types, read off the reference at 1440 against its 1340
   measure. They repeat down the page in the order the record gives.
   ============================================================ */
.s.project-body {
  padding-block: 0 clamp(4rem, 8vh, 7rem);
  background-color: transparent;
  color: var(--color--white);
}

/* ---- intro: a heading beside a paragraph ---- */
/* reference: heading x50..374 (24% of the measure) at 30px, paragraph
   x502..1051 — a third of the measure in, 41% wide, at 18px */
.pr-intro {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 1.25rem;
  align-items: start;
  margin-bottom: 2.6rem;
}
.pr-intro-title {
  grid-column: 1 / span 3;
  margin: 0;
  font-family: var(--font--display);
  font-size: clamp(1.7rem, 2.1vw, 2.25rem);
  font-weight: var(--wght--display-bold);
  line-height: 1.1;
  letter-spacing: -.028em;
}
.pr-intro-body {
  grid-column: 5 / span 5;
  margin: 0;
  font-family: var(--font--sans);
  font-size: clamp(15px, 1.35rem, 1.35rem);
  line-height: 1.5;
  color: var(--color--green-off-white-2);
}

/* ---- media: one image across the measure ---- */
.pr-media {
  /* the reference's own frame: 1340 by 754 */
  aspect-ratio: 16 / 9;
  overflow: clip;
  border-radius: var(--radius--small);
  background-color: var(--color--near-black);
}
.pr-media img,
.pr-media video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* the beat between one row and the next */
.pr-row + .pr-row { margin-top: 3.4rem; }
.pr-row.is-intro + .pr-row.is-media { margin-top: 0; }
/* A pinned row is wrapped by GSAP in a .pin-spacer, so the row after it is
   no longer adjacent to a .pr-row and the rule above stopped reaching it —
   the slideshow and the page design sat flush against each other. The spacer
   inherits the pinned row's own margins, so only the following side is
   missing. */
.pin-spacer + .pr-row { margin-top: 3.4rem; }

@media screen and (max-width: 767px) {
  /* the indent is a desktop idea — at this width it leaves the paragraph a
     column too narrow to read */
  .pr-intro { grid-template-columns: 1fr; }
  .pr-intro-title { grid-column: 1; margin-bottom: .9rem; }
  .pr-intro-body  { grid-column: 1; }
  .pr-media { aspect-ratio: 4 / 3; }
  .pr-row + .pr-row,
  .pin-spacer + .pr-row { margin-top: 2.6rem; }
}

/* ---- showcase: a pinned line of text, screens going past it ----
   Read off the reference at 1440 against its 1340 measure: the text is 24%
   of it, the two columns 41% together, each screen 19% at 254x550 — a phone.
   90px between screens in a column, 40px between the columns, and the second
   column starts 245px lower so the two never line up.

   position: sticky, not the reference's fixed-plus-script. Sticky stops at
   its own container's end on its own; fixed does not, which is why theirs
   needs JS to know when to let go. */
.pr-show {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 1.25rem;
  align-items: start;
}

.pr-show-text {
  grid-column: 1 / span 3;
  position: sticky;
  /* clear of the bar, and high enough that the text is read before the
     screens have gone by */
  top: 22vh;
}
.pr-show-title {
  margin: 0 0 1rem;
  font-family: var(--font--display);
  font-size: clamp(1.7rem, 2.1vw, 2.25rem);
  font-weight: var(--wght--display-bold);
  line-height: 1.1;
  letter-spacing: -.028em;
}
.pr-show-body {
  margin: 0;
  font-family: var(--font--sans);
  font-size: clamp(15px, 1.35rem, 1.35rem);
  line-height: 1.5;
  color: var(--color--green-off-white-2);
}

.pr-show-cols {
  grid-column: 6 / span 5;
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* The reference's gap is 40px between screens that are 254 wide — 15.7% of a
     screen. 3% was that same 40px taken as a share of the 1340 measure, but a
     gap here resolves against THIS box, not the measure, so it came out at a
     third of what it should be and the screens sat almost touching.
     Solved for the container instead: with two equal columns,
       g = .157 * (W - g) / 2  →  g = 7.3% of W. */
  column-gap: 7.3%;
  align-items: start;
}
/* A percentage here is a percentage of WIDTH, always — that is what the box
   model resolves it against, whichever direction it points. Both of these
   were written as shares of the screen's height and both came out wrong:
   `gap: 6.7%` in an auto-height column resolved to 0 and the screens touched,
   and a 22% offset gave a tenth of a screen where 45% was wanted.

   So the reference's vertical numbers are converted through the screen's own
   aspect (550/254 = 2.165):
     90px  of 550 = 16.4% of the height = 35.5% of the width
     245px of 550 = 44.5% of the height = 96.4% of the width */
.pr-show-col { display: flex; flex-direction: column; }
.pr-show-item + .pr-show-item { margin-top: 35.5%; }
/* the second column starts low, so the two never sit level */
.pr-show-col.is-offset { margin-top: 96.4%; }

.pr-show-item {
  /* the reference's own frame: 254 by 550 */
  aspect-ratio: 254 / 550;
  overflow: clip;
  /* 25px on a 254-wide screen — a tenth of the width. The shared small radius
     is 1rem, which on a box this tall reads as a bar rather than as a phone:
     what makes the shape legible is the corner's size relative to the width it
     is cut into, so this one is sized to the screen and not to the token. */
  border-radius: clamp(14px, 1.9rem, 30px);
  background-color: var(--color--near-black);
}
/* top, not centre: these are screens. A phone screenshot cropped from its
   middle loses the header, which is the part that says which screen it is. */
.pr-show-item img,
.pr-show-item video {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}

@media screen and (max-width: 767px) {
  /* Nothing to pin against: the text and the screens would each get half a
     phone's width. The text sits above, and the screens run as a plain pair
     of columns under it. */
  .pr-show { grid-template-columns: 1fr; }
  .pr-show-text { grid-column: 1; position: static; margin-bottom: 1.8rem; }
  .pr-show-cols { grid-column: 1; }
  .pr-show-col.is-offset { margin-top: 60%; }
}

/* ---- slideshow: a full-bleed strip that travels sideways ----
   Measured off the reference at 1440: seven frames of 710x533 — four by
   three — with 176px between them, laid in one flex row that runs off both
   edges of the window. 710 is 49.3% of the window and 176 is 24.8% of a
   frame, so both are written as shares and the strip holds its proportions
   at any width.

   Full bleed out of the measured container: the row is inside `.c`, and
   `margin-inline: calc(50% - 50vw)` is the one way back to the window's
   own width that does not care what the container's padding happens to be.
   `overflow: clip` and not `hidden` — hidden makes the box a scroll
   container, which lets a stray focus inside it scroll the strip sideways
   behind the animation's back. */
.pr-slide {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  overflow: clip;
}
.pr-slide-strip {
  display: flex;
  width: max-content;
  will-change: transform;
}
/* The space between frames is 24.8% of a frame — but a `gap` in percent
   resolves against the flex container, and this one is max-content, so the
   percentage would chase its own tail. Written against the window instead,
   where both numbers already live: 24.8% of 49.3vw. */
.pr-slide-item + .pr-slide-item { margin-inline-start: 12.23vw; }

.pr-slide-item {
  flex: 0 0 auto;
  width: 49.3vw;
  aspect-ratio: 710 / 533;
  overflow: clip;
  border-radius: var(--radius--small);
  background-color: var(--color--near-black);
}
.pr-slide-item img,
.pr-slide-item video { width: 100%; height: 100%; object-fit: cover; display: block; }

@media screen and (max-width: 991px) {
  /* a frame at half the window is 380px on a tablet — the strip still reads,
     but the picture inside it stops doing so. Fewer, larger frames on
     screen at once instead. */
  .pr-slide-item { width: 62vw; }
  .pr-slide-item + .pr-slide-item { margin-inline-start: 15.4vw; }
}
@media screen and (max-width: 767px) {
  .pr-slide-item { width: 78vw; }
  .pr-slide-item + .pr-slide-item { margin-inline-start: 9vw; }
}

/* ---- site scroll: a whole page design going past a pinned line of text ----
   Measured off the reference at 1440 against its 1340 measure: the text is
   324 wide and holds still; the design is 888 wide — 66.3%, eight columns —
   and 5283 tall, which is not a number anyone chose. It is whatever that
   design happens to be.

   That is the rule this row is built on: the WIDTH is fixed and the HEIGHT
   is the image's own. So there is no aspect-ratio here and no cropping —
   `height: auto` lets a taller design simply make the row taller, and a
   short one make it shorter, with nothing to adjust when the picture is
   replaced.

   Above it, the reference's three dots: a window frame, so a full page
   design reads as a page and not as a very long picture. */
.pr-site {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 1.25rem;
  align-items: start;
}
.pr-site-text {
  grid-column: 1 / span 3;
  position: sticky;
  top: 22vh;
}
.pr-site-title {
  margin: 0 0 1rem;
  font-family: var(--font--display);
  font-size: clamp(1.7rem, 2.1vw, 2.25rem);
  font-weight: var(--wght--display-bold);
  line-height: 1.1;
  letter-spacing: -.028em;
}
.pr-site-body {
  margin: 0;
  font-family: var(--font--sans);
  font-size: clamp(15px, 1.35rem, 1.35rem);
  line-height: 1.5;
  color: var(--color--green-off-white-2);
}

/* 888 of 1340 — eight of the twelve */
.pr-site-media { grid-column: 5 / span 8; }

/* 35px tall on an 888-wide frame, 12px dots 10px apart */
.pr-site-bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  height: 2.65rem;
  min-height: 26px;
  padding-inline: 1.2rem;
  border-radius: 17px 17px 0 0;
  background-color: var(--color--near-black);
}
.pr-site-bar span {
  width: .9rem; height: .9rem;
  min-width: 8px; min-height: 8px;
  border-radius: 50%;
  background-color: var(--color--green-off-white-2);
  opacity: .45;
}

.pr-site-frame {
  overflow: clip;
  border-radius: 0 0 var(--radius--small) var(--radius--small);
  background-color: var(--color--near-black);
  /* not a flow root by accident: the image is a block and this keeps the
     frame exactly as tall as it, with no line-box gap under it */
  display: flow-root;
  font-size: 0;
}
/* the whole point of the row: one fixed width, and whatever height the
   design that was uploaded happens to have */
.pr-site-frame img,
.pr-site-frame video { width: 100%; height: auto; display: block; }

@media screen and (max-width: 991px) {
  /* three columns of text against eight of design leaves the text too narrow
     to read once the root font has shrunk. The text sits above instead, and
     the design takes the whole measure. */
  .pr-site { grid-template-columns: 1fr; }
  .pr-site-text { grid-column: 1; position: static; margin-bottom: 1.8rem; }
  .pr-site-media { grid-column: 1; }
}

/* ---- the ground turns over at 4500px ----
   A marker, not a box: no size, no paint, and `top` measured from the top of
   the document because there is no positioned ancestor between it and the
   initial containing block. Everything it does, it does by being a place. */
.ground-mark {
  position: absolute;
  top: 4500px;
  inset-inline-start: 0;
  width: 1px; height: 1px;
  pointer-events: none;
}

/* The field crossfades to its light end and the copy has to turn with it —
   white type on a white ground is not a decision, it is a section nobody can
   read. One switch on the root drives both, so they cannot disagree, and the
   type takes the same half second the field's own crossfade takes.

   Only the type turns. The image frames keep their dark fill: a frame is the
   shape of a picture that has not arrived yet, and a dark one still reads as
   that on a light ground. */
.s.project-hero, .s.project-say, .s.project-body,
.pd-body, .pr-intro-body, .pr-show-body, .pr-site-body {
  transition: color .5s ease;
}
:root[data-page-ground="light"] .s.project-hero,
:root[data-page-ground="light"] .s.project-say,
:root[data-page-ground="light"] .s.project-body { color: var(--color--black); }

:root[data-page-ground="light"] .pd-body,
:root[data-page-ground="light"] .pr-intro-body,
:root[data-page-ground="light"] .pr-show-body,
:root[data-page-ground="light"] .pr-site-body {
  color: var(--color--dark-green-tint-2);
}

/* ---- more work: four other cases, and never the same four ---- */
.s.project-more {
  position: relative;
  padding-block: clamp(5rem, 10vh, 8rem) clamp(6rem, 12vh, 10rem);
  background-color: transparent;
  color: var(--color--white);
}

.pm-head {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
  align-items: end;
  margin-bottom: 3.4rem;
}
.pm-title {
  grid-column: span 2;
  margin: 0;
  font-family: var(--font--display);
  /* the site's own h2, the size every other section heading uses — this
     was 74.7px against their 60px, which made the row on the way out the
     loudest heading on the page */
  font-size: var(--text--h2);
  font-weight: var(--wght--display-bold);
  line-height: .95;
  letter-spacing: -.028em;
}
.pm-body {
  grid-column: 4 / span 1;
  margin: 0;
  font-family: var(--font--sans);
  font-size: clamp(15px, 1.35rem, 1.35rem);
  line-height: 1.5;
  color: var(--color--green-off-white-2);
}

/* Four across, and then two — never three. Three columns is the one count
   four cards cannot fill: it strands the fourth on a row of its own, and the
   grid's own orphan rule leaves it there because it only steps in once there
   are three full rows to spare one from. */
.pm-grid { grid-template-columns: repeat(4, 1fr); }
@media screen and (max-width: 991px) {
  .pm-head { grid-template-columns: 1fr; gap: 1.2rem; margin-bottom: 2.6rem; }
  .pm-title { font-size: 5.4rem; }
  .pm-title { grid-column: 1; }
  .pm-body  { grid-column: 1; }
  .pm-grid  { grid-template-columns: repeat(2, 1fr); }
}
@media screen and (max-width: 479px) {
  /* two, not one: this is the row on the way out, and four cards stacked
     single file is a second gallery nobody asked for */
  .pm-grid { grid-template-columns: repeat(2, 1fr); gap: 1rem; }
  .pm-title { font-size: 4.6rem; }
}

/* ---- the seam into the footer ----
   Past 4500px the ground is the light field and the footer is a flat white a
   shade off it. Butted, that shade change is a line across the page. This
   carries the footer's own white up over the join and fades it out, so the
   two meet over 16rem instead of at an edge — the same move the contact page
   makes at the same seam, in the other direction. */
.pm-fade {
  position: absolute;
  z-index: 1;
  inset-inline: 0;
  inset-block-end: 0;
  height: 16rem;
  background-image: linear-gradient(to bottom,
    rgb(244 244 244 / 0)   0%,
    rgb(244 244 244 / .22) 28%,
    rgb(244 244 244 / .55) 54%,
    rgb(244 244 244 / .86) 78%,
    var(--color--white)   100%);
  pointer-events: none;
}
/* Above the switch the ground is still dark, and a white gradient there is a
   glow with no reason. It only paints once the page has turned over. */
:root:not([data-page-ground="light"]) .pm-fade { opacity: 0; }
.pm-fade { transition: opacity .5s ease; }

:root[data-page-ground="light"] .s.project-more { color: var(--color--black); }
:root[data-page-ground="light"] .pm-body { color: var(--color--dark-green-tint-2); }
.s.project-more, .pm-body { transition: color .5s ease; }

/* ---- the more-work captions ----
   The gallery's caption is written for the dark ground it normally sits on:
   white name, lime discipline. This row sits on the light one, where both
   all but vanish. Scoped to this grid and not changed at the source — the
   home page and the works page still sit on the dark ground and want the
   pair they have.

   Only the colour. The light name against the discipline's bold is the
   caption's own pairing now, on every ground. */
.pm-grid .card-client   { color: var(--color--black); }
.pm-grid .card-category { color: var(--color--black); }


/* ============================================================
   LEGAL PAGES — privacy.html, terms.html
   A page of words on the contact page's ground. Every section is a heading
   beside a paragraph, the way the project template's rows are: the title
   takes the reading side and the text sits a third of the measure in. The
   copy is the whole point, so the type is sized to be read, not admired.
   ============================================================ */
.s.legal {
  position: relative;
  padding-block: clamp(5.4rem, 11vh, 8rem) clamp(4rem, 8vh, 6rem);
  background-color: transparent;
  color: var(--color--white);
}
.c.is-legal { width: 100%; }

.legal-head {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
  align-items: end;
  margin-bottom: clamp(3rem, 7vh, 5rem);
}
.legal-title {
  grid-column: span 2;
  margin: 0;
  font-family: var(--font--display);
  font-size: var(--text--h2);
  font-weight: var(--wght--display-bold);
  line-height: .886;
  letter-spacing: -.028em;
}
.legal-title-line { display: block; }
.legal-title-line:last-child { font-weight: var(--wght--display-light); color: var(--color--lime); }
.legal-updated {
  grid-column: 1 / -1;
  order: 3;
  margin: 1.2rem 0 0;
  font-family: var(--font--sans);
  /* px floors: the site's rem follows the window, and a legal page set in 10px
     at tablet width is a page nobody reads */
  font-size: max(.9rem, 13px);
  letter-spacing: .04em;
  color: var(--color--green-off-white-2);
}
.legal-lead {
  grid-column: 3 / span 2;
  margin: 0;
  font-family: var(--font--sans);
  font-size: max(1.25rem, 17px);
  line-height: 1.5;
  color: var(--color--green-off-white-2);
}

.legal-body { border-top: 1px solid rgb(244 244 244 / .16); }
.legal-sec {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.2fr);
  gap: 1.5rem clamp(2rem, 6vw, 6rem);
  padding-block: clamp(1.6rem, 3.4vh, 2.4rem);
  border-bottom: 1px solid rgb(244 244 244 / .16);
}
.legal-h {
  margin: 0;
  font-family: var(--font--display);
  font-size: max(1.6rem, 21px);
  font-weight: var(--wght--display-bold);
  line-height: 1.15;
  letter-spacing: -.01em;
}
.legal-p {
  margin: 0;
  max-width: 46rem;
  font-family: var(--font--sans);
  font-size: max(1.1rem, 16px);
  line-height: 1.7;
  color: var(--color--green-off-white-2);
}
.legal-p strong { color: var(--color--white); font-weight: 700; }

@media screen and (max-width: 991px) {
  .legal-head { grid-template-columns: 1fr; gap: 1.4rem; align-items: start; }
  .legal-title { grid-column: auto; font-size: 5.8rem; }
  .legal-lead { grid-column: auto; max-width: none; }
  .legal-updated { order: 0; grid-column: auto; margin-top: 0; }
  .legal-sec { grid-template-columns: 1fr; gap: .8rem; }
}
@media screen and (max-width: 479px) {
  .s.legal { padding-block: 6.4rem 3rem; }
  .legal-title { font-size: 4.2rem; }
  .legal-lead { font-size: max(1.15rem, 17px); }
  .legal-h { font-size: max(1.4rem, 20px); }
  .legal-p { font-size: max(1.05rem, 16px); }
}
