/* ══════════════════════════════════════════════════════════════
   NETWORKOUT — waitlist page · STANDALONE SHEET

   This used to be a thin layer over ../v5/styles.css. It is now a
   single sheet that owes v5 nothing: the page can be lifted out of
   this repo, dropped anywhere, and it will look the same.

   What that merge involved, so the next person is not surprised:

   · Only the parts of v5 this page actually renders were carried
     over. v5's own hero (.stack / .hq / .ticker / .hero-marg), its
     pricing table, its stat blocks and its .h2--big are gone —
     there is no markup here that could reach them.
   · The page used to spend its second half undoing v5's accent —
     .nx .btn on top of .btn, .nx .join on top of .join, and so on
     for a dozen components. Those pairs are collapsed: each
     component is now declared once, with the Networkout value, and
     the .nx body class they hung off has been dropped from the
     markup. The .nx- prefix survives only where it is a name
     (.nx-hero, .nx-h1) rather than a scope.
   · § PLATES is kept even though no markup currently uses it. The
     looping strip is meant to be restorable by pasting the markup
     back — see the comment in index.html — and that promise dies if
     the styles it needs go with v5.

   Behaviour that reads as a bug and is not: white means active here
   and orange means wrong, which is a cleaner split than v5's
   orange-means-important. So nearly every accent is bone, and the
   two survivors are deliberate — the focus ring, which has to stay
   visible on the bone blocks as well as the black ones, and a field
   filled in wrongly, because an error that looks identical to a
   correct field is not an error message.
   ══════════════════════════════════════════════════════════════ */

:root{
  --black:#0A0A0A;
  --steel:#141414;
  --bone:#F2F0EC;
  --grey:#7A7772;
  --line:rgba(242,240,236,.16);
  /* still declared, and still spent — but only on the two states
     above. See the header. */
  --hot:#FF4A1C;

  --pad:clamp(16px,3.6vw,64px);
  --mono:"Chivo Mono",ui-monospace,Menlo,monospace;
  --disp:"Anton","Haettenschweiler","Arial Narrow",sans-serif;
  --cut:cubic-bezier(.85,0,.15,1);
  --ease:cubic-bezier(.16,1,.3,1);
}

/* ── ground ──────────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box}
body{
  margin:0;background:var(--black);color:var(--bone);
  font-family:var(--mono);font-weight:300;font-size:15px;line-height:1.6;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
body::after{
  content:"";position:fixed;inset:0;z-index:300;pointer-events:none;opacity:.35;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='190' height='190'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='190' height='190' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
}
img,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
ul,ol,dl{margin:0;padding:0;list-style:none}
h1,h2,p,dd,dt,figure,figcaption{margin:0}
button{font:inherit}

/* `hidden` has to beat the display it is hiding: .done sets
   display:grid, which is a class rule and outranks the UA sheet's
   [hidden]{display:none} on its own. */
[hidden]{display:none!important}

.skip{position:absolute;left:-999px;background:var(--bone);color:var(--black);padding:10px 14px;z-index:400;font-size:11px}
.skip:focus{left:8px;top:8px}
/* one of the two places the orange stays: it has to read on the
   bone blocks as well as the black ones */
:focus-visible{outline:2px solid var(--hot);outline-offset:2px}

/* scroll progress */
.prog{position:fixed;top:0;left:0;right:0;height:2px;z-index:250;background:rgba(242,240,236,.08)}
.prog span{display:block;height:100%;width:0;background:var(--bone)}

/* column guides — the drafting sheet under the page */
.guides{position:fixed;inset:0;z-index:1;pointer-events:none;display:grid;grid-template-columns:repeat(5,1fr);padding:0 var(--pad)}
.guides i{border-left:1px solid rgba(242,240,236,.045)}
.guides i:last-child{border-right:1px solid rgba(242,240,236,.045)}
@media (max-width:760px){.guides{display:none}}

/* ── primitives ──────────────────────────────────────────────── */
.lbl{font:400 10px/1.5 var(--mono);letter-spacing:.24em;text-transform:uppercase;color:var(--grey)}
.lbl--inv{color:rgba(10,10,10,.55)}
.mono{font:300 12px/1.9 var(--mono);color:rgba(242,240,236,.7)}
.mono a:hover{color:var(--hot)}
.body{font-size:clamp(14px,1.25vw,17px);line-height:1.75;color:rgba(242,240,236,.68);max-width:52ch;font-weight:300}
.body--sm{font-size:12px;max-width:40ch}
.hot{color:var(--bone)}
.h2{
  font-family:var(--disp);font-weight:400;
  font-size:clamp(2.8rem,9.5vw,9rem);line-height:.84;letter-spacing:-.015em;
  text-transform:uppercase;margin:clamp(18px,2.4vw,32px) 0 clamp(28px,4vw,60px);
}
.h2--inv{color:var(--black)}

/* ── the mark ────────────────────────────────────────────────
   Bigger than v5 carries it. This page is somebody's first sight
   of the gym, arriving from a link rather than from the site, so
   the name has further to travel.

   The bar carries the joint lockup, which is landscape where the
   TriFit mark on its own is nearly square — so it is sized by
   height, not width. Sizing it by width would let the bar grow to
   whatever the artwork's proportions happened to be. The footer
   keeps the TriFit mark alone. */
.mark{height:auto;display:block}
.top-brand .mark{width:auto;height:clamp(52px,6.2vw,72px)}
.mark--big{width:72px}

/* ── top bar ─────────────────────────────────────────────────── */
.top{
  /* flush to the top, not inset by the height of the progress rail.
     Offsetting it left a 2px band of page scrolling past above the
     bar, which reads as a gap the bar has failed to cover. The rail
     has the higher z-index, so it simply draws over the bar's first
     two pixels instead of pushing it down. */
  position:fixed;top:0;left:0;right:0;z-index:200;
  display:flex;align-items:center;gap:clamp(14px,3vw,40px);
  padding:14px var(--pad);transition:background .35s var(--cut),padding .35s var(--cut);
  border-bottom:1px solid transparent;
}
.top.is-stuck{background:rgba(10,10,10,.86);backdrop-filter:blur(10px);border-bottom-color:var(--line);padding-top:10px;padding-bottom:10px}
/* the section nav used to hold this over to the right edge; with
   the nav gone the button has to push itself there */
.top-go{margin-left:auto}

/* ── buttons ─────────────────────────────────────────────────
   The button inverts rather than colours: bone ground, and the
   dark panel slides up under the label on hover. */
.btn{
  display:inline-flex;align-items:center;gap:10px;position:relative;overflow:hidden;isolation:isolate;
  background:var(--bone);color:var(--black);border:2px solid var(--bone);
  padding:15px 22px;font:500 10px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;
  transition:color .3s var(--cut),border-color .3s var(--cut);
}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--black);transform:translateY(101%);transition:transform .32s var(--cut)}
.btn:hover::before{transform:none}
.btn:hover{color:var(--bone);border-color:var(--bone)}
.btn i{font-style:normal;transition:transform .32s var(--cut)}
.btn:hover i{transform:translateX(6px)}
.btn--sm{padding:11px 15px;font-size:9px}
.btn--lg{padding:19px 28px;font-size:11px}
/* --xl sits on the bone closing block, so it stays the other way up */
.btn--xl{padding:26px 40px;font-size:13px;background:var(--black);border-color:var(--black);color:var(--bone)}
.btn--xl::before{background:var(--bone)}
.btn--xl:hover{color:var(--black);border-color:var(--black)}

/* the second door in — quieter than the button beside it */
.ghost{
  display:inline-flex;align-items:center;
  font:400 10px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;
  color:rgba(242,240,236,.72);padding:8px 0;border-bottom:1px solid var(--line);
  transition:color .3s var(--cut),border-color .3s var(--cut);
}
.ghost:hover{color:var(--bone);border-bottom-color:var(--hot)}
/* .ghost is written for an <a>; as a <button> it arrives with the
   agent's own chrome on it */
button.ghost{background:none;border:0;border-bottom:1px solid var(--line);cursor:pointer;font-family:var(--mono)}

/* ── hero ────────────────────────────────────────────────────
   Not v5's hero. There is no name to fill the screen with here
   and no film to play behind it — the page has one job, which is
   the box on the right, so the box gets half the frame and the
   first screen. */
.nx-hero{position:relative;min-height:100svh;display:flex;align-items:center;overflow:hidden;padding:clamp(96px,14vh,150px) var(--pad) clamp(48px,8vh,90px)}
.nx-hero-media{position:absolute;inset:0;z-index:0;background:var(--black)}
/* held right down: this is texture under the type, not a picture */
.nx-hero-media img{width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.1) brightness(.3)}
.nx-shade{position:absolute;inset:0;pointer-events:none;background:
  radial-gradient(120% 90% at 20% 40%,rgba(10,10,10,.55) 0%,rgba(10,10,10,.92) 70%,var(--black) 100%)}
.scanline{
  position:absolute;inset:0;pointer-events:none;opacity:.4;
  background-image:repeating-linear-gradient(0deg,rgba(0,0,0,.5) 0 1px,transparent 1px 4px);
}

.nx-hero-in{
  position:relative;z-index:3;width:100%;display:grid;gap:clamp(34px,4vw,64px);
  grid-template-columns:1fr;align-items:center;
}
@media (min-width:1000px){.nx-hero-in{grid-template-columns:1.05fr .95fr;gap:clamp(40px,5vw,90px)}}

/* the name, at a size that leaves room for the form beside it
   rather than eating the whole screen. --ty drives the reveal:
   the clipping box is padded upward so the cap line is never
   shaved off. */
.nx-h1{
  margin:0;font-family:var(--disp);font-weight:400;text-transform:uppercase;
  font-size:clamp(3rem,min(13.5vw,15vh),9.5rem);line-height:.92;letter-spacing:-.02em;
}
.ln{display:block;overflow:hidden;padding-top:.22em;margin-top:-.22em}
.w{display:inline-block;transform:translateY(var(--ty,101%));transition:transform 1s var(--cut)}
.is-ready .w{--ty:0%}
.out{color:transparent;-webkit-text-stroke:2px var(--bone)}
/* WORK and OUT share the second line and read as one word, so no
   gap between them — the break is NET / WORKOUT, not NET / WORK / OUT */
.nx-h1 .ln--pair{display:flex;align-items:baseline}

.nx-sub{
  margin-top:clamp(20px,2.6vw,32px);max-width:46ch;
  font:300 clamp(13px,1.15vw,15px)/1.75 var(--mono);letter-spacing:.02em;color:rgba(242,240,236,.72);
}

/* the four things somebody checks before they read a word — when,
   where, what it costs, and whether it is aimed at them. That last
   one is the tile that decides whether the rest gets read at all,
   so it is the one carrying .hot.

   No uppercasing here, unlike everywhere else on the page: several
   of the values are proper nouns and a date, and shouting them
   costs the capitalisation that tells you which is which. */
.facts{
  display:grid;grid-template-columns:1fr;gap:1px;list-style:none;padding:0;
  margin-top:clamp(26px,3.4vw,44px);background:var(--line);border:1px solid var(--line);
}
@media (min-width:520px){.facts{grid-template-columns:repeat(3,minmax(0,1fr))}}
.facts li{background:rgba(10,10,10,.72);padding:14px 14px 16px}
.facts b{display:block;font-family:var(--disp);font-weight:400;font-size:clamp(1.2rem,1.9vw,1.6rem);line-height:1.05;letter-spacing:-.01em}
.facts span{display:block;margin-top:7px;font:300 10px/1.4 var(--mono);letter-spacing:.08em;color:var(--grey)}
/* the reader tile takes the full width above the three logistics
   ones — given a column of its own it would wrap to two lines and
   read as the least of four equals, which is the opposite of the
   job it is doing */
.facts li.hot{
  grid-column:1/-1;background:rgba(242,240,236,.07);
  box-shadow:inset 3px 0 0 var(--bone);padding:15px 15px 17px;
}
.facts li.hot b{font-size:clamp(1.3rem,2.1vw,1.75rem)}
.facts li.hot span{color:rgba(242,240,236,.6)}

/* ── the box ─────────────────────────────────────────────────
   Given a border and a ground of its own so it reads as a thing
   to fill in rather than more page. */
.card{
  position:relative;background:rgba(10,10,10,.88);backdrop-filter:blur(6px);
  border:1px solid rgba(242,240,236,.28);padding:clamp(22px,2.6vw,38px);
}
.card::before,.card::after{
  content:"";position:absolute;width:14px;height:14px;pointer-events:none;
  border:2px solid var(--bone);
}
.card::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.card::after{bottom:-1px;right:-1px;border-left:0;border-top:0}
.card-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;border-bottom:1px solid var(--line);padding-bottom:14px;margin-bottom:clamp(18px,2.2vw,26px)}

.f{display:grid;gap:clamp(14px,1.8vw,20px)}
.f-row{display:grid;gap:clamp(14px,1.8vw,20px)}
@media (min-width:520px){.f-row{grid-template-columns:1fr 1fr}}
.fld{display:block;min-width:0}
.fld>span{display:block;font:400 9px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--grey);margin-bottom:9px}
.fld input,.fld select{
  width:100%;background:transparent;color:var(--bone);
  border:0;border-bottom:1px solid rgba(242,240,236,.28);border-radius:0;
  padding:9px 0;font:300 14px/1.4 var(--mono);letter-spacing:.02em;
  transition:border-color .3s var(--cut);
}
.fld input::placeholder{color:rgba(242,240,236,.26)}
.fld input:focus,.fld select:focus{outline:0;border-bottom-color:var(--bone)}
.fld select{appearance:none;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--grey) 50%),linear-gradient(135deg,var(--grey) 50%,transparent 50%);
  background-position:calc(100% - 10px) 55%,calc(100% - 5px) 55%;background-size:5px 5px;background-repeat:no-repeat;
  padding-right:22px;
}
.fld select option{background:var(--black);color:var(--bone)}
/* the other place the orange stays. Higher specificity than the
   :focus rule above on purpose: a field with something wrong in it
   keeps its mark while you are standing in it, which is when the
   mark is worth anything. And only once somebody has actually put
   something in — an empty field is not yet a mistake. */
.fld input:not(:placeholder-shown):invalid{border-bottom-color:var(--hot)}

.chk{display:grid;grid-template-columns:16px 1fr;gap:12px;align-items:start;cursor:pointer;margin-top:2px}
.chk input{
  appearance:none;width:16px;height:16px;margin:2px 0 0;
  border:1px solid rgba(242,240,236,.4);background:transparent;cursor:pointer;
  transition:background .2s var(--cut),border-color .2s var(--cut);
}
.chk input:checked{background:var(--bone);border-color:var(--bone)}
.chk input:checked::after{content:"";display:block;width:4px;height:8px;margin:1px auto 0;border:solid var(--black);border-width:0 2px 2px 0;transform:rotate(42deg)}
.chk span{font:300 11px/1.65 var(--mono);letter-spacing:.02em;color:rgba(242,240,236,.6)}
.chk b{font-weight:500;color:rgba(242,240,236,.85)}

.f-go{justify-content:center;margin-top:6px}
.f-go[disabled]{opacity:.55;cursor:default}
.f-go[disabled]:hover::before{transform:translateY(101%)}
/* orange, like a field filled in wrongly — on this page that is
   what the colour means */
.f-err{font:400 11px/1.6 var(--mono);letter-spacing:.03em;color:var(--hot)}
.f-err a{color:inherit;border-bottom:1px solid currentColor}
.f-note{font:300 10px/1.7 var(--mono);letter-spacing:.03em;color:var(--grey);text-align:center}
.f-note a{color:var(--bone);border-bottom:1px solid var(--line);transition:border-color .3s var(--cut)}
.f-note a:hover{border-bottom-color:var(--bone)}

.done{display:grid;gap:16px;justify-items:start;padding:clamp(10px,2vw,26px) 0}
.done-k{font-family:var(--disp);font-size:clamp(1.8rem,3.4vw,2.8rem);line-height:1;text-transform:uppercase;letter-spacing:-.01em;color:var(--bone)}
.done-b{font:300 13px/1.75 var(--mono);letter-spacing:.02em;color:rgba(242,240,236,.7);max-width:40ch}

/* ── sections ────────────────────────────────────────────────── */
.sec{position:relative;z-index:2;padding:clamp(70px,10vw,150px) var(--pad)}
.sec--flush{padding-bottom:0}
.two{display:grid;gap:clamp(30px,4vw,60px)}
@media (min-width:900px){.two{grid-template-columns:1.1fr .9fr;align-items:start}}
.two--inv{margin-top:0}
.lead-nx{max-width:62ch;margin:calc(-1 * clamp(12px,1.6vw,24px)) 0 clamp(30px,4vw,52px)}
.lead-nx b{color:var(--bone);font-weight:500}

/* ══ § PLATES — the survey overlay ═════════════════════════════
   Nothing on this page uses these at the moment. They are kept
   because the looping strip is meant to be restorable by pasting
   its markup back — see the comment in index.html and the clips at
   media/n1—n3-loop.mp4 — and that is only true while the styles
   are here to receive it.

   The drawing is a generated clip made from that plate's own
   photograph as its start frame, so the still and the clip are the
   same picture: frame zero of the video is the jpg sitting under
   it. The video can therefore be switched on at full opacity with
   nothing visibly happening, and the only change the eye catches
   is the pen starting to move.

   v5's plates wait to be pointed at. Nobody is expected to point
   at anything here, so --loop runs on its own: on, held, off the
   same way it arrived, held bare, round again. app.js starts the
   three at different points so the strip is never doing the same
   thing in three places.
   ═════════════════════════════════════════════════════════════ */
.strip-head{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-top:clamp(40px,6vw,90px);border-bottom:1px solid var(--line);padding-bottom:10px}
.strip3{display:grid;gap:clamp(10px,1.2vw,16px);margin-top:clamp(12px,1.4vw,18px)}
@media (min-width:760px){.strip3{grid-template-columns:repeat(3,1fr)}}

/* 3:4 — the plates are 900 × 1200 and the clips are cut to match,
   so the drawing sits on the photograph with no crop between them */
.plate{
  position:relative;display:block;aspect-ratio:3/4;overflow:hidden;
  background:var(--steel);border:1px solid var(--line);isolation:isolate;
  transition:border-color .4s var(--cut);
}
.plate:hover,.plate:focus-visible{border-color:rgba(242,240,236,.4)}
/* no grayscale() here: the plates are already monochrome
   photographs, and desaturating the clip would take the orange out
   of the dimension lines */
.plate-img,.plate-vid{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:contrast(1.12);
}
.plate-vid{z-index:2;opacity:0;transition:opacity .34s var(--ease)}
.plate.is-on .plate-vid{opacity:1;transition:none}
.proc{
  position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(circle at 50% 50%,rgba(242,240,236,.5) 1px,transparent 1.2px);
  background-size:4px 4px;z-index:3;mix-blend-mode:overlay;opacity:.4;
}
.cap{
  position:absolute;left:10px;bottom:10px;z-index:4;
  font:400 9px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;
  color:var(--bone);background:var(--black);padding:5px 8px;border:1px solid var(--line);
  transition:opacity .3s var(--cut) .2s;
}
.plate.is-on .cap{opacity:0;transition:opacity .2s var(--cut)}
.plate-go{
  position:absolute;left:10px;bottom:10px;z-index:4;
  display:flex;align-items:center;gap:8px;
  font:500 9px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--black);
  background:var(--bone);padding:6px 9px;
  clip-path:inset(0 100% 0 0);transition:clip-path .2s linear;
}
.plate-go i{font-style:normal}
.plate.is-on .plate-go{clip-path:inset(0 0 0 0);transition:clip-path .34s linear 4.05s}

/* the looping variant: no hover target, and the drawing is always on */
.plate--loop{cursor:default}
.plate--loop .plate-vid{opacity:1;transition:none}
.plate--loop:hover,.plate--loop:focus-visible{border-color:var(--line)}
.plate--loop .cap{opacity:1}

/* ── the run sheet ───────────────────────────────────────────
   Down to the name and how long it lasts. The clock column and the
   line of description are gone, and with them the reason v5's rows
   are a four-track grid — two columns is the whole of it now.
   No hover target either: these are classes, not links. */
.rows{border-top:2px solid var(--bone);margin-top:clamp(20px,3vw,40px)}
.row{
  /* centred, not baseline: with the description gone there is
     nothing for the duration to sit on a line with, and against a
     cap this deep the baseline drops it to the floor of the row */
  display:grid;grid-template-columns:1fr auto;gap:4px 20px;align-items:center;
  padding:clamp(16px,2vw,26px) 0;border-bottom:1px solid var(--line);
}
.row-n{font-family:var(--disp);font-size:clamp(1.5rem,3.4vw,2.6rem);line-height:.92;letter-spacing:-.01em;text-transform:uppercase}
.row-m{font:400 10px/1.5 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--grey);text-align:right}

/* ── slab (inverted block) ───────────────────────────────────── */
.slab{position:relative;z-index:2;background:var(--bone);color:var(--black);margin-top:clamp(70px,10vw,150px)}
.slab-in{padding:clamp(70px,10vw,150px) var(--pad)}
.slab .body{color:rgba(10,10,10,.72)}
.steps{border-top:2px solid var(--black)}
.steps li{
  display:grid;grid-template-columns:40px 1fr;gap:2px 16px;padding:16px 0;
  border-bottom:1px solid rgba(10,10,10,.16);align-items:baseline;
  transition:padding-left .3s var(--cut);
}
.steps li:hover{padding-left:10px}
.steps b{font-family:var(--disp);font-size:20px;font-weight:400;color:rgba(10,10,10,.5)}
.steps span{font-family:var(--disp);font-size:clamp(1.2rem,2.2vw,1.8rem);text-transform:uppercase;letter-spacing:-.01em}
.steps i{grid-column:2;font:300 11px/1.6 var(--mono);letter-spacing:.06em;font-style:normal;color:rgba(10,10,10,.6)}

/* ── sponsor ─────────────────────────────────────────────────
   A footnote, not a chapter. This was a display heading, two
   paragraphs and a bordered box; it is now one hairline rule, one
   paragraph and the mark. The box is what did most of the damage —
   a border around a logo reads as bought placement, which is
   exactly the register a sponsor should not have on somebody
   else's signup page.

   The section keeps a lighter --tight padding so it reads as a
   note between the slab above it and the closing block below,
   rather than as a section of its own weight. */
.sec--tight{padding-top:clamp(44px,6vw,84px);padding-bottom:clamp(44px,6vw,84px)}
.sp{display:grid;gap:clamp(22px,3vw,40px);border-top:1px solid var(--line);padding-top:clamp(20px,2.4vw,30px)}
@media (min-width:760px){.sp{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:clamp(34px,6vw,80px)}}
.sp-l .lbl{margin-bottom:12px}
.sp-l .body{max-width:58ch;font-size:clamp(13px,1.05vw,14px)}
.sp-l b{color:var(--bone);font-weight:500}
.sp-r{display:grid;gap:14px;justify-items:start;align-content:start}
/* the artwork carries its own gradient — the one place on this
   page where a colour other than the orange is allowed. Held at
   85% so it sits back into the page rather than off it. */
.sp-mark{display:block;width:170px;max-width:100%;opacity:.85;transition:opacity .3s var(--cut)}
.sp-mark:hover{opacity:1}
.sp-mark img{width:100%;height:auto}
.sp-r .ghost{font-size:9px}
.sp-r .ghost i{font-style:normal;margin-left:6px}

/* ── join ────────────────────────────────────────────────────
   v5 ends on a slab of orange. Bone gives the same full stop
   without the colour, and sets up the black button that sits
   on it. */
.join{position:relative;z-index:2;background:var(--bone);color:var(--black);padding:clamp(70px,10vw,150px) var(--pad)}
.join-h{
  font-family:var(--disp);font-weight:400;text-transform:uppercase;
  font-size:clamp(3.4rem,15vw,14rem);line-height:.82;letter-spacing:-.02em;
  margin:clamp(18px,2.4vw,32px) 0 0;
}
.join-row{display:flex;justify-content:space-between;align-items:flex-end;gap:clamp(24px,4vw,60px);flex-wrap:wrap;margin-top:clamp(36px,5vw,70px);border-top:2px solid var(--black);padding-top:clamp(24px,3vw,40px)}
.join .body{color:rgba(10,10,10,.75);text-align:right;margin-left:auto}
@media (max-width:680px){.join .body{text-align:left;margin-left:0}}

/* ── footer ──────────────────────────────────────────────────── */
.foot{position:relative;z-index:2;padding:clamp(40px,5vw,70px) var(--pad) 24px}
.foot-cols{display:grid;gap:clamp(24px,3vw,44px);grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin-top:clamp(28px,3.4vw,44px)}
.foot-cols .lbl{margin-bottom:12px}
.foot-line{
  display:flex;flex-wrap:wrap;gap:10px 26px;justify-content:space-between;
  margin-top:clamp(40px,5vw,70px);border-top:1px solid var(--line);padding-top:16px;
  font:400 9px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--grey);
}

/* ── reveals — hard cuts, no drifting ─────────────────────────
   The wipe never closes past 45%: a target clipped to zero height
   reports intersectionRatio 0, and the observer that is meant to
   open it would never fire. */
[data-io]{
  opacity:0;transform:translateY(22px);clip-path:inset(0 0 45% 0);
  transition:opacity .45s var(--cut),transform .55s var(--cut),clip-path .6s var(--cut);
}
[data-io].in{opacity:1;transform:none;clip-path:inset(0 0 0 0)}
/* a plate must not carry the reveal clip once it has arrived, or it
   would keep a stacking context that traps the drawing's own clip */
.plate.in{clip-path:none}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
  [data-io]{opacity:1;clip-path:none;transform:none}
  .w{--ty:0%;opacity:1;transform:none}
  /* no pen, and the loop never stops — so do not run it at all */
  .plate-vid{display:none}
  .plate.is-on .cap{opacity:1}
  .plate.is-on .plate-go{clip-path:inset(0 100% 0 0)}
}
