/* ==========================================================================
   Marble Consulting Group — editorial layer, part 2 of 2

   editorial.css grew past 500KB, which a plain static file server truncates
   mid-transfer: everything past ~522KB silently never reached the browser, so
   the page rendered half-styled and any rule near the end was dead on arrival.
   The file is split at a brace-depth-zero boundary - nothing is deleted, added
   or reordered, and part 1 then part 2 in the <head> is byte-identical to the
   original cascade.
   ========================================================================== */

.otn__frame--move .otn__shot img {
  object-position: 44% 46%;
  filter:
    brightness(calc(0.5 + 0.54 * var(--m)))
    saturate(calc(0.7 + 0.42 * var(--m)))
    contrast(calc(0.96 + 0.08 * var(--m)));
}
.otn__frame--move .otn__shot {
  box-shadow:
    inset 0 0 0 1px rgba(192, 156, 96, calc(0.14 + 0.3 * var(--m))),
    0 calc(var(--m) * 34px) calc(24px + var(--m) * 56px) -20px rgba(0, 0, 0, calc(0.18 + 0.62 * var(--m)));
}

.otn__shot {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 2px;
  background: var(--obsidian-raised);
}
.otn__shot img {
  position: absolute;
  inset: -5%;
  width: 110%;
  height: 110%;
  /* main.css carries a global img { max-width: 100% } that silently clamps
     any deliberately oversized image */
  max-width: none;
  display: block;
  object-fit: cover;
  /* NO transition on filter: it is computed from --m, which GSAP writes
     every frame, and a transition would smear the whole scrub */
}

/* the pointer specular, inside the frame so it is clipped with the picture */
.otn__gleam {
  --omx: 50;
  --omy: 50;
  position: absolute;
  inset: 0;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background: radial-gradient(42% 34% at calc(var(--omx) * 1%) calc(var(--omy) * 1%),
    rgba(255, 240, 212, 0.2), transparent 70%);
}

/* ---- the words. Fixed, and each one carries its own scrim, because a
   photograph is travelling underneath them. ---- */
.otn__head,
.otn__lede,
.otn__neg,
.otn__note,
.otn__end {
  position: absolute;
  z-index: 5;
  isolation: isolate;    /* keeps the scrim pseudo out of the frames' business */
}
/* ONLY the negations cross a photograph, so only they carry a scrim. A
   scrim behind a block that sits on plain obsidian paints a slightly
   different black rectangle with visible edges and nothing else. It has to
   be a wide soft ellipse rather than a box, because it crosses both frames
   and one of them is lit. */
.otn__neg::before {
  content: "";
  position: absolute;
  inset: -3.4rem -5rem -3.6rem -4.4rem;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(46% 52% at 40% 50%, rgba(6, 6, 8, 0.93), rgba(6, 6, 8, 0.74) 56%, rgb(34 31 27 / 0) 88%),
    radial-gradient(72% 76% at 46% 50%, rgba(6, 6, 8, 0.6), rgb(34 31 27 / 0) 84%);
}

.otn__head { left: 3%; top: 6%; width: 38%; }
.otn__h {
  margin: 0.55rem 0 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--white);
}
.otn__h em { font-style: italic; color: var(--gold-light); }

.otn__lede {
  left: 3%;
  top: 44%;
  width: 31%;
  margin: 0;
  color: var(--ink);
  font-size: var(--text-lg);
  line-height: 1.6;
}

.otn__neg {
  left: 30%;
  top: 56%;
  width: 52%;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.3rem, 1rem + 1.2vw, 1.85rem);
  line-height: 1.24;
  letter-spacing: -0.014em;
  color: var(--white);
}

.otn__note {
  left: 62%;
  top: 90%;
  width: 30%;
  margin: 0;
  color: var(--vein);
  font-size: var(--text-sm);
  line-height: 1.68;
}

.otn__end { left: 3%; top: 76%; width: 46%; }
.otn__close {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.5rem, 1.15rem + 1.4vw, 2.2rem);
  line-height: 1.18;
  letter-spacing: -0.018em;
  color: var(--white);
}
.otn__close span { display: inline; }
.otn__close em { font-style: italic; color: var(--gold-light); }
.otn__act { margin-top: clamp(1.1rem, 0.85rem + 1vw, 1.8rem); }

@media (hover: hover) and (pointer: fine) {
  .otn__frame--move:hover .otn__shot { box-shadow:
    inset 0 0 0 1px rgba(192, 156, 96, calc(0.3 + 0.3 * var(--m))),
    0 calc(var(--m) * 40px) calc(24px + var(--m) * 64px) -18px rgba(0, 0, 0, calc(0.24 + 0.62 * var(--m))); }
}

/* ---- the type wraps to more lines as the measure narrows, so the stage
   gets taller in steps rather than in one jump ---- */
@media (max-width: 1360px) { .otn__stage { --oh: 0.66; } }
@media (max-width: 1180px) { .otn__stage { --oh: 0.75; } }
@media (max-width: 1024px) { .otn__stage { --oh: 0.86; } }

/* ---- 900 and below the overtake cannot hold: two frames crossing each
   other need the horizontal room they cross in. The stage becomes a run
   in reading order, the doorstep stays the larger of the two, and every
   absolute value the composition set has to be reset here. ---- */
@media (max-width: 900px) {
  .otn__stage {
    --oh: auto;
    aspect-ratio: auto;
    display: grid;
    gap: clamp(1.6rem, 1rem + 2.4vw, 2.6rem);
  }
  .otn__frame,
  .otn__head,
  .otn__lede,
  .otn__neg,
  .otn__note,
  .otn__end {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
  }
  .otn__lede::before,
  .otn__neg::before,
  .otn__note::before { inset: -0.7rem -1rem; background: none; }

  /* reading order: headline, who it suits, the doorstep, the negations,
     the tower, the mechanism, the standard */
  .otn__head        { order: 1; }
  .otn__lede        { order: 2; max-width: 34rem; }
  .otn__frame--move { order: 3; --ar: 4 / 5; width: min(78%, 22rem); margin-left: auto; }
  .otn__neg         { order: 4; max-width: 30rem; }
  .otn__frame--wait { order: 5; --ar: 3 / 4; width: min(58%, 16rem); }
  .otn__note        { order: 6; max-width: 30rem; margin-left: auto; }
  .otn__end         { order: 7; max-width: 34rem; }

  /* the grade is the argument even when the geometry cannot be: the tower
     stays cool and soft, the doorstep stays lit */
  .otn__frame--wait .otn__shot img { filter: brightness(0.72) saturate(0.6) hue-rotate(-10deg) blur(1.3px); }
  .otn__frame--move .otn__shot img { filter: brightness(1.02) saturate(1.1) contrast(1.04); }
}

@media (max-width: 560px) {
  .otn__frame--move { width: min(92%, 20rem); }
  .otn__frame--wait { width: min(66%, 13rem); }
}

@media (prefers-reduced-motion: reduce) {
  .otn__gleam { transition: none; }
}

/* ==========================================================================
   THE FLOOR — team.html, Behind the scenes (section 04)
   Replaced a `.rail--scroll` horizontal gallery whose four `.media` frames
   all used `data-src`, so the clean-pass hid every one of them and the
   section rendered as four blank marble panels. `.rail--scroll` /
   `.railwrap` / `.rail__item` stay: about.html still uses them.

   THE PRINTS ARE SPREAD, NOT SCROLLED. Four sizes, four crops, four
   angles, overlapping at the corners the way prints actually sit on a
   table, and the scroll spreads them out of one tight pile. 01 turns,
   02 converges, 03 holds still, this one spreads.

   --gather is written in PX by main.js. A percentage translate resolves
   against the element's own size rather than its parent, which is the trap
   that shaped `.wall`, and cqw would break the whole transform where it is
   unsupported. It defaults to 0 so no-JS renders the prints already
   spread.
   ========================================================================== */

@property --spread { syntax: "<number>"; initial-value: 1; inherits: false; }

.floor { position: relative; overflow-x: clip; }

.floor__head { max-width: 46rem; }
.floor__h {
  margin-top: clamp(0.9rem, 0.75rem + 0.6vw, 1.4rem);
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.floor__note {
  position: absolute;
  /* clear of print D's corner by a real gutter, measured: at 72% the two
     overlapped by 5px */
  left: 74.5%;
  top: 64%;
  width: 25.5%;
  z-index: 6;
  color: var(--vein);
  font-size: var(--text-sm);
  line-height: 1.75;
}
.floor__note i {
  display: block;
  width: 2.2rem;
  height: 1px;
  margin-bottom: 0.85rem;
  background: linear-gradient(90deg, var(--gold-light), transparent);
}

/* ---- the table ---------------------------------------------------------- */

.floor__stage {
  position: relative;
  margin-top: clamp(2rem, 1.4rem + 2.6vw, 3.5rem);
  aspect-ratio: 1 / 0.58;
}

.print {
  position: absolute;
  margin: 0;
  /* the gather runs first so the rotation and scale pivot on the print's
     own centre wherever it currently is */
  transform:
    translate(calc(var(--gx, 0px) * (1 - var(--spread))), calc(var(--gy, 0px) * (1 - var(--spread))))
    rotate(calc(var(--rot) * var(--spread)))
    scale(calc(0.88 + 0.12 * var(--spread)));
}

/* hand-laid: no two share a width, a crop, an angle or a corner */
.print--a { left: 0;   top: 10%; width: 36%; aspect-ratio: 16 / 9; --rot: -1.4deg; z-index: 1; }
.print--b { left: 40%; top: 0;   width: 24%; aspect-ratio: 4 / 3;  --rot: 1.1deg;  z-index: 2; }
/* z-index 5, above D: the two overlap at a corner and D was landing on
   top of C's caption, clipping the first word off it. The print that owns
   the caption has to own the stacking. */
.print--c { left: 64%; top: 8%;  width: 27%; aspect-ratio: 1 / 1;  --rot: -0.7deg; z-index: 5; }
.print--d { left: 26%; top: 40%; width: 46%; aspect-ratio: 3 / 2;  --rot: 1.6deg;  z-index: 4; }

.print__shot {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--radius-sm);
  box-shadow:
    0 0 0 1px rgba(156, 120, 72, 0.24),
    0 34px 64px -30px rgba(0, 0, 0, 0.95);
  transition: filter 0.45s var(--ease-out), box-shadow 0.45s var(--ease-out);
}
.print__shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.84) contrast(1.04) saturate(0.84);
}
.print__shot::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(90% 70% at 22% 8%, rgba(156, 120, 72, 0.13), transparent 58%),
    linear-gradient(180deg, transparent 48%, rgba(6, 6, 8, 0.8));
}

/* hover lands on filter and shadow only: GSAP composes the transform from
   --spread and must not share it */
@media (hover: hover) {
  .print:hover .print__shot {
    filter: brightness(1.15);
    box-shadow:
      0 0 0 1px rgba(192, 156, 96, 0.5),
      0 34px 64px -30px rgba(0, 0, 0, 0.95);
  }
  .floor__stage:has(.print:hover) .print:not(:hover) .print__shot {
    filter: brightness(0.82);
  }
}

.print__cap {
  /* holds back until its print has actually landed */
  opacity: calc(1.5 * var(--spread) - 0.5);
  position: absolute;
  left: 0.95rem;
  right: 0.95rem;
  bottom: 0.8rem;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.95);
}
.print__cap i {
  flex: 0 0 auto;
  width: 0.9rem;
  height: 1px;
  background: var(--gold-light);
}

/* ---- narrower ----------------------------------------------------------- */

/* Below the desktop range the four prints stop being a table you look down
   at and become a column you read. Absolute placement is dropped entirely
   rather than re-tuned, because four overlapping frames in 400px of width
   is a pile, not a composition. */
@media (max-width: 860px) {
  .floor__stage {
    aspect-ratio: auto;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(0.75rem, 0.5rem + 1.4vw, 1.4rem);
  }
  .print,
  .print--a,
  .print--b,
  .print--c,
  .print--d {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    transform: rotate(calc(var(--rot) * var(--spread)));
  }
  /* the two wide crops take the full row so the set still has a rhythm */
  .print--a { grid-column: 1 / -1; aspect-ratio: 2 / 1; }
  .print--d { grid-column: 1 / -1; aspect-ratio: 2 / 1; }
  /* back into flow with the prints once the table becomes a column */
  .floor__note {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    grid-column: 1 / -1;
    margin-top: 0.25rem;
  }
}

@media (max-width: 520px) {
  .floor__stage { grid-template-columns: minmax(0, 1fr); }
  .print--b { aspect-ratio: 3 / 2; }
  .print--c { aspect-ratio: 4 / 3; }
  .print__cap { font-size: 0.55rem; letter-spacing: 0.14em; }
}

@media (prefers-reduced-motion: reduce) {
  .print__shot { transition: none; }
}


/* ==========================================================================
   TEAM PAGE RHYTHM + TYPE SCALE — scoped to this page on purpose.
   The client asked for a medium heading size and less air between the
   sections, the same pass what-we-do had. Both are scoped to `.team` so no
   other page moves: `--section` cascades into every `.section` inside the
   main element, and the headings are re-declared here rather than by
   touching the shared `--text-h2` / `--text-h1` tokens, which still run
   index / about / results / careers / contact / the two legal pages.

   If the request ever becomes "do it site-wide", change --text-h2,
   --text-h1 and --section in main.css and delete this block.

   THE LADDER, and keep it in this order:
     hero h1            3rem
     section h2         2.6rem   (.clk__h .fld__h .otn__h .floor__h
                                  and .sec--md h2)
     closing statement  2.2rem   (.otn__close)
     display lede       1.85rem  (.otn__neg)
     panel heading      2rem     (.fld__note--1 .fld__name)
     sub-headings       1.5rem   (.fld__name)

   NOTE the two rebuilds this block has already outlived: .seat became .fld
   and .turn became .otn, and the selectors here went stale both times
   because the sizes are also declared in each section's own block. When a
   section is replaced, GREP THIS BLOCK for its prefix.
   ========================================================================== */

.team {
  --section: clamp(3.5rem, 2.5rem + 4vw, 5.75rem);
  --section-sm: clamp(2.75rem, 2rem + 3vw, 4.25rem);
}

.team .hero h1 {
  font-size: clamp(1.95rem, 1.45rem + 2.1vw, 3rem);
  line-height: 1.1;
}

.team .clk__h,
.team .fld__h,
.team .otn__h,
.team .floor__h {
  font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.team .otn__close { font-size: clamp(1.35rem, 1.05rem + 1.45vw, 2.2rem); }
.team .otn__neg { font-size: clamp(1.25rem, 1.02rem + 1.15vw, 1.85rem); }
.team .fld__note--1 .fld__name { font-size: clamp(1.4rem, 1.15rem + 1.2vw, 2rem); }
.team .fld__name { font-size: clamp(1.1rem, 0.98rem + 0.55vw, 1.5rem); }
.team .clk__name { font-size: clamp(1.25rem, 1.12rem + 0.5vw, 1.55rem); }

/* the engraved numerals come down with everything else, or they end up
   louder than the headings they sit beside */
.team .fld__mark { font-size: clamp(2.4rem, 1.7rem + 2.8vw, 4.4rem); }

/* the lede paragraphs step down one notch so the body does not crowd the
   now-smaller headings */
.team .clk__lede,
.team .fld__lead,
.team .otn__lede { font-size: clamp(1rem, 0.96rem + 0.2vw, 1.125rem); }

/* ==========================================================================
   CAREERS HERO — "the board"   (careers.html)

   Was the shared `.hero--page`: eyebrow, headline, sub, a 5% mark
   watermark and a glow. `.hero--page` is untouched and still runs
   about / contact / privacy / terms.

   THE HEADLINE ALREADY NAMED THE OBJECT. "No seniority. No waiting. A
   leaderboard." was being set as flat type over a watermark, so the one
   concrete thing this page offers a candidate was asserted rather than
   shown. The hero is now the board itself: three positions standing on
   one rule, each one a photograph of the work, each one carrying its own
   engraved position numeral.

   THE MOTION IS REORDERING, AND THAT IS WHY IT CAN EXIST HERE. Every
   other moment on this site moves a different way - index travels X,
   pushes Z, climbs Y, turns an object and strikes type through;
   what-we-do swings doors and assembles a case; results registers a tear
   and develops a print; team slides lanes in and runs a clock. Nothing
   anywhere REORDERS, and reordering is the single thing a leaderboard
   does. The position numerals roll on a reel as the standing changes, so
   the change is unmistakable with no caption explaining it.

   THE ENTRANCE IS THE BOARD RESOLVING. While the preloader curtain is up
   every plate sits at last place - same height, same grade - and the
   standing sorts itself out as the curtain lifts. Then, on a slow cycle,
   whoever is last comes up to first and everyone else steps down one.
   Hovering a plate promotes it, because the argument is that anyone can
   be at the top and nothing about the order is owed to anybody.

   RANK IS ONE NUMBER. `--rank` (0, 1, 2) drives height, grade, frame,
   glow, numeral opacity and the reel, all through calc. That is what
   makes the whole sort one CSS transition instead of a tween per
   property, and it is why the module can live in main.js and work with
   GSAP absent - a hero cannot depend on a CDN (same call as `.tally`).

   THE GRADE ONLY FALLS A LITTLE (1.04 / 0.90 / 0.76). Prominence is
   carried by height, frame and glow instead, because crushing third
   place into the dark is how this site keeps producing the empty-screen
   failure. Third place is still a photograph you can read.

   Photography is another explicit exception to the `.media img` clean
   pass, via its own `.bp__*` classes: field-dusk / door / phone-win, the
   arc of the job in three anonymous frames. No faces are claimed and no
   names or numbers are attached to any position.
   ========================================================================== */

.hero--board {
  min-height: min(80svh, 44rem);
  padding-top: clamp(3.625rem, 3.045rem + 1.392vw, 4.495rem);
  padding-bottom: clamp(1.75rem, 1.4rem + 1.4vw, 2.75rem);
  justify-content: stretch;
}

.board__wash {
  position: absolute;
  inset: -6%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(30rem 24rem at 72% 18%, rgba(192, 156, 96, 0.2), transparent 66%),
    radial-gradient(26rem 20rem at 84% 78%, rgba(156, 120, 72, 0.12), transparent 68%),
    radial-gradient(40rem 24rem at 2% 96%, rgba(156, 120, 72, 0.08), transparent 62%);
}

.board__inner {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.board__body {
  display: grid;
  grid-template-columns: minmax(0, 1.04fr) minmax(0, 0.96fr);
  gap: clamp(2rem, 1.2rem + 3.4vw, 4.5rem);
  align-items: center;
}

/* ---- the claim --------------------------------------------------------- */

.board__claim { max-width: 34rem; }

.board h1 {
  font-size: clamp(1.95rem, 1.45rem + 2.1vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.026em;
  margin-bottom: clamp(1rem, 0.85rem + 0.7vw, 1.5rem);
}
.board h1 em { font-style: italic; color: var(--gold-light); }

.board .hero__sub { max-width: 31rem; margin-bottom: 0; }

/* the sentence the whole composition is arguing, set apart on a hairline */
.board__note {
  margin-top: clamp(1.1rem, 0.9rem + 0.9vw, 1.7rem);
  padding-left: clamp(0.9rem, 0.7rem + 0.8vw, 1.35rem);
  border-left: 1px solid rgba(156, 120, 72, 0.42);
  max-width: 26rem;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--ink);
  text-wrap: pretty;
}

.board .hero__actions { margin-top: clamp(1.4rem, 1.1rem + 1.2vw, 2.1rem); }

/* ---- the board --------------------------------------------------------- */

.board__stand {
  --stand-h: clamp(17rem, 11rem + 21vw, 28.5rem);
  position: relative;
  margin: 0;
  width: 100%;
}

/* a board is an object, so it gets a header the way a real one would */
.board__head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: clamp(0.7rem, 0.6rem + 0.4vw, 1rem);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold);
}
.board__head i {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, rgba(156, 120, 72, 0.5), rgba(156, 120, 72, 0.05));
}

.board__plates {
  position: relative;
  display: grid;
  /* hand-set unequal, so three plates on a shared baseline never resolve
     into the even columns of a chart */
  grid-template-columns: 1.15fr 0.78fr 1fr;
  column-gap: clamp(0.5rem, 0.35rem + 0.6vw, 0.95rem);
  height: var(--stand-h);
}

/* the rule the standing stands on. Static: it is structure, not motion. */
.board__base {
  display: block;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(156, 120, 72, 0.5) 0%,
    rgba(156, 120, 72, 0.28) 62%,
    rgba(156, 120, 72, 0.08) 100%);
}

.board__tell {
  margin-top: clamp(0.7rem, 0.6rem + 0.4vw, 1rem);
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--vein);
}

/* ---- one position ------------------------------------------------------
   ONE NUMBER DRIVES EVERYTHING. --rank is 0, 1 or 2 and every difference
   between first and third is calculated from it, so a change of position
   is a single transition across six properties at once. */
.bp {
  --rank: 0;
  --h: calc(84 - var(--rank) * 14);
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-width: 0;
  transition: opacity 1.05s var(--ease-out), transform 1.05s var(--ease-out);
}
.bp--1 { --rank: 0; }
.bp--2 { --rank: 1; }
.bp--3 { --rank: 2; }

/* the lit segment of the baseline belongs to whoever is first. The three
   segments cross-fade, so the light appears to move along the rule. */
.bp::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, transparent, rgba(242, 216, 168, 0.95), transparent);
  box-shadow: 0 0 20px 2px rgba(192, 156, 96, 0.55);
  opacity: 0;
  transition: opacity 1.05s var(--ease-out);
}
.bp.is-lead::after { opacity: 1; }

/* the position numeral, on a reel. Rolling is what makes the reorder
   legible without a line of type explaining it. */
.bp__pos {
  display: block;
  height: 1.06em;
  overflow: hidden;
  margin-bottom: 0.5rem;
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 0.85rem + 1.35vw, 2.25rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  opacity: calc(1 - var(--rank) * 0.26);
  transition: opacity 1.05s var(--ease-out);
}
/* EM, NEVER A PERCENTAGE. A percentage translate resolves against the
   element's OWN height, and the reel is three digits tall, so -100% rolled
   three positions at once and left the mask empty. Same trap as the
   homepage wall. */
.bp__reel {
  display: block;
  transform: translateY(calc(var(--rank) * -1.06em));
  transition: transform 1.05s var(--ease-out);
}
/* the metallic ramp is near-vertical on purpose: at a flatter angle a
   leading digit drops into the darkest stop and disappears */
.bp__reel i {
  display: block;
  height: 1.06em;
  line-height: 1.06;
  font-style: normal;
  background: linear-gradient(179deg, #fdf6e8 0%, #d8b981 42%, #9c7848 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.bp.is-lead .bp__reel i {
  background: linear-gradient(179deg, #ffffff 0%, #f0dcb4 38%, #c09c60 100%);
  -webkit-background-clip: text;
  background-clip: text;
}

.bp__frame {
  position: relative;
  height: calc(var(--h) * 1%);
  min-height: 0;
  overflow: hidden;
  border-radius: 3px;
  background: var(--obsidian);
  border: 1px solid rgba(156, 120, 72, calc(0.5 - var(--rank) * 0.13));
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.03) inset,
    0 26px 58px -30px rgba(0, 0, 0, 0.94);
  transition:
    height 1.05s var(--ease-out),
    border-color 1.05s var(--ease-out),
    box-shadow 1.05s var(--ease-out),
    opacity 1.05s var(--ease-out);
}
.bp.is-lead .bp__frame {
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.06) inset,
    0 26px 58px -30px rgba(0, 0, 0, 0.94),
    0 0 60px -12px rgba(176, 138, 84, 0.6);
}

.bp__shot { position: absolute; inset: -4% 0; }
.bp__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the fall from first to third is deliberately shallow. Prominence is
     carried by height, frame and glow; a dark third place is how this
     site keeps producing a section nobody can see. */
  filter:
    saturate(calc(0.94 - var(--rank) * 0.05))
    contrast(1.05)
    brightness(calc(1.04 - var(--rank) * 0.12));
  transition: filter 1.05s var(--ease-out);
}
.bp--1 .bp__shot img { object-position: 32% 52%; }
.bp--2 .bp__shot img { object-position: 56% 48%; }
.bp--3 .bp__shot img { object-position: 50% 38%; }

/* the corner the whole page is lit from, plus a floor vignette so a plate
   sits into the dark rather than on top of it */
.bp__grade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 70% at 62% 24%, rgba(192, 156, 96, calc(0.12 - var(--rank) * 0.03)), transparent 66%),
    linear-gradient(180deg, rgba(6, 6, 10, 0.32) 0%, transparent 24%, transparent 58%, rgba(6, 6, 10, 0.66) 100%);
}

/* ---- ambient light ----------------------------------------------------
   The wrapper clips, the inner band travels. GSAP owns both, and nothing
   in CSS transitions either, so a tween and a transition never fight. */
.board__sheen {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 3;
}
.board__sheen i {
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -40%;
  width: 34%;
  opacity: 0;
  background: linear-gradient(104deg, transparent 0%, rgba(226, 190, 126, 0.16) 48%, transparent 100%);
  filter: blur(6px);
}

/* ---- entrance ---------------------------------------------------------
   Every plate opens at LAST PLACE and the standing sorts itself out as
   the curtain lifts. The from-state only exists while `is-loading` is on
   the document, so no-JS and reduced motion render a finished board. */
.is-loading .bp {
  --rank: 2;
  opacity: 0;
  transform: translateY(26px);
}
.is-loading .bp--2 { transition-delay: 0.08s; }
.is-loading .bp--3 { transition-delay: 0.16s; }
.is-loading .bp::after { opacity: 0; }

.board__head,
.board__base,
.board__tell {
  transition: opacity 0.95s var(--ease-out), transform 0.95s var(--ease-out);
}
.board__base { transition-delay: 0.12s; }
.board__tell { transition-delay: 0.42s; }
.is-loading .board__head { opacity: 0; transform: translateY(10px); }
.is-loading .board__base { opacity: 0; }
.is-loading .board__tell { opacity: 0; transform: translateY(10px); }

/* the headline is two sentences and it must stay on two lines. Widen the
   column before ever reaching for a smaller type size. */
@media (min-width: 981px) and (max-width: 1180px) {
  .board__body {
    grid-template-columns: minmax(0, 1.16fr) minmax(0, 0.84fr);
    gap: clamp(1.75rem, 1rem + 2.4vw, 3rem);
  }
  .board__claim { max-width: none; }
  /* the board loses width here, so it loses height with it, or the plates
     turn into three slivers */
  .board__stand { --stand-h: clamp(15rem, 6rem + 20vw, 21rem); }
}

@media (max-width: 980px) {
  .hero--board { min-height: 0; }
  .board__body {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(2rem, 1.6rem + 2.2vw, 3rem);
  }
  .board__claim { max-width: 42rem; }
  .board .hero__sub,
  .board__note { max-width: 42rem; }
  .board__stand { --stand-h: clamp(13rem, 6rem + 26vw, 19rem); }
}

@media (max-width: 560px) {
  .board__stand { --stand-h: 15rem; }
  .bp { --h: calc(86 - var(--rank) * 15); }
  .bp__pos { margin-bottom: 0.35rem; }
}

@media (prefers-reduced-motion: reduce) {
  .bp,
  .bp::after,
  .bp__pos,
  .bp__reel,
  .bp__frame,
  .bp__shot img,
  .board__head,
  .board__base,
  .board__tell { transition: none; }
}

/* ==========================================================================
   CAREERS - page rhythm and heading scale

   The same client pass what-we-do and team already had: a medium heading
   size and less air between the sections. Scoped to <main class="careers">
   so index / about / results / contact / the legal pages do not move.

   THE LADDER: hero h1 3rem > section h2 2.6rem > sub-headings unchanged.
   ========================================================================== */

.careers {
  --section: clamp(3.5rem, 2.5rem + 4vw, 5.75rem);
  --section-sm: clamp(2.75rem, 2rem + 3vw, 4.25rem);
}

.careers h2 {
  font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
}

/* ==========================================================================
   THE BAR — careers.html, section 01   (`.barx`)

   It replaced an `.ed ed--overlap` split whose image used `data-src`, so the
   clean pass hid it and the section rendered as a blank marble panel beside a
   paragraph. `.ed` stays: about and results still use it.

   THE COPY WAS THE REAL PROBLEM. This section restated the homepage almost
   word for word - "most people who apply do not get in", "barely for most
   people" and BOTH halves of the managed / measured fork are all on index.
   A prettier setting of sentences the reader has already read is worse than
   the plain version, because that repetition is exactly what reads as
   generated. The division now: index owns the FILTER and the FORK, this
   section owns "we are not for everyone" and the standard itself, section 03
   owns the published rungs.

   THE HEADLINE ANSWERS THE HERO. The board above says the order is not
   fixed; this says the bar does not move. People move, the standard does
   not, and the two sections argue together instead of repeating.

   NO PANEL, AND THAT IS DELIBERATE. Wrapping a section in a container is
   almost always the wrong move on this brand (the `.omit` lesson: a big card
   with dark boxes inside reads as a template). So the section's own ground IS
   the stone: a faint brushed grain, a warm floor, and the headline cut into
   it. There is no box anywhere in here.

   THE MECHANIC IS RAKING LIGHT, and that is what was still free. On this
   site `.wall` travels X, `.worlds` pushes Z, `.rise` climbs Y, `.lp` holds
   still, `.forge` turns, `.hire` strikes type through, `.cab` assembles,
   `.stop` opens a rule from the centre, `.cuts` register, `.latent` develops,
   `.lane` slides hairlines in, `.floor` spreads, `.clk` runs on a clock and
   the hero above reorders. Nothing anywhere is LIT FROM A MOVING SOURCE.
   Raking light is also the only way an engraving is ever read in the real
   world, so the mechanic and the subject are the same thing.

   `--rx` (0..1) is where the light is across the section. It drives the
   warm pool, the depth and direction of the engraved headline's shadows,
   the note's hairline and both plate rims, so one number relights the whole
   composition. It is an UNREGISTERED custom property on purpose: GSAP writes
   it every frame so it never needs to interpolate, and unregistered means it
   inherits to the children for free without the site-wide recalc cost a
   registered inherited property carries on a stylesheet that loads on nine
   pages.

   NEVER PUT A CSS TRANSITION ON ANYTHING DRIVEN BY --rx. GSAP owns it
   outright; the transitions in here are on `filter` for hover only.

   Photography is another explicit exception to the `.media img` clean pass,
   via its own `.barx__*` classes: car-dawn (the empty street before the
   first door) and training (the standard, up close under a lamp). Both are
   unused elsewhere on this page.
   ========================================================================== */

.barx {
  /* where the raking light is. GSAP owns it; this is the resting value. */
  --rx: 0.42;
  /* the distance from the container's content edge to the viewport edge, so
     the wide plate can run off the side of the page */
  --bleed: max(var(--gutter), calc((100vw - var(--container)) / 2));
  padding-block: clamp(2.16rem, 1.584rem + 2.16vw, 3.42rem);
  overflow-x: clip;
}

/* the moving source */
.barx__rake {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(36rem 22rem at calc(var(--rx) * 100%) 26%, rgba(192, 156, 96, 0.17), transparent 62%),
    radial-gradient(58rem 28rem at calc(var(--rx) * 100%) 94%, rgba(156, 120, 72, 0.075), transparent 66%);
}

/* the ground the headline is cut into. Brushed, not a surface with edges. */
.barx__floor {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.6;
  background:
    repeating-linear-gradient(101deg, rgba(255, 255, 255, 0.015) 0 2px, transparent 2px 8px),
    linear-gradient(180deg, transparent 0%, rgba(156, 120, 72, 0.035) 58%, transparent 100%);
}

.barx__inner {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr);
  grid-template-rows: auto auto;
  column-gap: clamp(1.75rem, 1.1rem + 2.6vw, 3.75rem);
  row-gap: clamp(1.25rem, 0.95rem + 1.4vw, 2rem);
  align-items: end;
}

.barx__cut {
  grid-column: 1;
  grid-row: 1;
  align-self: center;
}

/* ---- the engraving -----------------------------------------------------
   The letter fill NEVER changes: it stays --ink at about 16:1 whatever the
   light is doing. Only the two edges move, which is what makes it read as
   cut rather than as a text effect, and it is also why a moving light can
   never take the headline's contrast with it. */
.barx__h {
  --rxo: calc((var(--rx) - 0.5) * 2);   /* -1 at the left, +1 at the right */
  color: var(--ink);
  text-shadow:
    calc(var(--rxo) * -2.6px) -1.4px 2px rgba(0, 0, 0, 0.95),
    calc(var(--rxo) * 2.6px) 1.4px 0 rgba(226, 190, 126, 0.32),
    0 0 calc(16px + var(--rx) * 30px) rgba(156, 120, 72, 0.15);
}
/* the one metallic word. It drops the shadows: a text-shadow behind a
   background-clip:text fill paints straight through the transparent glyph. */
.barx__h em {
  font-style: italic;
  text-shadow: none;
  background: linear-gradient(179deg, #ffffff 0%, #f0dcb4 40%, #b08a54 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.barx__lead {
  margin-top: clamp(0.9rem, 0.8rem + 0.6vw, 1.35rem);
  max-width: 32rem;
  font-size: var(--text-lg);
  line-height: 1.7;
  color: var(--ink);
  text-wrap: pretty;
}

/* the honest gap. Its hairline is lit by the same source as the engraving. */
.barx__note {
  margin-top: clamp(0.9rem, 0.8rem + 0.6vw, 1.35rem);
  padding-top: clamp(0.75rem, 0.65rem + 0.45vw, 1.05rem);
  border-top: 1px solid rgba(156, 120, 72, calc(0.2 + var(--rx) * 0.3));
  max-width: 29rem;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--vein);
  text-wrap: pretty;
}

/* ---- the work ---------------------------------------------------------- */

.barx__plate {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--obsidian);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.03) inset,
    0 30px 64px -32px rgba(0, 0, 0, 0.94);
}

/* runs off the right edge of the page. The border and the radius go with it
   on that side, or the picture reads as a panel that happens to be wide. */
.barx__plate--wide {
  grid-column: 2;
  grid-row: 1 / span 2;
  /* it must fill the span, not sit at the bottom of it. With `align-items:
     end` on the grid a spanning item is pinned to the last row's baseline
     and leaves the whole top corner of the section empty. */
  align-self: stretch;
  height: 100%;
  width: calc(100% + var(--bleed));
  min-height: clamp(15rem, 10rem + 15vw, 23rem);
  border: 1px solid rgba(156, 120, 72, calc(0.14 + var(--rx) * 0.26));
  border-right: 0;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}

/* the near plate is smaller, pulled right and set OVER the wide one, so the
   two read as hand-laid at different depths rather than as a pair */
.barx__plate--near {
  grid-column: 1;
  grid-row: 2;
  z-index: 3;
  width: min(100%, 24rem);
  margin-left: auto;
  margin-right: clamp(-7rem, -7vw, -2.5rem);
  /* and it dips past the wide plate's bottom edge, so the pair reads as one
     print laid over another rather than as an inset panel */
  margin-bottom: clamp(-1.75rem, -1.4vw, -0.5rem);
  aspect-ratio: 16 / 10;
  border: 1px solid rgba(156, 120, 72, calc(0.4 - var(--rx) * 0.16));
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.05) inset,
    0 34px 70px -30px rgba(0, 0, 0, 0.96);
}

.barx__shot { position: absolute; inset: -5% 0; }
.barx__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 0.6s var(--ease-out);
}
.barx__plate--wide .barx__shot img {
  object-position: 46% 44%;
  filter: saturate(0.88) contrast(1.06) brightness(0.9);
}
.barx__plate--near .barx__shot img {
  object-position: 52% 54%;
  filter: saturate(0.94) contrast(1.04) brightness(1);
}
.barx__plate:hover .barx__shot img { filter: saturate(0.98) contrast(1.06) brightness(1.08); }

.barx__vig {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(110% 70% at 58% 26%, rgba(192, 156, 96, 0.1), transparent 66%),
    linear-gradient(180deg, rgba(6, 6, 10, 0.3) 0%, transparent 26%, transparent 58%, rgba(6, 6, 10, 0.62) 100%);
}

/* ---- narrow ------------------------------------------------------------
   The bleed and the overlap are DROPPED rather than re-tuned: two plates
   overlapping inside 400px of width is a pile, not a composition. */
@media (max-width: 900px) {
  .barx__inner {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
    row-gap: clamp(1.5rem, 1.2rem + 1.4vw, 2.25rem);
    align-items: stretch;
  }
  .barx__cut,
  .barx__plate--wide,
  .barx__plate--near {
    grid-column: 1;
    grid-row: auto;
  }
  .barx__plate--wide {
    width: calc(100% + var(--gutter));
    min-height: 0;
    aspect-ratio: 16 / 9;
  }
  .barx__plate--near {
    width: min(64%, 24rem);
    margin-left: 0;
    margin-right: 0;
    margin-bottom: 0;
    aspect-ratio: 16 / 10;
  }
  .barx__lead,
  .barx__note { max-width: 42rem; }
}

@media (max-width: 560px) {
  .barx__plate--wide { aspect-ratio: 16 / 10; }
  .barx__plate--near { width: 78%; }
}

@media (prefers-reduced-motion: reduce) {
  .barx__shot img { transition: none; }
}

/* ==========================================================================
   THE JOB — careers.html, section 02   (`.jobx`)

   It replaced a `.grid` col-5 / col-7 with a bulleted `.plain-list`, which is
   the shape a template produces. `.plain-list` is now unused on this page but
   STILL USED on about.html, so its CSS stays.

   THE SECTION IS SAID, NOT LISTED. The KB's note on this material is that
   nobody in this category will state the job plainly, and that stating it
   plainly wins the trust of every good applicant who is about to search for
   you. So the statements are SPOKEN: each one cuts in a word at a time, hard,
   with no fade and no easing. Everything else on this site eases; this is the
   only place that cuts, and a cut is the plainest transition there is.

   WHY NOT FOUR NUMBERED ROWS: section 03 directly below is four numbered
   rungs. Two numbered vertical fours in a row is the adjacent-section
   repetition that reads as generated, so this one has no numerals, no
   bullets and no rules between the statements, and it runs across the page
   rather than down it.

   THE MEASURES ARE HAND-SET AND UNEQUAL, and the last block FLIPS so the set
   never resolves into a zigzag: photograph left / statement right, then
   statement left / photograph right, then one wide statement across the
   left, then a hairline, then the payoff on the LEFT with its photograph on
   the right. Three different aspect ratios (16/9, 4/3, 5/4) so the plates
   never read as a set of three.

   THE HAIRLINE IS THE TURN. Three statements are what you give and the
   fourth is what you get, so the rule sits between them and the payoff is
   the only statement set larger.

   COLDER THAN ITS NEIGHBOURS ON PURPOSE. `.barx` above is a warm raking
   light and `.rungs` below is a lit ladder; this one is a flat neutral
   top-light with almost no gold in the ground. The temperature drop is what
   makes it feel like a different section rather than more of the same one.

   Photography is another explicit exception to the `.media img` clean pass,
   via `.jobx__*` classes: retail (the field, a door standing open on a
   business), team-walk (walking in to people who did not ask), signature
   (paid on what you close). All three are unused elsewhere on this page.
   ========================================================================== */

.jobx {
  --bleed: max(var(--gutter), calc((100vw - var(--container)) / 2));
  padding-block: clamp(2.16rem, 1.584rem + 2.16vw, 3.42rem);
  overflow-x: clip;
}

/* neutral, not gold. The cold section between two warm ones. */
.jobx__floor {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.022) 0%, transparent 34%),
    radial-gradient(52rem 26rem at 50% -8%, rgba(156, 120, 72, 0.05), transparent 64%);
}

.jobx > .container { position: relative; z-index: 2; }

.jobx__head { margin-bottom: clamp(1.75rem, 1.3rem + 2vw, 3rem); }

/* ---- the arrangement ---------------------------------------------------
   Twelve columns, every item placed by hand. Nothing here is auto-flowed,
   because auto-flow is what makes a set of things look like a set. */
.jobx__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(1rem, 0.6rem + 1.6vw, 2.25rem);
  row-gap: clamp(1.1rem, 0.9rem + 1vw, 1.85rem);
  align-items: center;
}

/* THE PHOTOGRAPHS SHARE ROWS WITH THE STATEMENTS RATHER THAN STACKING
   BELOW THEM. Three plates on three rows of their own measured 1718px for
   this section; spanning them across the statements they belong to brings it
   under 1000 with the same three pictures at the same size. Height is the
   first thing to check whenever a section grows a third image. */
.jobx__plate--a { grid-column: 1 / 6;  grid-row: 1 / span 3; }
.jobx__plate--b { grid-column: 6 / 8;  grid-row: 1 / span 2; }
.jsay--1        { grid-column: 8 / 13; grid-row: 1; }
.jsay--2        { grid-column: 8 / 13; grid-row: 2; }
.jsay--3        { grid-column: 6 / 13; grid-row: 3; }
.jobx__turn     { grid-column: 1 / 13; grid-row: 4; }
/* the payoff and the terms hug the row boundary between them, or the tall
   plate beside them centres each in its own row and opens a void between
   two lines that belong together */
.jsay--4        { grid-column: 1 / 7;  grid-row: 5; align-self: end; }
.jobx__close    { grid-column: 1 / 7;  grid-row: 6; align-self: start; }
.jobx__plate--c { grid-column: 7 / 13; grid-row: 5 / span 2; }

/* ---- the statements ---------------------------------------------------- */

.jsay {
  margin: 0;
  /* the grid cells are hand-set and uneven, but the READING measure is not
     allowed to be: a statement that runs 95 characters wide is not plain */
  max-width: 40rem;
  font-size: clamp(1.12rem, 0.98rem + 0.68vw, 1.6rem);
  line-height: 1.45;
  letter-spacing: -0.008em;
  color: var(--ink);
  text-wrap: pretty;
}

/* the payoff. The only statement set larger, and the only one with gold in
   it, because it is the only one that is not a cost. */
.jsay--4 {
  font-size: clamp(1.35rem, 1.08rem + 1.3vw, 2.15rem);
  line-height: 1.28;
  letter-spacing: -0.018em;
}
.jsay--4 b { font-weight: inherit; color: var(--gold-light); }

/* three statements are what you give, the fourth is what you get */
.jobx__turn {
  height: 1px;
  background: linear-gradient(90deg,
    rgba(156, 120, 72, 0.45) 0%,
    rgba(156, 120, 72, 0.22) 58%,
    rgba(156, 120, 72, 0.04) 100%);
}

.jobx__close {
  margin: 0;
  max-width: 34rem;
  font-size: var(--text-base);
  line-height: 1.7;
  color: var(--vein);
  text-wrap: pretty;
}

/* the word unit the build cuts in. Inline on purpose: inline-block would
   change how the lines break and the copy has to set exactly as written. */
.jw { will-change: opacity; }

/* ---- the plates -------------------------------------------------------- */

.jobx__plate {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--obsidian);
  border: 1px solid rgba(156, 120, 72, 0.2);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.03) inset,
    0 28px 60px -32px rgba(0, 0, 0, 0.94);
}

/* runs off the LEFT edge of the page. `.barx` above bleeds right, so this
   one bleeds the other way and the two never read as the same layout. */
.jobx__plate--a {
  align-self: stretch;
  width: calc(100% + var(--bleed));
  margin-left: calc(-1 * var(--bleed));
  min-height: clamp(15rem, 10rem + 14vw, 21rem);
  border-left: 0;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
/* bottom-aligned and shorter, so its top edge sits well below A's and the
   two never read as one photograph split down the middle */
.jobx__plate--b { align-self: end; aspect-ratio: 4 / 5; }
.jobx__plate--c {
  align-self: stretch;
  min-height: clamp(12rem, 8rem + 11vw, 17rem);
}

.jobx__shot { position: absolute; inset: -4% 0; }
.jobx__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 0.6s var(--ease-out);
}
.jobx__plate--a .jobx__shot img { object-position: 54% 46%; filter: saturate(0.9) contrast(1.06) brightness(0.94); }
.jobx__plate--b .jobx__shot img { object-position: 50% 44%; filter: saturate(0.88) contrast(1.05) brightness(0.92); }
.jobx__plate--c .jobx__shot img { object-position: 52% 54%; filter: saturate(0.94) contrast(1.05) brightness(1); }
.jobx__plate:hover .jobx__shot img { filter: saturate(0.98) contrast(1.06) brightness(1.1); }

.jobx__vig {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(110% 70% at 54% 24%, rgba(192, 156, 96, 0.08), transparent 66%),
    linear-gradient(180deg, rgba(6, 6, 10, 0.28) 0%, transparent 26%, transparent 60%, rgba(6, 6, 10, 0.6) 100%);
}

/* ---- narrow ------------------------------------------------------------
   One column, source order, and the placement is dropped rather than
   re-tuned. The statements keep their order relative to the photographs,
   which is the only thing that has to survive. */
@media (max-width: 900px) {
  .jobx__grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(1.35rem, 1.1rem + 1.2vw, 2rem);
    align-items: stretch;
  }
  .jobx__plate--a,
  .jsay--1,
  .jsay--2,
  .jobx__plate--b,
  .jsay--3,
  .jobx__turn,
  .jsay--4,
  .jobx__close,
  .jobx__plate--c {
    grid-column: 1;
    grid-row: auto;
  }
  /* THREE STACKED PHOTOGRAPHS IS THE HEIGHT PROBLEM AT THIS WIDTH, not the
     copy: at 900 the section measured 2249px with the desktop aspects still
     applied. The plates keep their order and their differences and simply
     stop being full-height. */
  .jobx__plate--a { aspect-ratio: 21 / 9; min-height: 0; }
  .jobx__plate--b { width: 50%; margin-left: auto; aspect-ratio: 3 / 2; }
  .jobx__plate--c { width: 62%; aspect-ratio: 3 / 2; min-height: 0; }
  .jobx__close { max-width: 42rem; }
}

@media (max-width: 560px) {
  .jobx__plate--a { aspect-ratio: 16 / 9; }
  .jobx__plate--b { width: 64%; }
  .jobx__plate--c { width: 78%; }
}

@media (prefers-reduced-motion: reduce) {
  .jobx__shot img { transition: none; }
}

/* ==========================================================================
   THE PATH — "the widening view"   (careers.html, section 03)

   History: `.rungs` / `.rung`, four identical rows -> `.climb`, a rung list
   beside ONE frame that widened when you selected a rung -> this.

   THE REFRAME IS KEPT, AND IT IS STILL THE WHOLE SECTION: the ladder is
   SCOPE, not height. Height was unavailable twice over - index `.rise` is
   already a vertical ascent past numbered landings, and the hero on THIS
   page is objects at different heights on a shared baseline - but the
   approved copy never actually says higher. It says a portfolio, then an
   account, then a team, then a market. Each rung is a WIDER VIEW of the
   same job.

   WHAT CHANGED IS THAT ALL FOUR ARE ON THE PAGE AT ONCE. The selection
   version showed one photograph at a time behind an interaction, left the
   right third of the section as dead ground, and the four rungs beside it
   were still a four-row list - the exact shape the version before it had
   been rebuilt out of. Nothing here is hidden and nothing has to be
   touched: four rungs, four photographs, four bars, all readable at rest.

   EACH RUNG IS A BAND OF PHOTOGRAPHY INSIDE A FULL-WIDTH HAIRLINE GHOST.
   The band fills 40, 60, 80 and 100 per cent of its ghost, so the ground
   you have not reached is visible on every rung and closes only at the
   last one. That device survived the rebuild because it fixes a
   compositional hole AND states the argument, which is always worth more
   than one that only fills space.

   AND THEY ALL START THE SAME WIDTH. `--sc` runs 0 -> 1 and every band is
   interpolated from the FIRST rung's width to its own, so the section
   opens as four equal bands and resolves into the ladder. Everybody starts
   with the same scope; the rest is earned. Nothing else on this page moves
   that way - 01 rakes light across stone, 02 cuts type in word by word, 04
   backlights an opening, 05 breathes, 06 closes a brace, 07 is a two-rail
   diagram.

   THE HEIGHTS FALL AS THE WIDTHS GROW, which is what stops four stacked
   bands reading as a bar chart: the view is not getting bigger, it is
   getting WIDER and flatter, the way a view does.

   `--sc` is UNREGISTERED: GSAP writes it every frame so nothing needs
   interpolating, and a registered INHERITED property costs a recalc on all
   nine pages that load this file. Its CSS value is 1, THE FINISHED LADDER,
   so no JS, a dead CDN and reduced motion all render it widened.
   ========================================================================== */

.scp { position: relative; overflow-x: clip; }

.scp__head {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  align-items: end;
  column-gap: clamp(1.5rem, 4vw, 4rem);
  margin-bottom: clamp(2rem, 1.5rem + 2.2vw, 3.4rem);
}
.scp__h {
  margin: 0.55rem 0 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--white);
}
/* the closing note used to sit alone under the ladder with 200px of dead
   ground round it; as the head's second column it fills the row and reads
   as the promise the ladder is made against */
.scp__lead {
  margin: 0;
  max-width: 30rem;
  color: var(--vein);
  font-size: var(--text-base);
  line-height: 1.68;
}

/* ---- the ladder ---- */
.scp__ladder {
  --sc: 1;    /* 0 four equal bands, 1 the earned ladder. GSAP owns it. */
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(0.85rem, 0.6rem + 1vw, 1.4rem);
}

.scp__row {
  position: relative;
  /* every band grows from the FIRST rung's reach to its own */
  --live: calc(40 + (var(--w) - 40) * var(--sc));
  height: var(--bh);
}
.scp__row--1 { --bh: clamp(11rem, 7.6rem + 8vw, 20rem); }
.scp__row--2 { --bh: clamp(10.5rem, 7.6rem + 6.4vw, 15rem); }
.scp__row--3 { --bh: clamp(10rem, 7.2rem + 6vw, 14rem); }
.scp__row--4 { --bh: clamp(9.75rem, 7.2rem + 5.8vw, 15.5rem); }

/* the ground you have not reached. A hairline, never a fill: the point is
   that it is empty. */
.scp__ghost {
  position: absolute;
  inset: 0;
  pointer-events: none;
  border: 1px solid rgba(156, 120, 72, 0.16);
  border-radius: 2px;
}
.scp__ghost::after {
  /* a short tick at the far end, so the extent reads as a measurement
     rather than as an empty box */
  content: "";
  position: absolute;
  top: 50%;
  right: -1px;
  width: 1px;
  height: 34%;
  transform: translateY(-50%);
  background: linear-gradient(180deg, transparent, rgba(192, 156, 96, 0.5), transparent);
}

.scp__band {
  --bmx: 50;
  --bmy: 50;
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--live) * 1%);
  overflow: hidden;
  border-radius: 2px;
  background: var(--obsidian-raised);
  /* the light on this page comes from the upper left */
  box-shadow:
    inset 1px 1px 0 rgba(192, 156, 96, 0.3),
    inset -1px -1px 0 rgba(0, 0, 0, 0.66);
}

.scp__shot { position: absolute; inset: 0; overflow: hidden; }
.scp__shot img {
  position: absolute;
  inset: -5%;
  width: 110%;
  height: 110%;
  /* main.css carries a global img { max-width: 100% } that silently clamps
     any deliberately oversized image */
  max-width: none;
  display: block;
  object-fit: cover;
  /* GSAP owns --bdx and nothing else here, so filter is free to carry a
     CSS transition for the hover states without ever sharing a property */
  filter: brightness(0.78) saturate(0.9);
  transition: filter 0.55s var(--ease-out);
  transform: translate3d(calc(var(--bdx, 0) * 1px), 0, 0);
}
/* each frame is anchored by hand: the band re-crops as it widens, so the
   subject has to be told where to stay */
.scp__row--1 .scp__shot img { object-position: 50% 34%; }
.scp__row--2 .scp__shot img { object-position: 52% 48%; }
.scp__row--3 .scp__shot img { object-position: 54% 40%; }
.scp__row--4 .scp__shot img { object-position: 50% 52%; filter: brightness(0.94) saturate(1) contrast(1.04); }

/* legibility: a fall from the left, where every lockup sits */
.scp__veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(96deg, rgba(6, 6, 8, 0.9) 0%, rgba(6, 6, 8, 0.66) 34%, rgba(6, 6, 8, 0.12) 64%, rgba(6, 6, 8, 0.34) 100%);
}

.scp__glow {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  transition: opacity 0.5s var(--ease-out);
  background: radial-gradient(38% 62% at calc(var(--bmx) * 1%) calc(var(--bmy) * 1%),
    rgba(255, 240, 212, 0.18), transparent 72%);
}

/* THE NUMERAL JOINS THE LOCKUP. The first cut put it at a different corner
   on each band for variety, and on the flat bands it landed straight on the
   scope label and on the bar line. A ladder's rungs should be numbered the
   same way; the variation here is the widths, the heights and the pictures. */
.scp__num {
  display: block;
  margin-bottom: 0.3rem;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.8rem, 1.35rem + 1.3vw, 2.7rem);
  line-height: 0.9;
  letter-spacing: -0.02em;
  background: linear-gradient(166deg, rgba(246, 242, 234, 0.92), rgba(198, 160, 102, 0.82) 46%, rgba(128, 96, 56, 0.52));
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.85));
}

.scp__body {
  position: absolute;
  z-index: 3;
  left: clamp(1.1rem, 0.85rem + 1.4vw, 2.3rem);
  bottom: clamp(1rem, 0.8rem + 1.2vw, 1.9rem);
  width: min(calc(100% - 4rem), 27rem);
}
.scp__name {
  margin: 0 0 0.4rem;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.2rem, 1rem + 0.72vw, 1.62rem);
  line-height: 1.14;
  letter-spacing: -0.014em;
  color: var(--white);
}
.scp__note {
  margin: 0 0 0.5rem;
  color: var(--ink);
  font-size: var(--text-sm);
  line-height: 1.6;
}
.scp__bar {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-light);
}

/* the reach sits at the band's own right edge, so it travels outward with
   the rung rather than being parked at the page margin */
/* THE REACH SITS PAST THE BAND'S END, in the ground that rung has not
   taken. Inside the band there is no corner it can hold on the narrow
   rungs without landing on the lockup, and out here it reads as the
   end-cap of a measurement, which is what it is. */
.scp__reach {
  position: absolute;
  z-index: 3;
  left: calc(var(--live) * 1% + clamp(1rem, 2vw, 1.9rem));
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 0.88rem + 0.3vw, 1.2rem);
  color: var(--ink);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8);
}
.scp__reach span {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-shadow);
  margin-bottom: 0.15rem;
}

/* the last rung fills its ghost, so its own label has nowhere outside to
   go and takes the head of the band instead */
.scp__row--4 .scp__reach {
  left: auto;
  right: clamp(1rem, 2vw, 1.9rem);
  top: clamp(0.9rem, 1.8vw, 1.5rem);
  transform: none;
  text-align: right;
}

@media (hover: hover) and (pointer: fine) {
  .scp__band:hover .scp__glow { opacity: 1; }
  .scp__ladder:has(.scp__band:hover) .scp__band:not(:hover) .scp__shot img { filter: brightness(0.5) saturate(0.68); }
  .scp__band:hover .scp__shot img { filter: brightness(1.02) saturate(1.06); }
}

/* ---- the copy needs more room as the measure narrows, so the bands get
   taller in steps rather than in one jump ---- */
@media (max-width: 1180px) {
  .scp__row--2 { --bh: clamp(9rem, 6.6rem + 5.6vw, 13.5rem); }
  .scp__row--3 { --bh: clamp(8.5rem, 6.2rem + 5vw, 12.5rem); }
}
@media (max-width: 1024px) {
  .scp__head { grid-template-columns: 1fr; row-gap: 1.1rem; align-items: start; }
  .scp__lead { max-width: 38rem; }
}

/* ---- 760 and below the ladder cannot be read as widths: at 380px of
   measure, 40 per cent is 152px and no photograph survives that. The reach
   becomes the ladder instead - every band runs full width and the SCOPE
   label carries the progression, with the heights still falling. ---- */
@media (max-width: 760px) {
  .scp__row { --live: 100; }
  .scp__ghost { border-color: rgba(156, 120, 72, 0.1); }
  .scp__row--1 { --bh: clamp(14.5rem, 10rem + 22vw, 17.5rem); }
  .scp__row--2 { --bh: clamp(14rem, 10rem + 20vw, 16.5rem); }
  .scp__row--3 { --bh: clamp(13.5rem, 9.5rem + 19vw, 16rem); }
  .scp__row--4 { --bh: clamp(14rem, 10rem + 20vw, 16.5rem); }
  .scp__body { width: min(calc(100% - 3rem), 24rem); }
  .scp__row--1 .scp__body { bottom: clamp(1rem, 0.8rem + 1.2vw, 1.9rem); top: auto; }
  .scp__reach,
  .scp__row--4 .scp__reach {
    left: auto;
    right: clamp(0.9rem, 2.4vw, 1.4rem);
    top: clamp(0.8rem, 2vw, 1.3rem);
    transform: none;
    text-align: right;
  }
  .scp__num { font-size: clamp(1.9rem, 1.4rem + 3vw, 2.8rem); }
  .scp__row--1 .scp__num,
  .scp__row--4 .scp__num { left: auto; right: clamp(0.9rem, 2.4vw, 1.4rem); bottom: clamp(0.7rem, 1.8vw, 1.2rem); top: auto; }
  .scp__row--2 .scp__num,
  .scp__row--3 .scp__num { right: clamp(0.9rem, 2.4vw, 1.4rem); bottom: clamp(0.7rem, 1.8vw, 1.2rem); top: auto; }
  .scp__veil { background: linear-gradient(102deg, rgba(6, 6, 8, 0.92) 0%, rgba(6, 6, 8, 0.72) 40%, rgb(34 31 27 / 0.3) 78%, rgba(6, 6, 8, 0.5) 100%); }
}

@media (prefers-reduced-motion: reduce) {
  .scp__shot img,
  .scp__glow { transition: none; }
}

/* ==========================================================================
   THE APERTURE — careers.html, section 04   (`.trn`)

   It replaced an `.ed` split whose image used `data-src`, so the clean pass
   hid it and the section rendered as a blank marble panel beside a bulleted
   `.plain-list`. `.plain-list` is STILL USED on about.html, so its CSS stays.

   THE COPY WAS THE REAL PROBLEM, for the third time on this page. "A defined
   promotion track with a published bar" restated section 03 directly above,
   whose own headline is "Four rungs. A published bar for each."; the closing
   compensation line restated the FAQ below almost word for word. Both went
   back to the section that owns them. Grep the distinctive phrases first -
   a prettier setting of sentences the reader has already read is worse than
   the plain version, because that repetition is what reads as generated.

   THE MECHANIC IS BACKLIGHT, and it was what was still free. `.barx` in
   section 01 of this same page lights a stone surface from the SIDE and cuts
   its headline INTO it; everything else on the site lights a surface from
   the front. Nothing anywhere is lit from BEHIND, through an opening. So the
   ground here is one photograph with the light off, and the word is an
   opening in it.

   THE REGISTER IS THE WHOLE TRICK, and it is what stops this being the
   common image-filled-text effect. `.trn__ground` and `.trn__h` are the same
   element box (both `inset: 0` of the stage), carry the SAME background
   image at the SAME `cover` size and the SAME position - declared in one
   shared rule so they cannot drift - and only the grade differs. The glyphs
   therefore show exactly the pixels that sit behind them, undimmed. It does
   not read as a picture poured into letters, it reads as light coming
   through a wall. Same family as the `.cuts` continuity math on results.

   FOUR LAYERS, ONE BOX: ground (the room, dark) / scrim / glow (a blurred
   copy of the word, so the light that comes through lands on the dark around
   each letter) / the opening / gleam (a specular travelling across it).

   THE TWO DECORATIVE COPIES OF THE WORD ARE PSEUDO-ELEMENT CONTENT, never
   text nodes: `content: attr(data-w)` keeps them out of the DOM and out of
   the accessibility tree entirely, so the h2 is announced exactly once and
   the low-opacity-text check in the verification sweep has nothing to catch.

   ONLY THE GRADIENT POSITION MOVES on the gleam. Translating the layer would
   slide the light off the glyphs instead of across them - the `.cover`
   lesson, and the reason `--gl` feeds `background-position`.

   `--thru` (0..1, the backlight), `--pan` (px the world drifts behind the
   stencil) and `--gl` (the specular) are all UNREGISTERED on purpose: GSAP
   writes them every frame so they never need to interpolate, and unregistered
   means they inherit to the children for free without the site-wide recalc
   cost a registered inherited property carries on a stylesheet that loads on
   nine pages (the `.clk` lesson). The values declared here ARE the finished
   state, so no-GSAP / no-CDN / reduced-motion render the section fully lit.

   NEVER PUT A CSS TRANSITION ON ANYTHING DRIVEN BY --thru / --pan / --gl.
   GSAP owns them outright; the transitions in here are on `filter`, for hover.

   Photography is another explicit exception to the `.media img` clean pass,
   via its own `.trn__*` classes: office-dawn (the building before the day
   starts; the only thing the room is asked to say is that nobody is in it)
   and tower (a block you have not worked yet). Those were the ONLY two
   frames in the library still unused on careers.html - this section is
   asset-limited, not design-limited.
   ========================================================================== */

.trn {
  /* the backlight. GSAP owns it; this is the finished state. */
  --thru: 1;
  /* px the world drifts behind the stencil. Read by BOTH layers. */
  --pan: 0;
  /* where the specular sits across the letters, in % */
  --gl: 150;
  position: relative;
  overflow-x: clip;
}

.trn > .container { position: relative; z-index: 2; }

/* ---- the stage --------------------------------------------------------
   Full bleed, and deliberately NOT a panel: it sits outside the container as
   a direct child of the section, and the scrim feathers it to obsidian at
   the top and bottom edges so it dissolves into the page instead of ending.
   Wrapping a section in a box is almost always the wrong move on this brand
   (the `.omit` lesson). */
.trn__stage {
  position: relative;
  width: 100%;
  height: clamp(15rem, 6rem + 27vw, 26rem);
  margin-block: clamp(1.5rem, 1.1rem + 1.8vw, 2.75rem);
  overflow: hidden;
  isolation: isolate;
}

/* the four layers share ONE box and ONE typographic setting, which is what
   keeps the blurred copy, the opening and the specular in exact register.

   EVERY LAYER RULE IS PREFIXED `.trn `, AND THAT IS NOT COSMETIC. The page
   block above carries `.careers h2` (0,1,1), which OUT-SPECIFIES a bare
   `.trn__h` (0,1,0): the opening rendered at the page's 41.6px heading size
   while the two decorative spans, untouched by an h2 selector, sat at the
   full 168px. Measured 42px against 168px - three layers of the same word at
   two different sizes, so the spill and the specular were nowhere near the
   glyphs they belong to. Same family as the nav backdrop-filter trap: check
   what else in this stylesheet can reach the element before trusting a
   single-class selector. */
.trn .trn__ground,
.trn .trn__glow,
.trn .trn__h,
.trn .trn__gleam {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  /* THE WORD IS SET LEFT, TO THE CONTAINER'S EDGE, AND THAT IS A LEGIBILITY
     FIX BEFORE IT IS A COMPOSITIONAL ONE. Centred, the second half of the
     word landed on the dark block at the right of the photograph and "s on"
     effectively disappeared - the cost of showing the true pixels is that
     the word can only be read where the picture is lit. Set left, the whole
     of it sits over the glass. Padding does not change the padding box, so
     `cover` and the background position are untouched and the register with
     the ground still cannot drift. */
  justify-content: flex-start;
  padding-inline-start: max(var(--gutter), calc((100% - var(--container)) / 2));
  font-family: var(--font-display);
  font-weight: 500;
  font-style: normal;
  font-size: clamp(3.1rem, 0.6rem + 12.6vw, 10.5rem);
  line-height: 1;
  letter-spacing: -0.022em;
  white-space: nowrap;
  text-transform: none;
}

/* ONE rule, both layers: identical image, identical cover geometry,
   identical position. This is the register, and it cannot drift. */
.trn .trn__ground,
.trn .trn__h {
  background-image: url("../assets/img/office-dawn.jpg");
  background-repeat: no-repeat;
  background-size: cover;
  background-position: calc(46% + var(--pan) * 1px) 40%;
}

/* the room with the light off. It is deliberately NOT crushed: this client's
   standing complaint is a section that reads as an empty screen, and a dark
   room still has to look like a room. */
.trn__ground {
  z-index: 0;
  filter: brightness(calc(0.3 + var(--thru) * 0.2)) saturate(0.66) contrast(1.04);
}

/* cool top light and a vignette, so the dark ground still reads as a room
   rather than as a black band, and so the band has no hard edges */
.trn__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg, var(--obsidian) 0%, rgb(34 31 27 / 0.22) 32%, rgb(34 31 27 / 0.3) 64%, var(--obsidian) 100%),
    radial-gradient(122% 96% at 34% 46%, transparent 30%, rgba(6, 6, 8, 0.7) 100%);
}

/* the spill. A blurred copy of the word behind the opening, so the light
   coming through lands on the dark around each letter. */
.trn__glow {
  z-index: 2;
  pointer-events: none;
  color: rgba(238, 208, 152, 0.9);
  filter: blur(clamp(9px, 2.1vw, 24px));
  opacity: calc(0.08 + var(--thru) * 0.6);
}
.trn__glow::before { content: attr(data-w); }

/* THE OPENING.

   IT IS GRADED WARM, AND THAT IS A BRAND DECISION, NOT A PHOTOGRAPHIC ONE.
   Ungraded, the glass and the dawn sky put a large CYAN word on a page whose
   palette is antique gold on obsidian and never anything brighter or cooler,
   and `.jobx` two sections above is already the deliberately cold ground on
   this page. The grade costs nothing that matters: the register is about
   POSITION, not colour, so the letters still show exactly the pixels behind
   them, now as light rather than as a blue screen. */
.trn .trn__h {
  z-index: 3;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter:
    brightness(calc(0.72 + var(--thru) * 0.72))
    contrast(1.04) saturate(0.4) sepia(0.46) hue-rotate(-6deg);
}

/* the specular travelling beyond the wall */
.trn__gleam {
  z-index: 4;
  pointer-events: none;
  color: transparent;
  -webkit-background-clip: text;
  background-clip: text;
  background-image: linear-gradient(102deg,
    rgba(255, 244, 222, 0) 38%,
    rgba(255, 244, 222, 0.62) 50%,
    rgba(255, 244, 222, 0) 62%);
  background-repeat: no-repeat;
  background-size: 240% 100%;
  background-position: calc(var(--gl) * 1%) 0;
  mix-blend-mode: screen;
}
.trn__gleam::before { content: attr(data-w); }

/* ---- what you get -----------------------------------------------------
   Not a list, and no numerals or rules: section 03 directly above is four
   numbered rungs and section 07 below is a four-step timeline, so a third
   numbered set on one page is the repetition that reads as generated.
   The three are given DIFFERENT internal structures rather than different
   sizes of the same one (the `.seat` lesson): a bare display statement, a
   statement with a kicker above it and a dimmed trailing clause, and one
   bound to a photograph. */
.trn__body {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(1.5rem, 1rem + 2.4vw, 3.5rem);
  row-gap: clamp(1.1rem, 0.85rem + 1.2vw, 1.85rem);
  align-items: start;
}

.trn__lead {
  grid-column: 1 / 8;
  grid-row: 1;
  max-width: 36rem;
  color: var(--vein);
  font-size: clamp(0.98rem, 0.94rem + 0.2vw, 1.1rem);
  line-height: 1.62;
}

.trn__one {
  grid-column: 1 / 8;
  grid-row: 2;
  max-width: 32rem;
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 1.1rem + 1.3vw, 2rem);
  line-height: 1.22;
  letter-spacing: -0.01em;
}

/* indented, so the three do not stack into a left-hand column beside a
   picture - which is the `.ed` split this section replaced. The stagger is
   what fills the middle of the composition. */
.trn__two {
  grid-column: 3 / 9;
  grid-row: 3;
  max-width: 28rem;
  margin: 0;
  color: var(--ink);
  font-size: clamp(0.98rem, 0.94rem + 0.2vw, 1.08rem);
  line-height: 1.6;
}
.trn__q { color: var(--vein); }

.trn__k {
  display: block;
  margin-bottom: 0.6rem;
  color: var(--gold-light);
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* the third one is bound to its photograph, and the pair is lifted into the
   bottom of the stage so the two halves of the section interlock instead of
   sitting in stacked bands */
/* KEEP THE PLATE NARROW AND SHORT ENOUGH TO MATCH THE LEFT COLUMN. A grid
   item that spans rows distributes its excess height ACROSS those rows, so
   an over-tall picture on the right does not overflow, it silently pushes
   the three statements apart - which read as unexplained gaps rather than as
   air. At 4 columns and 3/4 it ran ~190px past the copy; at 3 columns the
   two sides finish together. */
.trn__three {
  grid-column: 10 / 13;
  grid-row: 1 / span 3;
  margin: 0;
  align-self: start;
}

.trn__plate {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border: 1px solid rgba(156, 120, 72, 0.26);
  background: var(--obsidian-raised);
}
.trn__shot { position: absolute; inset: -4% 0; }
.trn__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
  /* a dusk sky is inherently cool, and this page is gold on obsidian, so the
     blue is pulled back the same way the opening is */
  filter: saturate(0.7) sepia(0.16) contrast(1.04) brightness(1.12);
  transition: filter 0.5s ease;
}
.trn__plate:hover .trn__shot img { filter: saturate(1) contrast(1.06) brightness(1.1); }
.trn__vig {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, transparent 46%, rgba(6, 6, 8, 0.62) 100%),
    radial-gradient(120% 88% at 50% 34%, transparent 40%, rgba(6, 6, 8, 0.42) 100%);
}

.trn__three figcaption {
  margin-top: clamp(0.85rem, 0.7rem + 0.6vw, 1.2rem);
  color: var(--ink);
  font-size: clamp(0.96rem, 0.92rem + 0.2vw, 1.05rem);
  line-height: 1.55;
}

/* lift the pair into the stage only where there is room for it: below this
   width the plate would land on the word */
@media (min-width: 1120px) {
  .trn__three { margin-top: calc(-1 * clamp(4rem, 1rem + 7vw, 8.5rem)); }
}

@media (max-width: 900px) {
  /* rows follow DOM order, so what a screen reader hears and what a phone
     shows are the same sequence */
  .trn__lead  { grid-column: 1 / 13; grid-row: 1; }
  .trn__one   { grid-column: 1 / 13; grid-row: 2; }
  .trn__two   { grid-column: 1 / 13; grid-row: 3; }
  .trn__three { grid-column: 1 / 13; grid-row: 4; margin-top: 0; }

  /* THE CROP HAS TO CHANGE, NOT JUST THE POSITION. On a wide stage `cover`
     crops the photograph to a band and the lit glass is most of it; on a
     phone the stage is close to the image's own aspect, so `cover` shows
     nearly the whole frame and the word lands squarely on the dark floor in
     the middle of it - measured invisible at 390. Sizing off the HEIGHT
     instead pushes in on the lit band, and both layers read the same rule so
     the register is untouched. */
  .trn .trn__ground,
  .trn .trn__h {
    background-size: auto 280%;
    background-position: calc(30% + var(--pan) * 1px) 24%;
  }
  .trn__plate { aspect-ratio: 16 / 10; }
  .trn__shot img { object-position: 50% 56%; }
}

@media (max-width: 560px) {
  .trn__stage { height: clamp(12rem, 8rem + 26vw, 16rem); }
  .trn__plate { aspect-ratio: 3 / 2; }
}

@media (prefers-reduced-motion: reduce) {
  .trn__shot img { transition: none; }
  /* `.trn ` prefix REQUIRED, and this is the second time the same trap bit in
     this one block: the shared layer rule is `.trn .trn__gleam` (0,2,0), so a
     bare `.trn__gleam` (0,1,0) here never won and the specular stayed on -
     frozen mid-sweep, since motion.js returns before it can drive `--gl`.
     Measured display:flex when it should have been none. Whenever a base rule
     is written at a raised specificity, every override of it has to match. */
  .trn .trn__gleam { display: none; }
}

/* ==========================================================================
   HELD OPEN — careers.html, section 05   (`.hld`)

   It replaced three identical `.tcard` placeholders, all reading "Story
   pending" - a three-across grid of the same card, saying nothing three
   times, which is the shape a template produces. careers.html was the LAST
   user of `.tcard` site-wide so that block is DELETED. `.shead` stays:
   about.html and index.html still use it.

   THE SECTION HAS NO CONTENT AND THAT IS THE CONTENT. Nobody has a
   publishable promotion story yet. The three honest options were to invent
   one (forbidden), drop the section (loses "We will not fake them", which is
   the differentiator), or show the SENTENCE THAT WILL BE PUBLISHED with the
   two things we do not have left as blanks. The third is the only one that
   turns the gap into an argument.

   THE ONLY LIGHT IN THIS SECTION COMES FROM THE TWO EMPTY PLACES. The ground
   is deliberately unlit and cool - no warm pool, because `.barx` owns that on
   this page - so the blanks are the section's light source and the missing
   thing is the thing the eye goes to. That is the whole lighting design and
   it is also the argument.

   THE MECHANIC IS WAITING, and it was still free. Every other section on this
   site RESOLVES - `.wall` travels X, `.worlds` pushes Z, `.rise` climbs Y,
   `.lp` separates planes, `.forge` turns, `.hire` strikes through, `.cab`
   assembles, `.stop` opens a rule, `.cuts` register, `.latent` develops,
   `.lane` slides in, `.floor` spreads, `.clk` runs, `.tally` counts, the
   careers hero reorders, `.barx` rakes, `.jobx` cuts, `.climb` widens and
   `.trn` lights from behind. This one arrives and then does not finish: the
   two blanks hold a slow breath that never fills. Nothing else on the site
   is unresolved on purpose.

   THE TWO BREATHS ARE OUT OF PHASE (motion.js delays the second by half a
   cycle). In phase they pulse together and read as a LOADING INDICATOR, which
   is a UI idiom and says "wait a moment"; out of phase they read as two
   separate places being kept, which says "wait for something real". Same
   number of lines of code, completely different meaning.

   IT IS THE ONLY CENTRED COMPOSITION ON THIS PAGE and the only one with no
   photograph. After four loud, asymmetric, image-led sections the page needs
   a breath, and a quiet section only works if its quietness is clearly a
   decision - hence the symmetry and the single light source, rather than just
   less of everything.

   `--hold` (0..1, how far the light has come up) and `--breath` (the pulse,
   written per slot) follow the site's two-number pattern - one scrubbed, one
   free-running - so a tween and a transition can never fight. Both are
   UNREGISTERED: GSAP writes them every frame, they inherit to the children
   for free, and there is no site-wide recalc cost. The declared values ARE
   the finished state, so no-GSAP / no-CDN / reduced-motion render the blanks
   lit and steady.
   ========================================================================== */

.hld {
  /* how far the light in the blanks has come up. GSAP owns it. */
  --hold: 1;
  position: relative;
  overflow-x: clip;
}

/* the unlit ground. Cool and still on purpose: `.barx` above is a warm
   raking light and `.trn` directly above is a lit photographic band, so the
   temperature drop is what makes this register as a different room. */
.hld__ground {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(232, 232, 246, 0.028) 0%, transparent 42%),
    radial-gradient(80% 60% at 50% 8%, rgba(180, 190, 220, 0.022), transparent 70%);
}

.hld > .container { position: relative; z-index: 1; }

/* THE WHOLE SECTION IS CENTRED, and it is the only one on this page that is.
   Left-aligned it left the entire right half of the head empty while the
   sentence sat centred below it, so the two halves read as unrelated blocks
   rather than as one composition. Symmetry also suits what this is: a place
   formally kept, closer to a dedication than to an article. Everything else
   on careers.html is asymmetric, so the change of axis is what gives a quiet
   section its own identity. */
.hld__head {
  max-width: 46rem;
  margin-inline: auto;
  text-align: center;
}

.hld__lead {
  margin-top: clamp(0.85rem, 0.7rem + 0.6vw, 1.25rem);
  max-width: 36rem;
  margin-inline: auto;
  color: var(--vein);
  font-size: clamp(0.98rem, 0.94rem + 0.2vw, 1.1rem);
  line-height: 1.62;
}

/* ---- the sentence ------------------------------------------------------
   Capped at the page's own h2 size. The client asked for a medium heading
   size across careers, so this earns its presence through light and air, not
   through scale - the blanks are what carry it. */
.hld__spec {
  position: relative;
  isolation: isolate;
  margin: clamp(3rem, 1.9rem + 5vw, 6.5rem) auto clamp(1.6rem, 1.2rem + 1.6vw, 2.5rem);
  /* WIDE ENOUGH TO HOLD ONE LINE AT FULL SIZE. At 46rem it wrapped after "on"
     and left the MONTH blank alone on line two with the full stop stranded
     beside it, which reads as a broken layout rather than as a held place.
     `balance` is the safety net for the widths where it does have to wrap. */
  max-width: 54rem;
  text-align: center;
  text-wrap: balance;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: clamp(1.45rem, 1rem + 2.1vw, 2.6rem);
  line-height: 1.5;
  letter-spacing: -0.012em;
}

/* a place kept. No fill of its own - only a hairline to write on, a faint
   rise of light to it, and the pool it throws. */
.hld__slot {
  --breath: 0.5;
  /* one number the whole blank is lit from */
  --lum: calc(var(--hold) * (0.38 + var(--breath) * 0.62));
  position: relative;
  display: inline-block;
  width: clamp(6.5rem, 3.6rem + 10.5vw, 11.5rem);
  height: 0.9em;
  margin-inline: 0.14em;
  vertical-align: -0.04em;
  border-bottom: 1px solid rgba(192, 156, 96, calc(0.26 + var(--lum) * 0.62));
}
/* the closing blank carries almost no right margin, or the full stop floats
   away from it and reads as a stray dot rather than as the end of a sentence */
.hld__slot--sm {
  width: clamp(5rem, 3rem + 7vw, 8.5rem);
  margin-inline-end: 0.02em;
}

/* the pool on the stone. This is the section's only light source, so it is
   allowed to be wide and soft. z-index -1 inside the isolated paragraph puts
   it behind the sentence but above the section ground. */
.hld__slot::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 46%;
  width: 330%;
  height: 760%;
  transform: translate(-50%, -50%);
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(50% 50% at 50% 50%, rgba(196, 158, 98, calc(var(--lum) * 0.3)), transparent 70%);
}

/* the light rising to the line */
.hld__slot::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg,
    transparent 12%,
    rgba(192, 156, 96, calc(var(--lum) * 0.08)) 72%,
    rgba(226, 190, 126, calc(var(--lum) * 0.17)) 100%);
}

/* what the blank is waiting for, named. Without this the reader has to be
   told what is missing; with it the section explains itself, which is the
   test this client's rejected devices kept failing. */
.hld__field {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-size: clamp(0.55rem, 0.48rem + 0.24vw, 0.72rem);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(226, 190, 126, calc(0.3 + var(--lum) * 0.45));
}

.hld__note {
  max-width: 34rem;
  margin-inline: auto;
  text-align: center;
  color: var(--vein);
  font-size: clamp(0.9rem, 0.87rem + 0.18vw, 1rem);
  line-height: 1.6;
}

@media (max-width: 620px) {
  /* the sentence breaks over more lines on a phone, so it needs the line to
     breathe or the blanks collide with the row above */
  .hld__spec { line-height: 1.62; }
  .hld__slot { width: clamp(6rem, 4rem + 14vw, 9rem); }
  .hld__slot--sm { width: clamp(4.6rem, 3rem + 10vw, 7rem); }
}

/* ==========================================================================
   THE SET — careers.html, section 06   (`.opn`)

   It replaced three `.position` rows - full-width flex rows with a border top
   and bottom, which is the default jobs-board shape - and careers.html was
   the only user of `.position`, so that CSS is DELETED from main.css.

   THE REAL FAULT WAS NOT VISUAL. The three roles were `<button>` elements
   with NO HANDLER ANYWHERE IN THE JAVASCRIPT: a candidate clicked a role and
   nothing happened, on the one section of the site whose whole job is to get
   them to apply. They are real links to the application now. Check that
   interactive-looking markup is actually wired before redesigning it.

   SECTION 06 AND 07 USED TO SHARE ONE `<section id="apply">` as a two-column
   grid. They are separate sections now so this one can have the full width;
   section 07's content is untouched, only re-housed. The id="apply" stays on
   THIS section - every page's footer links careers.html#apply and the hero
   CTA points at it.

   THE BRACE IS THE WHOLE IDEA. Section 07 directly below is a numbered
   four-step sequence, so a second vertical run of items on the same page had
   to be legibly a different KIND of thing. These are not steps and not a
   queue: they are simultaneous alternatives, all open at once, which is
   precisely what a brace means and precisely what "We hire year-round"
   means. A brace is also a typesetter's mark rather than a UI component, so
   it cannot read as a template, and it needs no caption to be understood -
   the test this client's rejected devices kept failing.

   THE BRACE CLOSES AROUND THE SET rather than opening outward. `--opn` runs
   0..1 and CSS computes `scaleY(1.42 -> 1)`, so it arrives loose and tightens
   to fit, which reads as gathering. Opening outward from a centre is
   `.stop`'s gesture on what-we-do and had to be avoided; this is the same
   axis doing the opposite thing.

   IT IS SCALED, NEVER DRAWN. A self-drawing stroke is `.rules` and `.argue`
   on results and what-we-do, and by this point on this site the question is
   not "should it move" but "which movement is still free". `vector-effect:
   non-scaling-stroke` keeps the 1.15px stroke even under both the
   `preserveAspectRatio="none"` stretch and the scaleY - note this is the SAFE
   use of that property; what breaks is combining it with `pathLength`
   normalisation, which is not used here.

   THE TRANSFORM IS COMPOSED IN CSS from a GSAP-written number (the `.clk`
   pattern) rather than tweened directly, so a tween and a CSS transition can
   never share a property. `--opn` is unregistered and its declared value is
   the finished state, so no-GSAP / no-CDN / reduced-motion render the brace
   closed and the roles in place.
   ========================================================================== */

.opn {
  /* how far the set has arrived. GSAP owns it; this is the finished state. */
  --opn: 1;
  position: relative;
  overflow-x: clip;
}

/* a cool, quiet ground. `.hld` above is lit only by its two blanks and
   `.barx` owns the warm pool, so this one is close to bare stone. */
.opn__floor {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(99deg, rgba(255, 255, 255, 0.012) 0 2px, transparent 2px 9px),
    linear-gradient(180deg, transparent 0%, rgba(156, 120, 72, 0.03) 54%, transparent 100%);
}

.opn > .container { position: relative; z-index: 1; }

/* h2 left, the qualifying line right, so the head fills the width instead of
   leaving half of it empty (the mistake `.hld` had to be rescued from) */
.opn__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.78fr);
  column-gap: clamp(1.5rem, 1rem + 2.6vw, 3.5rem);
  align-items: end;
}

.opn__lead {
  max-width: 25rem;
  color: var(--vein);
  font-size: clamp(0.95rem, 0.92rem + 0.2vw, 1.05rem);
  line-height: 1.6;
}

/* ---- the set ---------------------------------------------------------- */
.opn__set {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(1.1rem, 0.7rem + 1.9vw, 2.6rem);
  margin-top: clamp(2.25rem, 1.6rem + 2.8vw, 4rem);
  align-items: stretch;
}

.opn__brace {
  display: block;
  width: clamp(0.95rem, 0.65rem + 1.4vw, 1.95rem);
  color: var(--gold);
  /* loose, then tightening to fit */
  transform: scaleY(calc(1.42 - var(--opn) * 0.42));
  transform-origin: 50% 50%;
  opacity: calc(0.12 + var(--opn) * 0.88);
}
.opn__brace svg { display: block; width: 100%; height: 100%; }

/* CAPPED, AND THAT IS A TYPOGRAPHIC FIX. Run to the full 80rem container the
   rows put roughly 580px of nothing between each role and its own data three
   times over, which reads as a table that lost its middle column rather than
   as air. At 70rem the name and the data belong to each other again. */
.opn__list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 70rem;
}

.opn__role {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  column-gap: clamp(1rem, 0.6rem + 1.8vw, 2.4rem);
  padding-block: clamp(0.9rem, 0.62rem + 1.25vw, 1.65rem);
  color: inherit;
  text-decoration: none;
}

.opn__name {
  font-family: var(--font-display);
  font-size: clamp(1.22rem, 0.92rem + 1.55vw, 2.35rem);
  line-height: 1.2;
  letter-spacing: -0.012em;
  color: var(--ink);
  transition: transform 0.45s var(--ease-out), color 0.45s var(--ease-out);
}

.opn__meta {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6em;
  font-family: var(--font-sans);
  font-size: clamp(0.66rem, 0.6rem + 0.2vw, 0.78rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-light);
  white-space: nowrap;
}
.opn__sep { opacity: 0.45; }
.opn__terms { color: var(--vein); letter-spacing: 0.14em; }

.opn__arrow {
  width: clamp(0.95rem, 0.8rem + 0.5vw, 1.2rem);
  height: auto;
  color: var(--gold-light);
  opacity: 0.42;
  transform: translateX(-0.35rem);
  transition: transform 0.45s var(--ease-out), opacity 0.45s var(--ease-out);
}

/* the hairline between roles. Static, and only BETWEEN them - a rule that
   extends from one end is `.cab`'s gesture on what-we-do, and section 03 of
   this page already uses rule LENGTH to encode scope, so nothing here draws
   or measures. */
.opn__item + .opn__item { border-top: 1px solid rgba(156, 120, 72, 0.16); }

@media (hover: hover) {
  .opn__role:hover .opn__name,
  .opn__role:focus-visible .opn__name { transform: translateX(0.6rem); color: #fff; }
  .opn__role:hover .opn__arrow,
  .opn__role:focus-visible .opn__arrow { transform: translateX(0); opacity: 1; }
  /* the set dims around whichever one is being considered. On the list, never
     on a wrapper that also contains copy - the recurring contrast trap. */
  .opn__list:has(.opn__role:hover) .opn__item:not(:hover) { opacity: 0.46; }
  .opn__item { transition: opacity 0.4s var(--ease-out); }
}

@media (max-width: 860px) {
  .opn__head { grid-template-columns: minmax(0, 1fr); row-gap: 1rem; }
  .opn__lead { max-width: 34rem; }
  /* name over meta, arrow held at the right across both rows */
  .opn__role {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    row-gap: 0.5rem;
  }
  .opn__name { grid-column: 1; }
  .opn__meta { grid-column: 1; white-space: normal; }
  .opn__arrow { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
}

@media (max-width: 560px) {
  .opn__set { column-gap: 0.9rem; }
}

@media (prefers-reduced-motion: reduce) {
  .opn__name,
  .opn__arrow,
  .opn__item { transition: none; }
}

/* ==========================================================================
   BOTH WAYS — careers.html, section 07   (`.xch`)

   It replaced the `.tl` vertical timeline - a rule, a dot per row, an 01-04
   numeral, a heading and a line of copy. careers.html was the only user of
   `.tl` site-wide, so that block is DELETED from editorial.css.

   IT COULD NOT STAY A NUMBERED FOUR. Section 03 of this page is already four
   numbered rungs, and two numbered vertical fours on one page is exactly the
   adjacent repetition that reads as generated - it is the thing section 02
   was deliberately designed around. There are no numerals here at all; the
   `<ol>` is for semantics only.

   THE COPY NAMED THE SHAPE, which by now is the most reliable move on this
   site. "Straight talk, both ways" and "See the job before you take it. We
   see you before we offer it." say the process runs in TWO DIRECTIONS: the
   candidate is assessing Marble for exactly as long as Marble is assessing
   them. That is genuinely unusual for a careers page and the old timeline
   threw it away by setting it as a one-way list of stages. So it is drawn as
   a two-party diagram - your side, our side, the direction of each stage -
   and every sentence is the approved copy, unmoved.

   THE FOUR DIRECTION MARKS ARE ALL DIFFERENT: one way, both ways, two
   simultaneous passes, then a merge into a single node. That is what stops
   four rows reading as one component repeated four times (the `.seat`
   lesson: a different internal structure breaks a set, more size variation
   does not).

   THE GRAMMAR IS CONVERGENCE and nothing else on this site converges. The
   two rails start parallel and lean toward each other as you read down, so
   the diagram closes on the decision - `--conv` drives a rotation about each
   rail's top edge. Rotation, not width or position, so it costs no layout
   and cannot introduce overflow.

   IT IS THE MOST DELIBERATELY BUSINESSLIKE SECTION ON THE PAGE, per brief:
   sans-serif stage names (the site's existing convention for process
   headings), a real diagram rather than a metaphor, precise small-caps
   direction labels, and it resolves onto the Apply action instead of
   trailing off. Restraint here is the point - `.opn` directly above already
   carries the page's typographic set piece.

   `--conv` is unregistered, GSAP writes it every frame, and its declared
   value is the FINISHED state, so no-GSAP / no-CDN / reduced-motion render
   the rails already converged.
   ========================================================================== */

.xch {
  /* how far the two sides have come together. GSAP owns it. */
  --conv: 1;
  overflow-x: clip;
}

.xch__head { max-width: 46rem; }

.xch__lead {
  margin-top: clamp(0.8rem, 0.65rem + 0.6vw, 1.2rem);
  max-width: 34rem;
  color: var(--vein);
  font-size: clamp(0.98rem, 0.94rem + 0.2vw, 1.1rem);
  line-height: 1.62;
}

.xch__diagram {
  position: relative;
  margin-top: clamp(2.25rem, 1.6rem + 2.6vw, 3.75rem);
  padding-inline: clamp(1.1rem, 0.6rem + 2.4vw, 3.25rem);
}

/* the two sides. They lean together as you read down. */
/* A ROTATED 1px LINE ANTIALIASES ACROSS TWO SUBPIXELS AND LOSES ROUGHLY HALF
   ITS CONTRAST, so a rail that measures the same alpha as every other hairline
   on the site renders visibly fainter than one. These are brighter than a
   normal hairline on purpose. The lean is also 4deg rather than 3: below that
   the convergence stops reading as a gesture and starts reading as two
   slightly crooked lines, which looks like a rendering fault. */
.xch__rail {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  transform-origin: 50% 0;
  background: linear-gradient(180deg,
    rgba(192, 156, 96, 0.15) 0%,
    rgba(192, 156, 96, 0.72) 12%,
    rgba(192, 156, 96, 0.72) 74%,
    rgba(192, 156, 96, 0.28) 100%);
}
/* the tick that anchors each rail under its party name, so the pair reads as
   a frame rather than as two stray diagonals */
.xch__rail::before {
  content: "";
  position: absolute;
  top: 0;
  width: 0.7rem;
  height: 1px;
  background: rgba(192, 156, 96, 0.7);
}
.xch__rail--l { left: 0; transform: rotate(calc(var(--conv) * 4deg)); }
.xch__rail--l::before { left: 0; }
.xch__rail--r { right: 0; transform: rotate(calc(var(--conv) * -4deg)); }
.xch__rail--r::before { right: 0; }

.xch__parties {
  display: flex;
  justify-content: space-between;
  margin-bottom: clamp(1rem, 0.8rem + 0.9vw, 1.6rem);
  font-family: var(--font-sans);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold-light);
}

.xch__steps {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* name | direction | statement. The mark sits BETWEEN the two, which is
   where the exchange happens. */
.xch__step {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) auto minmax(0, 1.42fr);
  align-items: center;
  column-gap: clamp(1.1rem, 0.7rem + 2vw, 2.75rem);
  padding-block: clamp(1.1rem, 0.8rem + 1.4vw, 1.9rem);
}
.xch__step + .xch__step { border-top: 1px solid rgba(156, 120, 72, 0.15); }

/* THE ROWS TAPER WITH THE RAILS. The lean alone moves each rail about 45px
   over the diagram's height, which against a 1265px gap is too small a
   proportion to register on its own; the content narrowing in step with it is
   what makes the convergence legible as one movement rather than as a stray
   diagonal. Kept small - the copy measure has to stay comfortable. */
.xch__step:nth-child(2) { padding-inline: 1.4%; }
.xch__step:nth-child(3) { padding-inline: 2.8%; }
.xch__step:nth-child(4) { padding-inline: 4.2%; }

.xch__name {
  margin: 0;
  font-family: var(--font-sans);
  font-size: clamp(1.02rem, 0.94rem + 0.4vw, 1.3rem);
  font-weight: 600;
  line-height: 1.3;
  color: #fff;
}

.xch__mark {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  width: clamp(4.5rem, 3rem + 5.5vw, 7.5rem);
  color: var(--gold);
}
.xch__mark svg { display: block; width: 100%; height: auto; }

.xch__dir {
  font-family: var(--font-sans);
  font-size: 0.56rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-light);
  opacity: 0.72;
  white-space: nowrap;
}

.xch__copy {
  margin: 0;
  color: var(--vein);
  font-size: clamp(0.95rem, 0.92rem + 0.2vw, 1.05rem);
  line-height: 1.6;
}

/* the diagram resolves onto the action rather than trailing off */
.xch__end {
  display: flex;
  justify-content: center;
  margin-top: clamp(1.75rem, 1.3rem + 2vw, 3rem);
}

@media (max-width: 820px) {
  /* stacked: name, then the direction mark on its own line, then the
     statement. The rails and the party labels stay, because they are the
     argument, but the lean comes down with the width. */
  .xch__step {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1.25rem;
    row-gap: 0.6rem;
    align-items: start;
  }
  .xch__name { grid-column: 1; grid-row: 1; }
  .xch__mark { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .xch__copy { grid-column: 1; grid-row: 2; }
  .xch__rail--l { transform: rotate(calc(var(--conv) * 1.7deg)); }
  .xch__rail--r { transform: rotate(calc(var(--conv) * -1.7deg)); }
}

@media (max-width: 560px) {
  .xch__diagram { padding-inline: 0.85rem; }
  .xch__mark { width: 3.6rem; }
  /* the longest label ("At the same time") runs right up to the rail at this
     width, so it is allowed to break instead of being held on one line */
  .xch__dir {
    font-size: 0.5rem;
    letter-spacing: 0.14em;
    white-space: normal;
    text-align: center;
    line-height: 1.35;
  }
}

/* ==========================================================================
   ABOUT HERO — "the block"   (about.html)

   It replaced the shared `.hero--page`: eyebrow, headline, one line of sub, a
   5% mark watermark and a glow. `.hero--page` is untouched and still runs
   contact / privacy-policy / terms.

   THE HEADLINE IS THE ONLY PLACE THE STONE METAPHOR IS ALLOWED TO EXIST, and
   it was being set as flat type over a watermark. "Marble is not poured. It
   is carved." is the one line the knowledge base permits on the whole site,
   so if any hero anywhere should perform its own sentence it is this one.

   THE MECHANIC IS REMOVAL, and that is the reason it can sit on this site at
   all. Every other moment here ADDS or MOVES something: index travels x,
   pushes z, climbs y, turns an object and strikes type through; what-we-do
   swings doors and assembles a case; results registers a tear and develops a
   print; team slides lanes in and runs a clock; careers reorders a standing,
   rakes light, cuts words in and lights a word from behind. NOTHING ANYWHERE
   TAKES MATERIAL AWAY, and taking material away is the single thing carving
   is. The block arrives whole and is worked until two faces come up out of
   it. No caption explains that, because the headline already said it.

   ONE NUMBER DRIVES THE WHOLE CARVE. `--carve` runs 0 (uncut) to 1 (worked)
   and every one of the 24 pieces of crust computes its own window from it:
   `--s` is when that piece is struck and each piece takes 0.38 of the carve
   to leave. So a 24-part animation is one CSS transition, and it is CSS that
   owns it, keyed off the preloader's `is-loading` class exactly like the
   careers board. A hero cannot depend on a CDN: with GSAP absent, with the
   CDN blocked, with reduced motion or with no JavaScript at all, `--carve`
   sits at its registered initial value of 1 and the finished block renders.

   THE CRUST IS ONE SURFACE, NOT 24 TILES. Every `.bchip` is `inset: 0` of the
   stage with an identical background, and only its `clip-path` differs, so
   the rough skin is continuous until it breaks. Same register trick as the
   careers aperture. The vertex grid is jittered but SHARED between touching
   cells, so the pieces tile exactly; each polygon is then pushed 0.34pp out
   from its own centroid, which overlaps the seams by a fraction of a percent
   and kills the antialiasing hairlines that would otherwise let the picture
   show through before it is cut.

   `transform-origin` IS THE PIECE'S OWN CENTROID (`--ox` / `--oy`). Without
   it all 24 pieces turn about the stage centre and the crust reads as one
   sheet rotating off rather than as material coming away. Same family as the
   percentage-translate trap on the long wall and the careers reel.

   ORDER IS A CARVING ORDER, NOT A WIPE. Pieces leave in order of distance
   from the figure in the upper photograph, so the person emerges first and
   the rest of the scene opens around them, and the distance is jittered so it
   is never the clean radial ripple that would read as an effect.

   THE EVIDENCE STAYS. Four pieces do not vanish: they come to rest on the
   base rule at the foot of the block, dipped below it, unlit. What was taken
   off is still in the room. That is the detail that stops the carve reading
   as a reveal transition, and it is also the argument: this firm is defined
   by what it removed, not by what it added.

   PHOTOGRAPHY is an explicit exception to the `.media img` clean pass, via
   its own `.bface` classes: field-dusk (the approach, up a road at golden
   hour) and handshake (the close, hands over a counter). Both are anonymous,
   no face is claimed, and both are unused anywhere else on about.html. The
   two crops are deliberately unalike - one panoramic, one near-standard - so
   two photographs in one object never resolve into a set of two.
   ========================================================================== */

/* 0 uncut, 1 worked. Inherited so 24 pieces read it, and its INITIAL VALUE IS
   THE FINISHED STATE, so every degraded path renders a carved block. */
@property --carve { syntax: "<number>"; inherits: true; initial-value: 1; }

.hero--block {
  min-height: min(80svh, 44rem);
  padding-top: clamp(3.77rem, 3.19rem + 1.392vw, 4.64rem);
  padding-bottom: clamp(2rem, 1.6rem + 1.6vw, 3rem);
  justify-content: stretch;
}

.blk__wash {
  position: absolute;
  inset: -8% -4%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(34rem 26rem at 66% 8%, rgba(192, 156, 96, 0.16), transparent 66%),
    radial-gradient(28rem 22rem at 88% 84%, rgba(156, 120, 72, 0.10), transparent 68%),
    radial-gradient(38rem 24rem at 4% 92%, rgba(156, 120, 72, 0.07), transparent 62%);
}

.blk__inner {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.blk__body {
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  gap: clamp(2.5rem, 1.5rem + 3vw, 4rem);
  align-items: center;
}

/* ---- the claim ---------------------------------------------------------- */

.blk__claim { max-width: 40rem; }

.blk h1 {
  font-size: clamp(2.2rem, 1.45rem + 3.25vw, 3.9rem);
  line-height: 1.07;
  letter-spacing: -0.028em;
  margin-bottom: clamp(1rem, 0.85rem + 0.7vw, 1.5rem);
}
.blk h1 em {
  font-style: italic;
  color: var(--gold-light);
}

.blk .hero__sub {
  max-width: 30rem;
  margin-bottom: 0;
}

/* what kind of about page this is, said before the reader starts one. Set
   apart on a hairline rather than run on from the sub, because it is a
   different register: the sub introduces, this one sets terms. */
.blk__note {
  margin-top: clamp(1.05rem, 0.85rem + 0.9vw, 1.6rem);
  padding-left: clamp(0.9rem, 0.7rem + 0.8vw, 1.35rem);
  border-left: 1px solid rgba(156, 120, 72, 0.42);
  max-width: 27rem;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--ink);
  text-wrap: pretty;
}

.blk .hero__actions { margin-top: clamp(1.5rem, 1.2rem + 1.2vw, 2.25rem); }

/* ---- the block ---------------------------------------------------------- */

.blk__stage {
  /* the block runs off the right edge of the page, so the hero can never be
     read as two columns of a card. `.hero` already clips, so the bleed can
     not turn into a horizontal scrollbar. */
  --bleed: max(var(--gutter), calc((100vw - var(--container)) / 2));
  --blk-h: clamp(19rem, 12rem + 22vw, 30rem);
  --k: 1;                       /* how far a struck piece travels, scaled by width */
  position: relative;
  margin: -1.75rem 0 0;
  width: calc(100% + var(--bleed));
}

.blk__block {
  position: relative;
  height: var(--blk-h);
  isolation: isolate;
  /* THE CARVE, AND CSS OWNS IT. The from-state exists only while the curtain
     is up, so no-JS, no-CDN and reduced motion all render a finished block
     and nothing can be left half-cut. GSAP must never touch --carve: a tween
     and a transition sharing one property is the bug this site has shipped
     three times. */
  --carve: 1;
  transition: --carve 2.3s cubic-bezier(0.36, 0.02, 0.18, 1) 0.5s;
}
/* the delay lets the preloader curtain clear before the first piece is struck */
.is-loading .blk__block { --carve: 0; }

/* the worked stone underneath: polished, veined, warmer and lighter than the
   crust that was covering it. The difference between the two surfaces is what
   sells the carve - a reveal of the same material would read as a wipe. */
.blk__stone {
  position: absolute;
  inset: 0;
  z-index: 1;
  background-color: #16151d;
  background-image:
    /* fine polish grain. soft-light so it MODULATES the surface: a plain
       noise layer at a workable opacity is a grey wash over everything, which
       is what turned the first cut of this block into flat felt. */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='0.5'/%3E%3C/svg%3E"),
    /* the veins, sharp because this face has been worked */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='440'%3E%3Cdefs%3E%3Cfilter id='v'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013' numOctaves='4' seed='27' result='n'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='70'/%3E%3C/filter%3E%3C/defs%3E%3Cg filter='url(%23v)' fill='none' stroke='%23c09c60'%3E%3Cpath d='M-40 320 C 130 265 220 315 345 215 S 490 100 600 62' stroke-width='1.15' opacity='0.5'/%3E%3Cpath d='M-30 128 C 115 168 210 112 335 158 S 470 226 600 198' stroke-width='0.75' opacity='0.34'/%3E%3Cpath d='M60 450 C 190 356 290 388 385 278 S 500 172 600 156' stroke-width='0.6' opacity='0.26'/%3E%3Cpath d='M-40 232 C 90 214 150 246 250 228 S 400 176 600 128' stroke-width='0.45' opacity='0.2'/%3E%3C/g%3E%3Cg filter='url(%23v)' fill='none' stroke='%23b9bcc9'%3E%3Cpath d='M-40 392 C 120 344 230 372 330 300 S 470 214 600 236' stroke-width='0.5' opacity='0.16'/%3E%3C/g%3E%3C/svg%3E"),
    radial-gradient(58% 54% at 14% 4%, rgba(224, 196, 148, 0.18), transparent 68%),
    radial-gradient(52% 46% at 94% 96%, rgba(140, 108, 60, 0.15), transparent 70%),
    /* WORKED, NOT COLDER. The first cut separated the two surfaces by
       temperature and the polished ground came out violet against a warm
       crust, which is off-palette for a house whose only accent is antique
       gold. Polish is LIGHTER, SMOOTHER AND MORE SPECULAR at the same
       temperature; that is the honest difference and it is the on-brand one. */
    linear-gradient(150deg, #2e2a25 0%, #211e1e 44%, #17161a 76%, #1d1a1c 100%);
  background-size: 160px 160px, cover, cover, cover, cover;
  background-position: 0 0, center, center, center, center;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat, no-repeat;
  background-blend-mode: soft-light, normal, normal, normal, normal;
}

/* a broad specular across the polished ground, so it reads as a finished
   surface rather than as a dark panel */
.blk__stone::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(116deg, rgba(255, 255, 255, 0.055) 0%, transparent 32%, transparent 70%, rgba(192, 156, 96, 0.06) 100%);
}

/* the outer cut edge. It exists only once the block has been worked. */
.blk__cut {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  box-shadow:
    inset 0 0 0 1px rgba(156, 120, 72, 0.34),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  opacity: var(--carve);
}

/* ---- the two cut faces -------------------------------------------------- */

.bface {
  position: absolute;
  z-index: 2;
  overflow: hidden;
  /* cut INTO the stone: the recess casts a shadow off its top edge and the
     lip below it catches the light */
  box-shadow:
    inset 0 0 0 1px rgba(156, 120, 72, 0.4),
    inset 0 3px 12px -4px rgba(0, 0, 0, 0.95),
    0 1px 0 rgba(255, 255, 255, 0.055),
    0 12px 34px -22px rgba(0, 0, 0, 0.9);
  transition: box-shadow 1.2s var(--ease-out);
}

/* one panoramic, one near-standard: two photographs in one object must not
   resolve into a set of two */
.bface--a { left: 0;   top: 0;   width: 70%; height: 44%; }
.bface--b { left: 32%; top: 54%; width: 68%; height: 46%; }

/* HEADROOM IS LAYOUT, NOT A TRANSFORM. GSAP drifts these images on scroll and
   nudges them on the pointer, so the picture is laid out larger than its own
   opening and offset back into place with left/top. A base `scale()` would
   have put a static transform on the element GSAP is tweening, which is the
   thing that keeps going wrong here. */
.bface img {
  position: relative;
  left: -6%;
  top: -9%;
  width: 112%;
  height: 118%;
  object-fit: cover;
  filter: saturate(0.86) contrast(1.05) brightness(0.99);
}
.bface--a img { object-position: 36% 58%; }
.bface--b img { object-position: 52% 46%; }

/* the obsidian grade, kept off the photograph's own filter so the two can be
   tuned separately */
.bface::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(6, 6, 8, 0.34) 0%, transparent 38%, rgba(6, 6, 8, 0.42) 100%),
    radial-gradient(90% 70% at 88% 4%, rgba(192, 156, 96, 0.1), transparent 58%);
}

/* the edges catch once, as the last piece comes off */
.blk__stage.is-cut .bface {
  box-shadow:
    inset 0 0 0 1px rgba(192, 156, 96, 0.52),
    inset 0 3px 12px -4px rgba(0, 0, 0, 0.95),
    0 1px 0 rgba(255, 255, 255, 0.08),
    0 12px 34px -22px rgba(0, 0, 0, 0.9);
}

/* ---- what is cut into the stone ----------------------------------------- */

/* both inscriptions are debossed: on a worked block the only way type exists
   is cut in, and the site already reads engraved type as its own material */
.blk__mark,
.blk__idx {
  position: absolute;
  z-index: 3;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  line-height: 1.9;
  /* --gold-light, NOT --gold. These are real content rather than a decorative
     eyebrow, and they sit at 10.6px on lit stone: #9c7848 measures about
     3.8:1 there, under AA, while #c09c60 clears it. Small type is where the
     house gold stops being safe. */
  color: var(--gold-light);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 -1px 1px rgba(0, 0, 0, 0.85);
  opacity: var(--carve);
}

/* the maker's mark, on the panel of the block that was never worked */
.blk__mark {
  left: 73.5%;
  top: 11%;
  padding-top: 0.8rem;
  border-top: 1px solid rgba(156, 120, 72, 0.36);
  padding-right: 1rem;
}
.blk__mark b {
  display: block;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.22em;
}

/* the two faces, named where the reader meets each one */
.blk__idx {
  left: 0;
  padding-left: 2.1rem;
  color: var(--ink);
  white-space: nowrap;
}
.blk__idx::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.9em;
  width: 1.55rem;
  height: 1px;
  background: linear-gradient(90deg, rgba(156, 120, 72, 0.75), rgba(156, 120, 72, 0.2));
}
.blk__idx--a { top: 45.6%; }
.blk__idx--b { top: 60%; }

/* ---- the crust ---------------------------------------------------------- */

.blk__crust {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}
/* once the block is worked there is nothing left to paint */
.blk__stage.is-cut .blk__crust { display: none; }

.bchip {
  /* This piece is struck at --s and takes 0.38 of the carve to leave. The
     multiplier is 1/0.38 rounded UP: at exactly 2.63 the last piece finishes
     at --t 0.9994 and sits at opacity 0.0006 forever, which is invisible but
     is still a painted layer and still shows up as a not-quite-clear element
     in a verification sweep. Round a window multiplier up, never down. */
  --t: clamp(0, calc((var(--carve) - var(--s)) * 2.7), 1);
  position: absolute;
  inset: 0;
  clip-path: var(--p);
  transform-origin: var(--ox) var(--oy);
  transform:
    translate3d(calc(var(--dx) * var(--t) * var(--k) * 1px), calc(var(--dy) * var(--t) * var(--k) * 1px), 0)
    rotate(calc(var(--rot) * var(--t) * 1deg));
  opacity: calc(1 - var(--t));
  /* THE ROUGH SKIN, AND IT HAS TO BE A HANDSOME OBJECT ON ITS OWN. For the
     first half second this block is the whole hero, and a featureless
     rectangle is the empty screen this client has objected to four times.
     So the uncut stone gets real form: a warm quarried body lit from the top
     left, irregular mottling, its own unpolished veining, and lit and shadowed
     edges that make it read as a solid rather than as a filled shape.

     TWO THINGS FROM THE FIRST CUT, BOTH WORTH REMEMBERING. A plain noise
     layer at a workable opacity is a flat GREY WASH over every other layer -
     it must be blended (`soft-light`), not stacked. And a
     `repeating-linear-gradient` of fine stripes is a TEXTILE WEAVE, not tool
     marks: any regular period at all reads as woven cloth at this scale.
     Stone has to be mottled irregularly or it is not stone. */
  background-color: #17140f;
  background-image:
    /* edges: a lit top and left, a shadowed bottom and right. Every chip is
       inset:0 of the stage, so these land on the BLOCK's edges and each piece
       carries away whatever part of them it was covering. */
    linear-gradient(180deg, rgba(255, 240, 214, 0.14) 0 1px, transparent 1px 3px, transparent 100%),
    linear-gradient(90deg, rgba(255, 240, 214, 0.09) 0 1px, transparent 1px),
    linear-gradient(0deg, rgba(0, 0, 0, 0.55) 0 2px, transparent 2px),
    linear-gradient(270deg, rgba(0, 0, 0, 0.4) 0 2px, transparent 2px),
    /* grain, modulating the surface rather than covering it */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='170' height='170' filter='url(%23g)' opacity='0.62'/%3E%3C/svg%3E"),
    /* the vein is in the raw block too, just not brought up yet */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='440'%3E%3Cdefs%3E%3Cfilter id='v'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.015' numOctaves='4' seed='9' result='n'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='86'/%3E%3C/filter%3E%3C/defs%3E%3Cg filter='url(%23v)' fill='none' stroke='%23a08258'%3E%3Cpath d='M-40 268 C 120 232 210 286 340 190 S 480 78 600 44' stroke-width='1.5' opacity='0.24'/%3E%3Cpath d='M-30 372 C 130 330 240 356 340 288 S 480 200 600 214' stroke-width='1.1' opacity='0.17'/%3E%3Cpath d='M-40 96 C 110 136 208 88 330 128 S 470 196 600 168' stroke-width='0.8' opacity='0.14'/%3E%3C/g%3E%3C/svg%3E"),
    /* irregular quarry mottling: four pools that share no axis */
    radial-gradient(42% 50% at 9% 6%, rgba(224, 192, 140, 0.2), transparent 72%),
    radial-gradient(46% 40% at 74% 17%, rgba(148, 116, 72, 0.16), transparent 74%),
    radial-gradient(56% 48% at 30% 82%, rgba(10, 9, 13, 0.72), transparent 76%),
    radial-gradient(44% 54% at 96% 74%, rgba(8, 7, 11, 0.8), transparent 72%),
    /* the body of the block */
    linear-gradient(146deg, #322a1d 0%, #221c14 30%, #14110f 66%, #0d0b10 100%);
  background-size: cover, cover, cover, cover, 170px 170px, cover, cover, cover, cover, cover, cover;
  background-position: 0 0, 0 0, 0 100%, 100% 0, 0 0, center, center, center, center, center, center;
  background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat;
  background-blend-mode: normal, normal, normal, normal, soft-light, normal, normal, normal, normal, normal, normal;
}

/* stone dust, up while the work is happening and gone when it stops. A
   product of a rise and a fall, so it needs no keyframes and no JS. */
.blk__dust {
  position: absolute;
  inset: 22% 0 -7% 0;
  z-index: 4;
  pointer-events: none;
  filter: blur(14px);
  background:
    radial-gradient(9rem 5rem at 26% 86%, rgba(214, 186, 138, 0.3), transparent 70%),
    radial-gradient(12rem 6rem at 58% 96%, rgba(192, 156, 96, 0.24), transparent 72%),
    radial-gradient(7rem 4rem at 82% 78%, rgba(214, 186, 138, 0.2), transparent 70%);
  opacity: calc(
    clamp(0, calc(var(--carve) * 5), 1) *
    clamp(0, calc((1 - var(--carve)) * 2.4), 1) * 0.85
  );
}

/* ---- what came off ------------------------------------------------------
   Four pieces do not disappear. They land on the base and stay there. */

.blk__frags {
  position: absolute;
  inset: 0;
  z-index: 7;
  pointer-events: none;
}

.bfrag {
  --t: clamp(0, calc((var(--carve) - 0.56) * 2.4), 1);
  position: absolute;
  bottom: var(--fb);
  left: var(--fl);
  width: var(--fw);
  height: var(--fh);
  clip-path: var(--p);
  transform: translateY(calc((1 - var(--t)) * -38px)) rotate(var(--fr));
  opacity: calc(var(--t) * 0.95);
  background-color: #14120e;
  background-image:
    /* A LIT UPPER FACET OVER A BODY IN SHADOW. This is the whole difference
       between a chip and a sticker: at this size a flat fill reads as a piece
       of tape, and the only thing that makes a small shape solid is that one
       plane of it catches the light and the rest does not. */
    linear-gradient(168deg,
      rgba(232, 208, 162, 0.4) 0%,
      rgba(196, 164, 112, 0.2) 16%,
      rgba(0, 0, 0, 0) 33%),
    linear-gradient(0deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 46%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='170' height='170' filter='url(%23g)' opacity='0.62'/%3E%3C/svg%3E"),
    linear-gradient(158deg, #2c261c 0%, #191510 44%, #0d0b0e 100%);
  background-size: cover, cover, 170px 170px, cover;
  background-blend-mode: normal, normal, soft-light, normal;
  /* off the block and out of the main light, but still readable as stone -
     a piece nobody can see is not evidence of anything */
  filter: brightness(0.88) saturate(0.82);
  box-shadow: 0 5px 12px -7px rgba(0, 0, 0, 0.95);
}

/* the block stands on something, which is what makes the pieces read as
   fallen rather than as floating shapes */
.blk__base {
  display: block;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(156, 120, 72, 0.5) 0%,
    rgba(156, 120, 72, 0.3) 58%,
    rgba(156, 120, 72, 0.06) 100%);
  box-shadow: 0 10px 26px -14px rgba(0, 0, 0, 0.9);
}

/* the light GSAP adds on top: a slow pass over the worked face. It is the
   BACKGROUND that travels, never the element - translating the element would
   carry the light out over the copy column, and the cover sheet already had
   to learn that lesson about moving a lit layer instead of the light. Resting
   opacity is 0, so with no GSAP there is simply no pass. */
.blk__sheen {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  background-image: linear-gradient(104deg,
    transparent 40%,
    rgba(255, 246, 226, 0.1) 49%,
    rgba(192, 156, 96, 0.06) 53%,
    transparent 63%);
  background-size: 230% 100%;
  background-repeat: no-repeat;
  background-position: -65% 0;
}

.blk__tell {
  margin-top: clamp(0.75rem, 0.6rem + 0.5vw, 1.1rem);
  padding-right: var(--bleed);
  max-width: 30rem;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--vein);
}

/* --------------------------------------------------------------------------
   Narrower
   -------------------------------------------------------------------------- */

@media (max-width: 1180px) {
  /* the headline holds two lines: widen the column before shrinking the type,
     the same call the what-we-do cover sheet makes */
  .blk__body { grid-template-columns: minmax(0, 1.14fr) minmax(0, 0.86fr); gap: clamp(2rem, 1.2rem + 2.4vw, 3rem); }
  .blk__stage { --blk-h: clamp(17rem, 10rem + 21vw, 26rem); }
  /* the block narrows faster than the label does, and by ~1100px the bottom
     left stone is no longer wide enough to hold "The agreement" - face B has
     to give the inscription its ground back */
  .bface--b { left: 38%; width: 62%; }
}

@media (max-width: 1024px) {
  .hero--block { min-height: 0; }
  .blk__body {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(2.25rem, 1.6rem + 2.4vw, 3.25rem);
  }
  .blk__claim { max-width: 34rem; }

  /* THE BLOCK IS CAPPED AND ASPECT-DRIVEN ONCE IT STACKS, NOT GIVEN A FIXED
     HEIGHT. Full width at a fixed height turns a 66% face into a 3.3:1 slot,
     and `cover` then crops the walking figure's head off - the picture stops
     being the picture. Capping the width and letting the height follow keeps
     every crop close to the one that was composed at 1440. */
  .blk__stage {
    margin-top: 0;
    margin-left: auto;
    width: calc(min(100%, 44rem) + var(--bleed));
    --k: 0.72;
  }
  .blk__block { height: auto; aspect-ratio: 1.75 / 1; }
  /* taller faces, because the block itself is now much wider than it is tall */
  .bface--a { width: 66%; height: 52%; }
  .bface--b { left: 34%; top: 60%; width: 66%; height: 40%; }
  .blk__idx--a { top: 53.5%; }
  .blk__idx--b { top: 66%; }
  .blk__mark { left: 69%; top: 9%; }
  .blk__tell { max-width: none; }
}

@media (max-width: 700px) {
  .blk__block { aspect-ratio: 1.3 / 1; }
  .blk__stage { --k: 0.55; }
}

@media (max-width: 620px) {
  /* the inscriptions are the first thing to crowd the pictures here: the
     bottom-left stone is only as wide as face B's left edge, so the label has
     to fit inside it or it lands on the photograph */
  .bface--b { left: 40%; width: 60%; }
  .blk__mark, .blk__idx { font-size: 0.56rem; letter-spacing: 0.14em; }
  .blk__mark { left: 71%; top: 7%; padding-top: 0.55rem; }
  .blk__idx { padding-left: 1.35rem; }
  .blk__idx::before { width: 0.95rem; }
}

@media (prefers-reduced-motion: reduce) {
  /* --carve is already at its finished initial value; only the light stops */
  .blk__sheen, .blk__dust { display: none; }
  .bface { transition: none; }
}

/* ==========================================================================
   THE FIRM — "the corridor"   (about.html, section 01)

   It replaced an `.ed ed--flip ed--overlap` split. That block had three
   separate faults, and two of them are ones this site has already paid for:

   1. ITS IMAGE USED `data-src`, so the clean pass hid it and the section
      rendered as a BLANK MARBLE PANEL beside a paragraph - the same failure
      as `.barx`, `.jobx`, `.trn` and `.turn` before they were rebuilt.
   2. THE PHOTOGRAPH IT POINTED AT WAS `boardroom.jpg`, a conference room,
      which the knowledge base bans outright as corporate cliche. So the
      section could never have been fixed by flipping data-src back to src.
   3. `.ed` is used twice on this page, here and by the founder directly
      below, so the two sections were the same shape one after the other.

   `.ed` STAYS: the founder section is still its user, and about.html is now
   its only user site-wide. `.ed--flip` and `.ed--overlap` are left in place
   rather than sliced out - see the near-miss note about deleting CSS between
   two markers. They have no user now and are a safe follow-up.

   **THE COPY WAS THE REAL FAULT, FOR THE FOURTH TIME ON THIS SITE.** The h2
   read "We built a sales force, and we rent it." and the paragraph under it
   ENDED with "We built a sales force, and we rent it to brands that need
   one." The section restated its own headline. And "38,000+ customers and
   $3.5M+ in revenue" was stated here, again in the `.statbar` four sections
   below, and a third time in the FAQ - three times on one page.
   Resolved without inventing a word: the negation is promoted OUT of the end
   of the paragraph and becomes the headline, the resolution becomes the
   closing statement, and the numbers go back to the `.statbar`, which owns
   them on this page and animates them. So the section now opens by saying
   what Marble is NOT and does not answer until the last line.

   THE COMPOSITION IS A MASTHEAD, A SPREAD AND A VERDICT, not a split: the
   headline sits above everything, the wide plate runs off the LEFT edge of
   the page (the hero above bleeds RIGHT - the same alternation `.jobx` uses
   against `.barx` on careers), the detail plate is pulled back over the seam
   between the two halves so they interlock, and the closing statement is
   indented across the full width under a hairline.

   THE LIGHT COMES DOWN THE CORRIDOR, and that is the one movement here. The
   site sweeps light ACROSS a flat surface in four places (`.cover`, `.board`,
   `.blk`, and the raking light on `.barx`); nothing moves light ALONG the
   depth of a photograph. It is motivated by this picture specifically - three
   people walking away under pendant lamps toward the far end - so it reads as
   the room lighting rather than as an effect on a rectangle, and it needs no
   caption. `--lamp` also lifts the plate's grade, so one number brings the
   whole picture up with the light.

   Photography is an explicit exception to the `.media img` clean pass via its
   own `.frm__*` classes: team-walk (the force, three figures from behind, no
   face claimed) and door (one hand, the point of contact). Neither is used as
   a real photograph anywhere else on about.html.
   ========================================================================== */

.frm {
  position: relative;
  /* the plate runs off the left edge; clip so it can never become a scrollbar */
  overflow-x: clip;
  --bleed: max(var(--gutter), calc((100vw - var(--container)) / 2));
  /* 0 unlit .. 1 lit. CSS value IS the finished state, so no-GSAP renders the
     corridor already lit. GSAP writes it every frame and it is unregistered on
     purpose: it never has to interpolate, and it reaches the children for free
     without the site-wide recalc cost of a registered inherited property. */
  --lamp: 1;
}

.frm__ground {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(46rem 26rem at 22% 26%, rgba(156, 120, 72, 0.09), transparent 66%),
    radial-gradient(34rem 22rem at 88% 92%, rgba(128, 96, 48, 0.06), transparent 68%);
}

.frm__inner { position: relative; z-index: 1; }

/* ---- the masthead ------------------------------------------------------- */

.frm__head {
  max-width: 44rem;
  margin-bottom: clamp(2.25rem, 1.6rem + 2.6vw, 3.75rem);
}

.frm__head h2 {
  margin-top: clamp(0.9rem, 0.75rem + 0.6vw, 1.3rem);
  text-wrap: balance;
}

/* ---- the spread --------------------------------------------------------- */

.frm__row {
  display: grid;
  grid-template-columns: minmax(0, 1.22fr) minmax(0, 0.78fr);
  gap: clamp(2rem, 1.1rem + 2.8vw, 3.75rem);
  align-items: start;
}

/* the wide plate, running off the left edge of the page */
.frm__plate {
  position: relative;
  /* the lamp blends with `screen`, and this plate is `z-index: auto`, so
     without an explicit stacking context the blend would resolve against
     whatever is painted below it in the section rather than against the
     photograph. Same defensive call as the nav pill and the hero block. */
  isolation: isolate;
  margin: 0 0 0 calc(-1 * var(--bleed));
  width: calc(100% + var(--bleed));
  aspect-ratio: 2.08 / 1;
  overflow: hidden;
  /* same cut edge as the hero's faces, so the two sections read as the same
     material rather than as two different treatments of a photograph */
  box-shadow:
    inset 0 0 0 1px rgba(156, 120, 72, 0.34),
    inset 0 3px 12px -4px rgba(0, 0, 0, 0.9),
    0 18px 46px -28px rgba(0, 0, 0, 0.95);
}

.frm__shot {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* laid out larger than its opening so the scroll drift never exposes an edge.
   Layout, not a base transform - GSAP owns this element's transform alone. */
.frm__shot img {
  position: relative;
  top: -7%;
  width: 100%;
  height: 114%;
  object-fit: cover;
  object-position: 50% 46%;
  filter:
    brightness(calc(0.88 + var(--lamp) * 0.18))
    saturate(0.88)
    contrast(1.05);
}

/* THE LIGHT AT THE FAR END. Sized and lit from --lamp, positioned on the
   picture's own vanishing point, so it grows the way an approaching source
   does instead of pulsing in place. */
/* --lampx IS REGISTERED, --lamp IS NOT, AND THE SPLIT IS DELIBERATE. GSAP
   writes --lamp every frame of the scrub, so it never has to interpolate and
   can stay unregistered and inherit for free. --lampx is a hover nudge CSS has
   to TRANSITION, and an unregistered property cannot interpolate - it would
   step. It is registered `inherits: false` and written on this element alone,
   because a registered INHERITED property is computed on every element in
   every document that loads this stylesheet, and editorial.css is on all nine
   pages (the lesson the clock's specular pair paid for). */
@property --lampx { syntax: "<number>"; inherits: false; initial-value: 0; }

.frm__lamp {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  mix-blend-mode: screen;
  transition: --lampx 0.75s var(--ease-out);
  --l: clamp(0, calc(var(--lamp) + var(--lampx)), 1.3);
  background: radial-gradient(
    calc((15 + var(--l) * 32) * 1%) calc((20 + var(--l) * 44) * 1%) at 52% 27%,
    rgba(255, 234, 190, calc(0.3 * var(--l))),
    rgba(192, 156, 96, calc(0.12 * var(--l))) 46%,
    transparent 74%);
}

/* the obsidian grade, kept off the photograph's own filter so the two tune
   separately */
.frm__plate::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(180deg, rgb(34 31 27 / 0.3) 0%, transparent 34%, rgba(6, 6, 8, 0.5) 100%);
}

.frm__cap {
  position: absolute;
  z-index: 4;
  left: var(--bleed);
  bottom: clamp(0.9rem, 0.7rem + 0.8vw, 1.4rem);
  padding-left: 2.1rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-light);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}
.frm__cap::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.86em;
  width: 1.55rem;
  height: 1px;
  background: linear-gradient(90deg, rgba(192, 156, 96, 0.85), rgba(192, 156, 96, 0.2));
}

/* ---- the column --------------------------------------------------------- */

.frm__copy { min-width: 0; }

/* the detail plate is pulled back over the seam, which is what stops the row
   reading as two columns sitting next to each other */
.frm__inset {
  position: relative;
  /* THE NEGATIVE MARGIN HAS TO BEAT THE COLUMN GAP BEFORE ANY OVERLAP EXISTS
     AT ALL - at -75px against a 60px gap this plate reached 15px onto the
     photograph, which reads as a misaligned edge rather than as a plate laid
     over another. The same arithmetic caught the careers bar. */
  margin: 0 0 clamp(1.15rem, 0.9rem + 1vw, 1.7rem) clamp(-9rem, -3.5rem - 4.5vw, -3.5rem);
  width: min(100% + 9rem, 17rem);
}

/* the picture clips, the figure does not - the caption hangs below it */
.frm__insetshot {
  position: relative;
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  box-shadow:
    inset 0 0 0 1px rgba(156, 120, 72, 0.4),
    0 1px 0 rgba(255, 255, 255, 0.05),
    0 16px 34px -20px rgba(0, 0, 0, 0.95);
}

/* THE LINE THAT CONNECTS THE TWO PHOTOGRAPHS. The wide plate is the firm
   leaving and this is where one of them arrives; without it the pair is just
   two pictures. It says what the section means rather than what the layout is
   doing, which is the test the rejected devices on this site kept failing. */
.frm__bridge {
  margin-top: clamp(0.7rem, 0.6rem + 0.4vw, 1rem);
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-lg);
  line-height: 1.4;
  color: var(--vein);
}

/* GRADED UP, NOT DOWN. This frame is a low-key photograph shown at a sixth of
   the wide plate's area, and at the site's usual grade it read as a dark
   rectangle you could not identify - the empty-screen failure at small scale.
   A detail plate has to be lit harder than the plate it sits on. */
.frm__inset img {
  position: relative;
  top: -7%;
  width: 100%;
  height: 114%;
  object-fit: cover;
  object-position: 56% 52%;
  filter: brightness(1.34) contrast(1.02) saturate(0.9);
}

.frm__lede {
  font-size: var(--text-lg);
  line-height: 1.7;
  color: var(--ink);
  text-wrap: pretty;
}

.frm__body {
  margin-top: clamp(0.9rem, 0.75rem + 0.6vw, 1.25rem);
  color: var(--vein);
  text-wrap: pretty;
}

/* ---- the verdict -------------------------------------------------------- */

.frm__close {
  margin-top: clamp(2.5rem, 1.8rem + 3vw, 4.25rem);
}

/* STATIC, never drawn. A rule that extends from one end is `.cab`'s gesture on
   what-we-do and a rule opening from the centre is `.stop`'s; this one is
   structure rather than motion. */
.frm__rule {
  display: block;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(156, 120, 72, 0.06) 0%,
    rgba(156, 120, 72, 0.42) 34%,
    rgba(156, 120, 72, 0.18) 100%);
}

.frm__stmt {
  margin-top: clamp(1.35rem, 1rem + 1.4vw, 2.1rem);
  margin-left: auto;
  max-width: 52rem;
  width: 100%;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.15rem + 1.7vw, 2.55rem);
  line-height: 1.22;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
}
.frm__stmt em {
  font-style: italic;
  color: var(--gold-light);
}

/* --------------------------------------------------------------------------
   Narrower
   -------------------------------------------------------------------------- */

@media (max-width: 1024px) {
  .frm__row {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.75rem, 1.2rem + 2vw, 2.5rem);
  }
  .frm__plate {
    aspect-ratio: 1.9 / 1;
    width: calc(100% + var(--bleed));
  }
  /* stacked, the detail plate keeps its overlap by riding UP over the wide
     plate's bottom edge instead of sideways over the column seam. It has to
     ride up nearly its own height: hanging BELOW the plate instead left a
     wide empty band under the photograph with the plate on one side of it
     and nothing on the other. */
  .frm__inset {
    margin: clamp(-9rem, -4rem - 7vw, -4rem) 0 clamp(1.5rem, 1.2rem + 1vw, 2rem) auto;
    width: min(48%, 15rem);
  }
  /* UNEVEN BLOCKS, EVEN MEASURE. Run full width here the lede sets a
     110-character line, and a definition nobody can read is not a definition. */
  .frm__lede, .frm__body { max-width: 42rem; }
  .frm__stmt { margin-left: 0; }
}

@media (max-width: 620px) {
  .frm__plate { aspect-ratio: 1.42 / 1; }
  .frm__inset { width: min(58%, 12rem); }
  .frm__cap { font-size: 0.56rem; letter-spacing: 0.16em; padding-left: 1.5rem; }
  .frm__cap::before { width: 1.05rem; }
}

/* the room answers when you look into it. CSS owns this because it is
   presentational and stateless; --lampx never meets the scrubbed --lamp, so a
   transition and a tween can not fight (the two-number pattern). */
@media (hover: hover) {
  .frm__plate:hover .frm__lamp { --lampx: 0.26; }
}

@media (prefers-reduced-motion: reduce) {
  /* --lamp is already at its finished value; only the hover lift stops */
  .frm__lamp { transition: none; }
  .frm__plate:hover .frm__lamp { --lampx: 0; }
}

/* ==========================================================================
   MISSION & VISION — "the letterbox"   (about.html, section 02)

   It replaced a plain `.grid` with two `.col-6` halves, each an eyebrow over a
   `.kicker-lg` line. Two identical columns saying two things is the shape a
   template produces, and it is the third time that exact shape has had to be
   rebuilt on this site. `.col-6` and `.grid` STAY (team and five other pages
   use them); `.kicker-lg` has NO user left after this and is a safe follow-up
   deletion - it was deliberately not sliced out here, per the near-miss that
   silently removed `.argue`.

   **THE COPY WAS NOT THE FAULT THIS TIME, AND THAT IS WORTH RECORDING.** Both
   statements were measured unique site-wide before anything was touched: the
   mission appears in visible copy only here (its one other hit is an index
   `twitter:description` meta tag), and "thinks of first", "Fortune 500" and
   "has to happen in person" are one occurrence each, all on this page. So
   neither sentence was changed. Where the copy IS clean, say so and leave it.

   A MISSION AND A VISION ARE NOT TWO EQUAL THINGS, which is exactly what two
   equal columns claimed. One is what is true today; the other is not true yet.
   The composition argues that instead of stating it: the frame opens.

   **THE GRAMMAR IS A LETTERBOX OPENING, ON THE VERTICAL.** Everything on this
   site that changes size does it sideways or in depth - `.climb` widens a
   frame horizontally as scope, `.worlds` pushes the camera in, `.gates` swing,
   `.opn` closes a brace. Nothing opens on the Y axis, and nothing pulls BACK.
   Here the section arrives as an anamorphic letterbox holding the mission, and
   as you read, the matte bars retract while the photograph pulls back from a
   handful of roofs to a whole market - so the same picture means "one
   customer" in the slot and "the standard for a category" when it is open, and
   the vision is literally the thing you can only see once the view opens.
   That is the mission-to-vision relationship as a camera move, and it needs no
   caption to be read.

   ONE NUMBER DOES ALL OF IT. `--open` (0 letterboxed, 1 full frame) drives both
   matte heights AND the photograph's scale through calc, so a three-part move
   is one scrubbed value. It is unregistered - GSAP writes it every frame so it
   never has to interpolate, and it reaches the children for free without the
   site-wide recalc cost of a registered inherited property - and its CSS value
   is 1, THE FINISHED STATE, so no-GSAP / no-CDN / reduced motion all render the
   full open frame with both statements in place.

   THE TYPE DOES NOT DEPEND ON THE SCRUB. Both blocks arrive through the robust
   `.reveal` observer rather than from `--open`, so nothing can be left at a
   fraction of an opacity if a trigger never fires - the recurring trap on this
   site. The opening and the reveal land at the same scroll position, so it
   still reads as one event.

   LEGIBILITY: the veil hangs off `.aim__band`, which is FULL BLEED, never off
   the `.container` inside it. That is the left-seam bug the long wall paid for
   - an overlay on a container element starts at the container edge and leaves
   an unscrimmed strip with a hard vertical seam down the page.

   Photography is an explicit exception to the `.media img` clean pass via its
   own `.aim__*` classes: neighborhood.jpg, an aerial at golden hour. It is the
   only aerial in the library and the only frame that can be both a detail and
   a territory depending on how much of it you are shown.
   ========================================================================== */

.aim {
  /* the band is the section: a full-bleed cinematic cut between two
     container-bound sections, so it needs no vertical padding of its own */
  padding-block: 0;
  /* 0 letterboxed .. 1 full frame. CSS value IS the finished state. */
  --open: 1;
}

.aim__band {
  position: relative;
  width: 100%;
  height: min(88svh, 47rem);
  overflow: hidden;
  isolation: isolate;
  /* no ground of its own: the site has ONE, and it is fixed. See .ground. */
}

.aim__shot {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}

/* CSS OWNS THE TRANSFORM, GSAP OWNS ONLY THE NUMBER (the clock's
   compose-in-CSS pattern). A tween and a CSS-computed transform on the same
   element is the bug this site has shipped three times. */
.aim__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 46%;
  transform: scale(calc(1 + (1 - var(--open)) * 0.42));
  transform-origin: 50% 46%;
  filter: brightness(0.78) saturate(0.76) contrast(1.05);
}

/* the veil. FULL BLEED, hung off the band and never off the container. */
.aim__veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(6, 6, 8, 0.6) 0%, rgba(6, 6, 8, 0.14) 34%, rgba(6, 6, 8, 0.28) 58%, rgba(6, 6, 8, 0.82) 100%),
    linear-gradient(90deg, rgba(6, 6, 8, 0.76) 0%, rgb(34 31 27 / 0.3) 46%, rgba(6, 6, 8, 0.08) 72%, transparent 100%),
    radial-gradient(46rem 22rem at 88% 92%, rgba(6, 6, 8, 0.72), transparent 72%),
    radial-gradient(52rem 26rem at 14% 6%, rgba(156, 120, 72, 0.1), transparent 66%);
}

/* the matte bars. Solid at the outer edge and feathered at the inner one, so
   the frame OPENS rather than being wiped. */
.aim__matte {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 3;
  height: calc((1 - var(--open)) * 34%);
  pointer-events: none;
}
.aim__matte--t {
  top: 0;
  background: linear-gradient(180deg, var(--obsidian) 0%, var(--obsidian) 78%, rgb(34 31 27 / 0) 100%);
}
.aim__matte--b {
  bottom: 0;
  background: linear-gradient(0deg, var(--obsidian) 0%, var(--obsidian) 78%, rgb(34 31 27 / 0) 100%);
}

/* ---- the two statements ------------------------------------------------- */

.aim__type {
  position: absolute;
  inset: 0;
  z-index: 4;
}

.aim__inner {
  position: relative;
  height: 100%;
}

/* "Mission" and "Vision" are the section's real headings, so they are h2s
   wearing the eyebrow. The old block had no heading at all. */
.aim__label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-light);
  margin: 0 0 clamp(0.85rem, 0.7rem + 0.5vw, 1.15rem);
  display: inline-flex;
  align-items: center;
  gap: 0.875rem;
}
.aim__label::before {
  content: "";
  width: 2rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-light));
  flex: none;
}

.aim__stmt {
  font-family: var(--font-display);
  line-height: 1.16;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
  margin: 0;
}

/* the mission sits inside the letterboxed slot, so it is readable from the
   moment the section arrives */
/* CENTRED WITH `translate`, NOT `transform`, AND THIS IS A REAL TRAP. This
   block carries `.reveal`, and `.reveal.is-visible` sets `transform: none` -
   which silently wiped a `translateY(-50%)` the moment the block became
   visible, dropping the mission half its own height and straight through the
   vision below it (measured 45px of overlap at 1440). The independent
   `translate` property is applied separately from `transform`, so the reveal
   can animate one while layout owns the other. ANY element carrying `.reveal`
   must not use `transform` for positioning. */
.aim__mission {
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  max-width: 43rem;
}
