/* ============================================================
   YoProfX — Experience Innovation Lab
   Landing page. Hand-written CSS, no build step.

   00 Fonts (self-hosted — no third-party request)
   00 Tokens
   01 Reset & base
   02 Background field (night → dawn)
   03 Navigation
   04 Hero
   05 Chapters (the five planes)
   06 Footer
   07 Motion
   08 Responsive
   09 Brush stroke image treatment (not used on this page)
   ============================================================ */


/* ── 00 Fonts ────────────────────────────────────────────────
   Self-hosted latin subsets. The page makes no third-party request
   and needs nothing but this folder on the server. ~126KB total.
   ──────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 500 700;
  font-stretch: 100% 125%;
  font-display: swap;
  src: url(../assets/fonts/archivo.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(../assets/fonts/instrument.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/mono400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../assets/fonts/mono700.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* ── 00 Tokens ───────────────────────────────────────────── */

:root {
  /* grid */
  --max: 1440px;
  --gutter: 24px;
  --margin: 48px;

  /* neutrals */
  --ink:  #141210;
  --bone: #E9DFD0;

  /* The mark's own orange, fixed by the logo file. It is the hero and
     nothing else: no territory may borrow it, or the logo stops being
     the one orange object on the page. */
  --c-logo: #FF6600;

  /* the five anchors. Every other colour on the page derives from these.
     TRANSFORM is the logo's complement rather than its neighbour — the
     hero hands off to the first chapter across the wheel, not into a
     second helping of the same orange. */
  --c-transform: #1E8F7E;   /* verdigris  */
  --c-play:      #B4C244;   /* olive lime */
  --c-make:      #2E3C9C;   /* indigo     */
  --c-tell:      #7B1F33;   /* oxblood    */
  --c-think:     #E4C77A;   /* sand       */

  /* background field — written by js/main.js on scroll.
     --field-p is the scroll as a plain 0–1 number; the plate is
     positioned from it in CSS rather than in pixels from script. */
  --bg: #040405;
  --field-p: 0;
  --metal: 0.14;

  /* nav ink flips once the field reaches dawn */
  --nav-fg: var(--bone);

  /* type */
  --f-display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --f-text: 'Instrument Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --f-mono: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ONE curve for the whole site. Fast departure, long settle, no
     overshoot — objects arrive and stop, like paper laid onto a desk.
     Nothing on this page uses a different easing. */
  --ease: cubic-bezier(.16, 1, .3, 1);

  /* Four durations, nothing in between.
     xs interaction · sm detail · md object · lg page-scale */
  --t-xs: 200ms;
  --t-sm: 420ms;
  --t-md: 620ms;
  --t-lg: 900ms;
}

/* Rectangles are rectangles. The only rounded objects on the page are
   the five navigation pills and the Instagram link — that contrast is
   the system, so nothing else gets a radius. */


/* ── 01 Reset & base ─────────────────────────────────────── */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--bone);
  font-family: var(--f-text);
  font-size: 1.0625rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, p, figure { margin: 0; }

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

/* Keyboard focus. The hover states alone were carrying this, and two of
   them are colour-only — which is no focus indicator at all.
   The ring cannot use currentColor: a focused pill turns its text ink,
   which would draw an invisible ring on the dark ground. --focus is
   set by whatever surface the element is sitting on instead. */
:focus-visible {
  outline: 2px solid var(--focus, var(--bone));
  outline-offset: 3px;
}

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

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

.rule {
  border: 0;
  border-top: 1px solid currentColor;
  opacity: .24;
  margin: clamp(30px, 4vw, 48px) 0 22px;
  width: 100%;
}

/* mono technical label */
.footer__label,
.footer__fine,
.hero__founder,
.pill,
.cta {
  font-family: var(--f-mono);
  font-size: .6875rem;
  line-height: 1;
  letter-spacing: .14em;
  text-transform: uppercase;
}


/* ── 02 Background field (night → dawn) ──────────────────── */

.field {
  position: fixed;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  background-color: var(--bg);
  transition: background-color .18s linear;
}

/* THE PLATE. One sheet of scratched steel, three viewports tall, hung
   behind the page — not a texture faded in over a colour. Scrolling
   travels down it, so the plate's own fall from shadow into light runs
   with the colour ramp underneath instead of fighting it: a fixed
   texture would put the same bright patch at the bottom of every
   screen, which reads as a vignette rather than as a surface.

   The travel is a transform, not a background-position. The layer is
   rasterised once and moved on the compositor, so a texture this large
   costs nothing per frame — the same reason the reveals translate
   rather than animate layout.

   The geometry is all in CSS. The plate carries the image's own 1:3
   proportion, so at 300vw tall it is exactly `cover` with no crop, and
   the travel is the overhang: 0 puts its top edge at the top of the
   window, 1 puts its bottom edge at the bottom. max() is the guard for
   a window taller than 1:3, where there is no overhang to travel. */
.field::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: max(300vw, 100vh);
  background: url("../assets/metal.png") 50% 0 / cover no-repeat;
  opacity: var(--metal);
  transform: translate3d(0, calc(var(--field-p) * (100vh - max(300vw, 100vh))), 0);
}

/* Small screens take the plate at native scale or below — it is
   sharper there than anywhere, and sharp is loud. Backing it off keeps
   it a ground rather than a competitor to 17px body copy. */
@media (max-width: 640px) {
  .field::before { opacity: calc(var(--metal) * .78); }
}


/* ── 03 Navigation ───────────────────────────────────────── */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--gutter);
  padding: 20px var(--margin);
  color: var(--nav-fg);
  --focus: var(--nav-fg);
  transition: color .5s var(--ease);
}

.nav__pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* The grid's third track was always there and always empty. The page
   links fill it, so the mark stays centred on the window rather than
   being pushed off by whatever sits beside it. */
.nav__pills--pages { justify-content: flex-end; }

.pill {
  --c: currentColor;
  --ct: var(--ink);
  display: inline-block;
  padding: 9px 15px 8px;
  border: 1px solid currentColor;
  border-radius: 999px;
  opacity: .78;
  transition: background-color .2s var(--ease),
              color .2s var(--ease),
              opacity .2s var(--ease),
              border-color .2s var(--ease);
}

/* The navigation is fixed, so a transparent pill is not a pill on the
   field — it is a pill on whichever chapter happens to be passing
   under it, and the row breaks into five different tints as you
   scroll. Painting each one with the field's own colour keeps the row
   reading as one object on one ground, night through dawn.
   The 78% is still there; it moved off the element, where it was
   thinning the ground as well, and onto the ink alone. */
.nav .pill {
  /* The house default, for any pill with no chapter behind it: the
     nav's own ink becomes the capsule and the ground becomes the
     label — a straight inversion of the resting state, which stays
     legible whichever way --nav-fg is pointing. (The bare .pill
     default above cannot serve here: --c resolving to currentColor
     paints the capsule the same colour as its own text.) */
  --c: var(--nav-fg);
  --ct: var(--bg);
  opacity: 1;
  background-color: var(--bg);
  color: color-mix(in srgb, var(--nav-fg) 78%, transparent);
  /* the ground tracks the field on the field's timing, not the
     interaction timing, so it never lags the page behind it */
  transition: background-color .18s linear,
              color .2s var(--ease),
              border-color .2s var(--ease);
}

.pill:hover,
.pill:focus-visible {
  opacity: 1;
  background: var(--c);
  border-color: var(--c);
  color: var(--ct);
}

/* each chapter pill carries its destination's colour, so the nav
   teaches the code before the visitor has scrolled a pixel. About and
   Contact are not chapters and have no colour to carry — they keep the
   house default, currentColor, which is the same bone-on-ink capsule
   the Instagram link uses in the footer. */
.nav__pills--chapters a:nth-child(1) { --c: var(--c-transform); --ct: var(--ink);  }
.nav__pills--chapters a:nth-child(2) { --c: var(--c-play);      --ct: var(--ink);  }
.nav__pills--chapters a:nth-child(3) { --c: var(--c-make);      --ct: var(--bone); }
.nav__pills--chapters a:nth-child(4) { --c: var(--c-tell);      --ct: var(--bone); }
.nav__pills--chapters a:nth-child(5) { --c: var(--c-think);     --ct: var(--ink);  }

/* Wordmark — brand mark scale, not headline scale. It is a label, not
   a control: no link, no focus stop, and the arrow cursor rather than
   the text caret, so nothing about it invites a click. Everywhere the
   visitor can actually go is a pill. */
.mark {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  cursor: default;
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 112;
  font-weight: 700;
  font-size: 1.25rem;
  letter-spacing: -.015em;
  line-height: 1;
}

/* The X sits inside the same outlined rectangle language as the nav
   pills. The outline is an SVG rather than a border so its corners
   keep their radius at any size the mark is set at.

   The X is the one mark on the page that holds still: it neither
   draws itself on arrival nor answers the pointer. It is the brand,
   not a control, and the five pills beside it are already carrying
   all the invitation the bar needs. */
.mark__x {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.02em;
  height: 1.3em;
  margin-left: .12em;
  border-radius: 5px;
}
.mark__rule {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.mark__rule rect {
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}


/* ── 04 Hero ─────────────────────────────────────────────── */

.hero {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
  align-items: stretch;
  align-content: stretch;
  min-height: 92vh;
  padding-top: clamp(140px, 22vh, 220px);
  padding-bottom: clamp(60px, 10vh, 120px);
}

.hero__text {
  grid-column: 1 / 9;
  align-self: center;
}

.hero__title {
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 110;
  font-weight: 700;
  font-size: clamp(3rem, 7vw, 6.25rem);
  line-height: .92;
  letter-spacing: -.028em;
}

.hero__founder {
  font-size: .75rem;
  color: var(--bone);
  opacity: .62;
  margin-bottom: 24px;
}

.hero__statement {
  max-width: 31rem;
  font-size: clamp(1.0625rem, 1.35vw, 1.25rem);
  line-height: 1.5;
  opacity: .88;
}

/* the single hero rectangle — now the mark itself, still bleeding off
   the right edge of the page. The artwork is laid into the content box
   and only the orange runs past it, so the plane keeps its bleed while
   the X stays whole and on screen. */
.hero__plane {
  grid-column: 9 / 13;
  background: var(--c-logo) url("../assets/yoprofx-logo.svg") no-repeat center / contain;
  background-origin: content-box;
  padding-right: var(--margin);
  margin-right: calc(var(--margin) * -1);
  min-height: 340px;
}

/* The game layer. js/hero-game.js puts one transparent canvas over the
   hero and nowhere else: it scrolls with the hero, so the character can
   never come loose from the page, and it takes no pointer input, so
   every link underneath stays a link. */
.hero { position: relative; }

.hero__game {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  image-rendering: pixelated;
}


/* ── 04b Portals ─────────────────────────────────────────────
   Each portal is an ordinary link: the gate and the label both take
   you there, by click, by tap, by keyboard. The character walking into
   the gate is the third way, not the only one.

   The gate is a teleporter from Engines of Enterprise, cut out of the
   game's tileset: four 32 × 48 frames — unpowered, then three powered.
   It rests on the first powered frame. Nothing on this page loops on
   its own, so it only shimmers while something is at it: a pointer,
   keyboard focus, or the character standing close. */
.hero__stage {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;       /* gates on one line; labels hang below */
  gap: 18px clamp(96px, 16vw, 240px);
  padding-top: clamp(32px, 6vh, 72px);
}

.portal {
  --s: 2.5;                       /* pixel scale of the gate art */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  color: var(--bone);
  text-decoration: none;
}

.portal__gate {
  display: block;
  width: calc(32px * var(--s));
  height: calc(48px * var(--s));
  background: url("../assets/game/portal.png") no-repeat;
  background-size: calc(128px * var(--s)) calc(48px * var(--s));
  background-position: calc(-32px * var(--s)) 0;
  image-rendering: pixelated;
  transition: filter var(--t-xs) var(--ease);
}

.portal:hover .portal__gate,
.portal:focus-visible .portal__gate,
.portal.is-near .portal__gate {
  animation: portal-shimmer 750ms steps(3) infinite;
}

/* the character has stepped in: the gate flares as it takes them */
.portal.is-warping .portal__gate {
  filter: brightness(1.25) drop-shadow(0 0 18px rgba(90, 170, 255, .85));
}

@keyframes portal-shimmer {
  from { background-position: calc(-32px * var(--s)) 0; }
  to   { background-position: calc(-128px * var(--s)) 0; }
}

.portal__label {
  position: relative;
  max-width: 15ch;
  padding-bottom: 6px;
  font-family: var(--f-mono);
  font-size: .75rem;
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: .14em;
  text-align: center;
  text-transform: uppercase;
}
/* the same underline stroke as every other link on the page */
.portal__label::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  opacity: .65;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-sm) var(--ease);
}
.portal:hover .portal__label::after,
.portal:focus-visible .portal__label::after,
.portal.is-near .portal__label::after { transform: scaleX(1); }

/* How to play. Only once the character has actually arrived — a hint
   for a game that failed to load would be a broken promise. */
.hero__hint {
  display: none;
  flex-basis: 100%;
  margin: 10px 0 0;
  font-family: var(--f-mono);
  font-size: .6875rem;
  letter-spacing: .08em;
  text-align: center;
  opacity: .62;
}
.hero.is-playable .hero__hint { display: block; }
.hero__hint--touch { display: none; }
@media (pointer: coarse) {
  .hero__hint--keys  { display: none; }
  .hero__hint--touch { display: inline; }
}

/* The joystick. Touch screens only, fixed to the lower-left corner, and
   only while the hero is on screen — further down the page it would sit
   on top of the reading. Ported from Engines of Enterprise v2, recoloured
   in the site's bone. Only the ring takes input; the page scrolls
   everywhere else. */
.joystick {
  position: fixed;
  left: clamp(16px, 4vw, 40px);
  bottom: calc(clamp(16px, 4vh, 40px) + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  width: clamp(104px, 24vmin, 160px);
  height: clamp(104px, 24vmin, 160px);
  border: 2px solid rgba(233, 223, 208, .5);
  border-radius: 50%;
  background: rgba(4, 4, 5, .45);
  touch-action: none;
  -webkit-user-select: none;
          user-select: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-xs) var(--ease), visibility 0s linear var(--t-xs);
}
.joystick.is-on {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--t-xs) var(--ease);
}
.joystick__thumb {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44%;
  height: 44%;
  border-radius: 50%;
  background: rgba(233, 223, 208, .7);
  transform: translate(-50%, -50%);
  transition: transform .16s var(--ease);
  pointer-events: none;
}
.joystick__thumb.is-dragging { transition: none; }


/* ── 05 Chapters ─────────────────────────────────────────── */

.chapter {
  position: relative;
  padding-block: clamp(80px, 11vh, 140px);
}
/* A and C hang their caption below the plane, so they need the room */
.chapter--a,
.chapter--c {
  padding-bottom: calc(clamp(80px, 11vh, 140px) + 72px);
}

.chapter__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
}

/* The five palettes. --cap is a near-black carrying a trace of its own
   section's hue, so the overlapping block belongs to the plane rather
   than sitting on it like a card. */
.chapter--a { --pc: var(--c-transform); --pt: var(--ink);  --cap: #08201C; --h: 560px; }
.chapter--b { --pc: var(--c-play);      --pt: var(--ink);  --cap: #1B1E0C; --h: 540px; }
.chapter--c { --pc: var(--c-make);      --pt: var(--bone); --cap: #0D1130; --h: 380px; }
.chapter--d { --pc: var(--c-tell);      --pt: var(--bone); --cap: #230A11; --h: 560px; }
.chapter--e { --pc: var(--c-think);     --pt: var(--ink);  --cap: #231C0D; --h: 480px; }

/* the colour plane */
.plane {
  grid-row: 1;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: var(--h);
  padding: clamp(26px, 3vw, 46px);
  background: var(--pc);
  color: var(--pt);
  --focus: var(--pt);
}

.plane__word {
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 112;
  font-weight: 700;
  font-size: clamp(2.5rem, 4.5vw, 4.25rem);
  line-height: .95;
  letter-spacing: -.025em;
}

/* the decorative question */
.q {
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 104;
  font-weight: 500;
  font-size: clamp(1.4rem, 2.4vw, 2.5rem);
  line-height: 1.16;
  letter-spacing: -.012em;
  max-width: 15em;
  margin-top: auto;
  padding-top: clamp(40px, 6vw, 80px);
}

/* The action belongs to the work, not to the territory, so it sits in
   the caption block with the thing it opens. One more film, book or
   game means one more block with its own link, and the plane stays a
   plane. */
.caption__foot {
  display: flex;
  margin-top: clamp(18px, 1.8vw, 26px);
}

/* The brackets are the button. An outlined capsule around bracketed
   text frames the same thing twice, so the outline is gone and the
   brackets open on hover instead. */
.cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 10px 2px 12px;
  font-size: .875rem;
  font-weight: 700;
  letter-spacing: .16em;
  white-space: nowrap;
}
/* STROKE: a rule drawn under the label, left to right — the same
   gesture as the questions and the hero rule, at interaction speed */
.cta::after {
  content: '';
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 2px;
  height: 1px;
  background: currentColor;
  opacity: .65;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-sm) var(--ease);
}
.cta span {
  display: inline-block;
  transition: transform var(--t-sm) var(--ease);
}
.cta:hover::after, .cta:focus-visible::after { transform: scaleX(1); }
.cta:hover span:first-child,
.cta:focus-visible span:first-child { transform: translateX(-6px); }
.cta:hover span:last-child,
.cta:focus-visible span:last-child { transform: translateX(6px); }

/* the dark block that straddles the plane's edge */
.caption {
  grid-row: 1;
  z-index: 2;
  padding: clamp(24px, 2.2vw, 32px);
  background: var(--cap);
  color: var(--bone);
}
.caption p {
  font-size: 1.0625rem;
  line-height: 1.45;
}

/* Overlap discipline: captions on the left cross the plane's bottom edge
   (empty territory); captions on the right cross its side edge — at mid
   height for B and D, high for E — always well outside the question's
   measure. Every block crosses exactly one edge; none of them sits on a
   corner, where two offsets at once read as a collision rather than a
   composition. */
.chapter--a .caption,
.chapter--c .caption {
  align-self: end;
  margin-bottom: -72px;   /* the block straddles the edge, roughly half and half */
}
/* …and the plane keeps a floor under its question deep enough that the
   block — taller now that it carries the link — never lands on a line
   of it. MAKE needs none: its plane holds nothing but the word. */
.chapter--a .plane { padding-bottom: clamp(152px, 11vw, 160px); }
.chapter--b .caption,
.chapter--d .caption { align-self: center; }

/* — composition: five variations on one three-object chord — */

/* A · right-weighted plane, caption in from the left */
.chapter--a .plane   { grid-column: 4 / 13; }
.chapter--a .caption { grid-column: 1 / 5; }

/* B · mirrored */
.chapter--b .plane   { grid-column: 1 / 11; }
.chapter--b .caption { grid-column: 9 / 13; }

/* C · short and narrow — the breath in the sequence */
.chapter--c .plane   { grid-column: 6 / 13; }
.chapter--c .caption { grid-column: 2 / 7; }

/* D · widest plane */
.chapter--d .plane   { grid-column: 1 / 12; }
.chapter--d .caption { grid-column: 10 / 13; }

/* E · resolution — the last chord is the same three objects as the rest,
   not a stack: the block crosses the plane's right edge the way B's and
   D's do, but rides high on it. THINK carries its word at the top left
   and its question along the bottom, so the upper right is the one
   quarter of the plane the block can take without landing on a line.
   A second block crosses the bottom edge the way A's and C's do, in from
   the right corner, over a floor deep enough to keep it off the question. */
.chapter--e { padding-bottom: calc(clamp(80px, 11vh, 140px) + 72px); }
.chapter--e .plane {
  grid-row: 1;
  grid-column: 3 / 11;
  padding-bottom: clamp(152px, 11vw, 160px);
}
.chapter--e .caption--high {
  grid-row: 1;
  grid-column: 9 / 13;
  align-self: start;
  /* far enough down that the block reads as placed on the edge rather
     than as flush with the plane's top corner */
  margin-top: clamp(40px, 5vw, 72px);
}
.chapter--e .caption--low {
  grid-row: 1;
  grid-column: 6 / 10;
  align-self: end;
  margin-bottom: -72px;
}


/* ── 06 Footer ───────────────────────────────────────────── */

.footer {
  display: grid;
  grid-template-columns: 5fr 7fr;
  min-height: 85vh;
  margin-top: clamp(80px, 12vh, 160px);
}

.footer__half {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.footer__half--ink  { background: var(--ink);  color: var(--bone); }
.footer__half--bone { background: var(--bone); color: var(--ink); --focus: var(--ink); }

.footer__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: clamp(24px, 3vw, 40px);
  padding: clamp(36px, 4.5vw, 72px) clamp(28px, 3.5vw, 56px);
}

.footer__label { opacity: .62; }

.footer__nav {
  display: flex;
  flex-direction: column;
  margin-top: auto;
}
.footer__nav a {
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 110;
  font-weight: 700;
  font-size: clamp(1.9rem, 3.2vw, 3rem);
  line-height: 1.12;
  letter-spacing: -.025em;
  transition: color .22s var(--ease);
}
.footer__nav a:hover, .footer__nav a:focus-visible { color: var(--c); }
.footer__nav a:nth-child(1) { --c: var(--c-transform); }
.footer__nav a:nth-child(2) { --c: var(--c-play); }
.footer__nav a:nth-child(3) { --c: var(--c-make); }
.footer__nav a:nth-child(4) { --c: var(--c-tell); }
.footer__nav a:nth-child(5) { --c: var(--c-think); }

/* the statement holds the top, the link and the colophon anchor the
   bottom — the space between them is the composition, not a gap */
.footer__founder {
  margin-bottom: auto;
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 106;
  font-weight: 500;
  font-size: clamp(1.5rem, 2.4vw, 2.5rem);
  line-height: 1.12;
  letter-spacing: -.015em;
}

.pill--footer { align-self: flex-start; opacity: .8; }
.pill--footer:hover, .pill--footer:focus-visible {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bone);
  opacity: 1;
}

.footer__fine {
  opacity: .62;
  border-top: 1px solid currentColor;
  padding-top: 18px;
}

/* the oversized wordmark, cropped by the page edge, split by the seam */
.footer__crop {
  position: relative;
  height: 12vw;
  min-height: 64px;
}
.footer__crop span {
  position: absolute;
  bottom: -9vw;
  font-family: var(--f-display);
  font-variation-settings: 'wdth' 116;
  font-weight: 700;
  font-size: 22.5vw;
  line-height: 1;
  letter-spacing: -.045em;
  text-align: center;
  white-space: nowrap;
}
/* both halves map onto the same full-footer coordinate space (5fr / 7fr) */
.footer__half--ink  .footer__crop span { width: 240%;    left: 0; }
.footer__half--bone .footer__crop span { width: 171.43%; left: -71.43%; }


/* ── 07 Motion ───────────────────────────────────────────────
   ONE language, three gestures, and every object belongs to exactly
   one of them:

     SETTLE    solid objects arrive vertically and stop.
               Planes, the hero field, the footer. Short travel, a
               whisper of scale from the bottom edge, like something
               being set down rather than flown in.

     SLIDE     secondary blocks enter laterally from the side they
               already overlap, so the movement explains the
               composition instead of decorating it.

     STROKE    anything that reads as a mark made by a hand travels
               left to right: rules, the big questions, the button
               underline, the drawing of the logo.

   One curve (--ease), four durations, no loops, nothing continuous.
   Sequencing is a --d delay on the element; there is no stagger
   engine and no per-word animation anywhere on the page.
   ──────────────────────────────────────────────────────────── */

/* — SETTLE — */
.js [data-reveal] .hero__plane,
.js [data-reveal] .plane,
.js [data-reveal] .footer__body,
.js [data-reveal] .footer__crop {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--t-md) var(--ease) var(--d, 0ms),
              transform var(--t-md) var(--ease) var(--d, 0ms);
}

/* — SLIDE — the block comes in from the edge it hangs over */
.js [data-reveal] .caption {
  opacity: 0;
  transition: opacity var(--t-md) var(--ease) var(--d, 140ms),
              transform var(--t-md) var(--ease) var(--d, 140ms);
}
.js .chapter--a .caption,
.js .chapter--c .caption { transform: translateX(-26px); }
.js .chapter--b .caption,
.js .chapter--d .caption,
.js .chapter--e .caption { transform: translateX(26px); }

/* — SETTLE, hero copy — */
.js [data-reveal] .hero__title,
.js [data-reveal] .hero__founder,
.js [data-reveal] .hero__statement {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--t-md) var(--ease) var(--d, 0ms),
              transform var(--t-md) var(--ease) var(--d, 0ms);
}

/* — STROKE — rules draw themselves from the left */
.js [data-reveal] .rule {
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-lg) var(--ease) var(--d, 0ms);
}

/* — STROKE — the question is uncovered, not faded */
.js [data-reveal] .q {
  clip-path: inset(0 101% 0 0);
  transition: clip-path var(--t-lg) var(--ease) var(--d, 200ms);
}

.js [data-reveal].is-in .hero__plane,
.js [data-reveal].is-in .plane,
.js [data-reveal].is-in .footer__body,
.js [data-reveal].is-in .footer__crop,
.js [data-reveal].is-in .caption,
.js [data-reveal].is-in .hero__title,
.js [data-reveal].is-in .hero__founder,
.js [data-reveal].is-in .hero__statement {
  opacity: 1;
  transform: none;
}
.js [data-reveal].is-in .rule { transform: scaleX(1); }
.js [data-reveal].is-in .q { clip-path: inset(0 -1% 0 0); }

/* The opening title sequence. Field, then the object, then the name,
   then the rule drawn under it, then the credit. Everything has
   landed inside a second. */
.hero__plane     { --d: 80ms; }
.hero__title     { --d: 200ms; }
.rule            { --d: 340ms; }
.hero__founder   { --d: 430ms; }
.hero__statement { --d: 490ms; }

/* Navigation. Animation rather than transition so the pills keep
   their own hover transition untouched; `backwards` holds the start
   frame through the delay and hands back to the base rule at the end,
   so nothing is left overridden. */
@keyframes nav-in {
  from { opacity: 0; transform: translateY(-8px); }
}
.js .nav.is-ready .mark { animation: nav-in var(--t-md) var(--ease) 60ms backwards; }
.js .nav.is-ready .pill { animation: nav-in var(--t-sm) var(--ease) var(--d) backwards; }
.nav__pills--chapters a:nth-child(1) { --d: 200ms; }
.nav__pills--chapters a:nth-child(2) { --d: 250ms; }
.nav__pills--chapters a:nth-child(3) { --d: 300ms; }
.nav__pills--chapters a:nth-child(4) { --d: 350ms; }
.nav__pills--chapters a:nth-child(5) { --d: 400ms; }
/* the page links close the row, on the same 50ms step */
.nav__pills--pages a:nth-child(1) { --d: 450ms; }
.nav__pills--pages a:nth-child(2) { --d: 500ms; }

/* The mark's rectangle used to draw itself here, on load. It does not
   any more — the box is simply there, from the first frame. The mark
   still arrives with the rest of the bar on the nav-in above; that is
   the opening sequence, not the X answering for itself. */

/* Reduced motion: the finished state, immediately. No entrance, no
   wipe. The field still tracks scroll — that is position, not
   movement — but it changes without a transition. */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] .hero__plane,
  .js [data-reveal] .plane,
  .js [data-reveal] .footer__body,
  .js [data-reveal] .footer__crop,
  .js [data-reveal] .caption,
  .js [data-reveal] .hero__title,
  .js [data-reveal] .hero__founder,
  .js [data-reveal] .hero__statement,
  .js [data-reveal] .rule,
  .js .nav.is-ready .mark,
  .js .nav.is-ready .pill {
    opacity: 1;
    transform: none;
    animation: none;
    transition: none;
  }
  .js [data-reveal] .q { clip-path: none; transition: none; }
  .field { transition: none; }
  .brush--reveal { clip-path: none !important; transition: none !important; }
  /* the gates stay powered but still; walking is the visitor's own
     movement and is left alone */
  .portal .portal__gate { animation: none; transition: none; }
  .portal__label::after,
  .joystick, .joystick__thumb { transition: none; }
  * { scroll-behavior: auto; }
}


/* ── 08 Responsive ───────────────────────────────────────── */

@media (max-width: 1100px) {
  :root { --margin: 32px; }

  .hero__text   { grid-column: 1 / 10; }
  .hero__plane  { grid-column: 10 / 13; }

  .chapter--a .plane   { grid-column: 3 / 13; }
  .chapter--a .caption { grid-column: 1 / 6; }
  .chapter--b .plane   { grid-column: 1 / 11; }
  .chapter--b .caption { grid-column: 8 / 13; }
  .chapter--c .plane   { grid-column: 4 / 13; }
  .chapter--c .caption { grid-column: 1 / 6; }
  .chapter--d .plane   { grid-column: 1 / 12; }
  .chapter--d .caption { grid-column: 9 / 13; }
  .chapter--e .plane   { grid-column: 2 / 12; }
  .chapter--e .caption { grid-column: 9 / 13; }
}

@media (max-width: 900px) {
  /* Navigation stacks and scrolls away rather than sitting on top of
     the content. It sits in the flow, so the hero starts below however
     many rows the pills wrap to — a fixed allowance for it overlapped
     the title once a phone wrapped them to three. The hero goes to one
     column. The five sections do NOT collapse yet — a tablet has room
     for the composition. */
  .nav {
    position: relative;
    grid-template-columns: 1fr;
    justify-items: center;
    gap: 14px;
    padding: 20px var(--margin) 14px;
    text-align: center;
  }
  .mark { order: -1; }
  .nav__pills { justify-content: center; gap: 8px; }

  .hero {
    grid-template-columns: 1fr;
    min-height: auto;
    padding-top: 40px;
    padding-bottom: 88px;
  }
  .hero__text, .hero__plane { grid-column: 1; }
  .hero__plane {
    min-height: 132px;
    margin-top: 48px;
    margin-left: calc(var(--margin) * -1);
    /* full-bleed band now: the mark sits centred in the page's own
       measure while the orange runs out to both edges */
    padding-inline: var(--margin);
  }

  /* Narrower planes hold less, so the same heights read as holes
     rather than as space. Heights and the gaps between come down
     together to keep the rhythm even. */
  .chapter--a { --h: 470px; }
  .chapter--b { --h: 450px; }
  .chapter--c { --h: 320px; }
  .chapter--d { --h: 470px; }
  .chapter--e { --h: 410px; }

  .chapter { padding-block: 84px; }
  .chapter--a,
  .chapter--c,
  .chapter--e { padding-bottom: 140px; }
}

@media (max-width: 720px) {
  :root { --margin: 22px; --gutter: 16px; }

  .pill { padding: 8px 13px 7px; font-size: .625rem; letter-spacing: .1em; }
  .hero { padding-top: 32px; }

  /* Smaller gates, held to the right: the joystick owns the lower-left
     corner and must never sit on a portal. */
  .hero__stage { justify-content: flex-end; gap: 18px clamp(28px, 9vw, 56px); }
  .portal { --s: 2; }
  .hero__hint { text-align: right; }

  /* One column, but the offsets stay: every block still steps in from
     an edge and still crosses the plane it belongs to. */
  .chapter { padding-block: 64px; }
  .chapter__grid { grid-template-columns: 1fr; }
  .chapter .plane,
  .chapter .caption { grid-column: 1; grid-row: auto; }

  /* extra floor inside the plane so the overlapping block
     never reaches the question */
  .plane { min-height: 0; padding: 26px 22px 62px; }
  .chapter--a .plane { padding-bottom: 62px; }  /* the wide floor is a desktop concern */
  .chapter--c .plane { min-height: 300px; }
  .q { max-width: none; padding-top: 44px; }

  .chapter--a .caption,
  .chapter--b .caption,
  .chapter--c .caption,
  .chapter--d .caption {
    align-self: auto;
    margin: -36px 0 0 26px;
  }
  /* THINK's block sits above its plane, so it overlaps downward */
  .chapter--e .caption--high { align-self: auto; margin: 0 0 -36px 26px; }
  /* …and its second block sits below, overlapping upward like the rest */
  .chapter--e .caption--low  { align-self: auto; margin: -36px 0 0 26px; }
  .chapter--e .plane { padding-bottom: 62px; }
  .chapter--a, .chapter--c, .chapter--e { padding-bottom: 64px; }

  .footer { grid-template-columns: 1fr; min-height: 0; }
  .footer__half--ink .footer__crop { display: none; }
  .footer__crop { height: 13vw; min-height: 50px; }
  .footer__half--bone .footer__crop span {
    width: 100%;
    left: 0;
    bottom: -9vw;
    font-size: 24vw;
  }
  .footer__nav { margin-top: 28px; }
}


/* ── 09 Brush stroke image treatment ─────────────────────────
   Not used on the landing page. This is the reusable treatment for
   portraits and project imagery on the pages that come later.

   Two parts, and they do different jobs:

     .brush          masks the image to the shape of a loaded brush
                     stroke — irregular edges, dry-brush skips, the
                     bristles splitting at the exit.

     .brush--reveal  drags that stroke across the frame once, left to
                     right, when it enters the viewport. STROKE, the
                     same gesture as the questions and the hero rule.

   Usage:
     <figure class="brush brush--reveal" data-reveal>
       <img src="…" alt="…">
     </figure>
   ──────────────────────────────────────────────────────────── */

.brush {
  display: block;
  margin: 0;
  -webkit-mask-image: url(../assets/brush.svg);
          mask-image: url(../assets/brush.svg);
  /* The stroke spans the width once, at its own proportions, and sits
     where it lands. Never stretched and never blown up: magnify a
     brush edge and it starts to read as torn paper. */
  -webkit-mask-size: 100% auto;
          mask-size: 100% auto;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* Fills the frame instead of banding it. Costs you the ends of the
   stroke and some magnification — worth it on wide images only. */
.brush--cover {
  -webkit-mask-size: cover;
          mask-size: cover;
}

.brush > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Three plates off one stroke. Shifting and scaling the mask lands a
   different part of the bristle work in frame, so a row of portraits
   never repeats the same silhouette. */
.brush--b {
  -webkit-mask-size: 116% auto;
          mask-size: 116% auto;
  -webkit-mask-position: -22% 42%;
          mask-position: -22% 42%;
}
.brush--c {
  -webkit-mask-size: 108% auto;
          mask-size: 108% auto;
  -webkit-mask-position: 116% 60%;
          mask-position: 116% 60%;
}

/* the drag */
.js .brush--reveal {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1100ms var(--ease) var(--d, 0ms);
}
.js .brush--reveal.is-in,
.js [data-reveal].is-in .brush--reveal { clip-path: inset(0 0 0 0); }
