/* ============================================================
   GYM DOUBLE X — style.css
   ------------------------------------------------------------
   Palette is pulled from two places only: the official logo
   (lime #ACFF29) and the footage itself (charcoal shell, warm
   LED strip white, olive-green feature walls).
   Nothing here ever tints the video pixels — all atmosphere
   sits in overlay layers ABOVE the <video>.
   ============================================================ */

/* ---------- 1. TOKENS ------------------------------------- */
:root{
  /* surfaces */
  --ink:#050505;
  --ink-2:#0A0A0B;
  --ink-3:#121214;
  --ink-4:#1A1A1D;

  /* type */
  --white:#F4F4F1;
  --gray:#8B8B85;
  --gray-dim:#56564F;

  /* brand */
  --lime:#ACFF29;          /* straight off the logo */
  --lime-deep:#7FBF13;
  --led:#FFE3B0;           /* the warm LED strips in the room */

  /* lines */
  --line:rgba(255,255,255,.09);
  --line-2:rgba(255,255,255,.17);

  /* fonts */
  --display:"Archivo","Helvetica Neue",Helvetica,Arial,sans-serif;
  --body:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* animated by JS */
  --gate:0px;              /* letterbox bar height */
  --warm:0;                /* 0 = dark shell · 1 = bright private studio */
  --noise:none;

  --pad:clamp(20px,4.5vw,72px);
  --navh:76px;             /* nav height — the mobile stage measures off it */
  --ease:cubic-bezier(.22,.61,.36,1);
}

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

html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  /* the sticky stage does the scroll-jacking; keep the document plain */
}
body{
  margin:0;
  background:var(--ink);
  color:var(--white);
  font-family:var(--body);
  font-weight:300;
  line-height:1.6;
  overflow-x:clip;              /* never a horizontal scrollbar */
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
body.menu-open,body.locked{overflow:hidden}

img,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
ul{margin:0;padding:0;list-style:none}

:focus-visible{outline:2px solid var(--lime);outline-offset:3px;border-radius:2px}
::selection{background:var(--lime);color:#080808}

/* !important throughout: this also hides the form honeypot, which
   would otherwise inherit .form input{width:100%} and blow the
   page open horizontally */
.sr-only{
  position:absolute!important;width:1px!important;height:1px!important;
  padding:0!important;margin:-1px!important;border:0!important;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;
}
.skip{
  position:fixed;top:12px;left:12px;z-index:400;transform:translateY(-200%);
  background:var(--lime);color:#080808;padding:11px 18px;
  font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  transition:transform .3s var(--ease);
}
.skip:focus{transform:none}

/* ---------- 2. TYPE HELPERS -------------------------------- */
.mono{font-family:var(--mono);font-weight:400}
.display{
  font-family:var(--display);font-weight:800;
  line-height:.85;letter-spacing:-.035em;text-transform:uppercase;margin:0;
}
.display em{font-style:normal;display:block;color:var(--lime)}
.eyebrow{
  font-family:var(--mono);font-size:clamp(10px,1.05vw,11px);font-weight:400;
  letter-spacing:.24em;text-transform:uppercase;color:var(--gray);margin:0 0 18px;
}
.eyebrow--green{color:var(--lime)}
.lede{
  font-size:clamp(14px,1.05vw,16px);color:rgba(244,244,241,.82);
  max-width:44ch;margin:18px 0 0;line-height:1.62;
}
.lede--tight{max-width:34ch}

/* ============================================================
   3. LOADER
   ============================================================ */
.loader{
  position:fixed;inset:0;z-index:300;background:var(--ink);
  display:grid;place-items:center;
  transition:opacity .9s var(--ease),visibility .9s;
}
.loader::after{ /* faint lime bloom behind the mark */
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(50% 45% at 50% 42%,rgba(172,255,41,.09),transparent 70%);
}
.loader.done{opacity:0;visibility:hidden;pointer-events:none}
.loader__inner{position:relative;z-index:1;text-align:center;padding:0 24px}
.loader__logo{
  width:clamp(120px,17vw,190px);height:auto;margin:0 auto 26px;
  filter:drop-shadow(0 0 34px rgba(172,255,41,.32));
  animation:markIn 1.1s var(--ease) both;
}
@keyframes markIn{from{opacity:0;transform:translateY(14px) scale(.94)}to{opacity:1;transform:none}}
.loader__word{
  font-size:clamp(26px,5.4vw,52px);letter-spacing:.02em;
  display:flex;justify-content:center;gap:.28em;
}
.loader__word em{display:inline}
.loader__tag{
  font-family:var(--mono);font-size:clamp(10px,1.1vw,12px);letter-spacing:.42em;
  text-transform:uppercase;color:var(--gray);margin:16px 0 34px;
}
.loader__bar{
  width:min(280px,58vw);height:1px;background:rgba(255,255,255,.13);
  position:relative;overflow:hidden;margin:0 auto;
}
.loader__bar i{
  position:absolute;inset:0 auto 0 0;width:0;background:var(--lime);
  box-shadow:0 0 14px rgba(172,255,41,.85);transition:width .28s linear;
}
.loader__pct{
  font-size:10px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gray-dim);margin:16px 0 0;
}

/* ============================================================
   4. NAV
   ============================================================ */
.nav{
  position:fixed;top:0;left:0;right:0;z-index:120;
  display:flex;align-items:center;gap:14px;
  padding:16px var(--pad);
  border-bottom:1px solid transparent;
}
/* No backdrop blur here either. The nav sits over the sticky video
   stage for the entire tour, so a blur on it would be re-resolved
   against a changing backdrop on every single scrubbed frame.

   Going solid is an OPACITY fade of a layer behind the bar, and nothing
   about the bar's size changes. It used to shrink its padding and its
   logo with transitions — layout on every frame for half a second,
   exactly as you start scrolling or come back to the top, and on a
   phone it made the logo GROW from 36 to 56 px (the solid-state width
   outranked the phone width). That jump was a big part of the screen
   "shaking" near the top. */
.nav::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(5,5,6,.94),rgba(5,5,6,.82));
  border-bottom:1px solid var(--line);
  opacity:0;transition:opacity .45s var(--ease);
}
.nav.is-solid::before{opacity:1}
/* The mark alone. It carries "DOUBLE X" inside the artwork already, so
   setting the words next to it was the logo said twice. Bigger, because
   it is now the only thing on that side of the bar. */
.nav__brand{display:flex;align-items:center;min-width:0}
.nav__brand img{width:64px;height:auto;transform-origin:0 50%;transition:transform .4s var(--ease)}
.nav.is-solid .nav__brand img{transform:scale(.875)}
/* brand left, links centred in what is left over, actions right —
   `auto` margins rather than space-between, because the bar now has
   five children and space-between would spread them into a row of
   equal gaps instead of three groups */
.nav__links{display:flex;gap:clamp(16px,2.1vw,30px);align-items:center;margin-inline:auto}
.nav__links a{
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--gray);position:relative;padding:7px 0;transition:color .3s;
}
.nav__links a::after{
  content:"";position:absolute;left:0;bottom:2px;height:1px;width:0;
  background:var(--lime);transition:width .38s var(--ease);
}
.nav__links a:hover,.nav__links a:focus-visible{color:var(--white)}
.nav__links a:hover::after{width:100%}
.nav__cta{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  border:1px solid var(--line-2);padding:10px 18px;white-space:nowrap;
  transition:background .35s var(--ease),color .35s,border-color .35s;
}
.nav__cta .ico{width:14px;height:14px;fill:var(--lime);transition:fill .35s}
.nav__cta:hover{background:var(--lime);border-color:var(--lime);color:#080808}
.nav__cta:hover .ico{fill:#080808}

.nav__burger{display:none;width:38px;height:38px;position:relative;flex:0 0 auto}
.nav__burger i{
  position:absolute;left:8px;right:8px;height:1.5px;background:var(--white);
  transition:transform .4s var(--ease),opacity .3s;
}
.nav__burger i:nth-child(1){top:15px}
.nav__burger i:nth-child(2){bottom:15px}
body.menu-open .nav__burger i:nth-child(1){transform:translateY(4.5px) rotate(45deg)}
body.menu-open .nav__burger i:nth-child(2){transform:translateY(-4.5px) rotate(-45deg)}



/* ============================================================
   5. THE TOUR — sticky cinematic stage
   ============================================================ */
/* black ground: on iOS the URL bar can uncover a sliver below a
   100svh sticky stage, and it should read as letterbox, not as a gap */
/* Height in svh, not vh, and this matters more than it looks: vh is
   re-measured when a phone collapses its address bar, so a track sized
   in vh gets SHORTER mid-scroll and the browser corrects the scroll
   position under the finger — the stick-then-jump. svh is the small
   viewport height and never changes, so the timeline has one length
   for the whole visit. */
.track{position:relative;height:880vh;height:880svh;height:calc(var(--sv,1svh) * 880);background:#000}

.stage{
  --warm:0;              /* the stage owns it; the engine writes it here */
  position:sticky;top:0;
  height:100vh;height:100svh;
  overflow:hidden;background:#000;
  perspective:1400px;
  perspective-origin:50% 46%;
}

.frame{
  position:absolute;inset:0;overflow:hidden;background:#000;
  transition:inset .6s var(--ease);
}
.frame__video,.frame__poster{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:50% 50%;
  background:#000;
  /* no filters on the footage — the room is shown as it was shot */
  /* keep the footage on its own compositor layer: every scrubbed
     frame then swaps a texture instead of repainting the stage */
  transform:translateZ(0);
  backface-visibility:hidden;
}
.stage{contain:layout paint}
.frame__poster{z-index:1;pointer-events:none;transition:opacity .9s var(--ease)}
/* once the footage is in, the poster is gone for good — not just see-through:
   an invisible full-screen picture is still a layer the GPU keeps */
.frame.ready .frame__poster{opacity:0;visibility:hidden;transition:opacity .9s var(--ease),visibility 0s linear .9s}

/* --- atmosphere (above the video, never on it) --- */
.atmo{position:absolute;inset:0;z-index:3;pointer-events:none}
/* The vignette hugs the edge; the centre of the room stays clean.
   Two of these, crossfaded by OPACITY, rather than one gradient with
   a transitioned colour inside it: interpolating a gradient means
   re-rasterising a full-screen radial on every frame of the half
   second it takes, and that half second lands exactly on the chapter
   seam where the scroll most needs to be smooth. */
.atmo::before{
  content:"";position:absolute;inset:0;
  background:radial-gradient(145% 108% at 50% 46%,transparent 56%,rgba(0,0,0,.42) 100%);
  opacity:calc(1 - var(--warm,0)*.57);
  transition:opacity .5s linear;
}
.atmo::after{ /* scrim only where copy sits */
  content:"";position:absolute;inset:0;opacity:calc(.5 - var(--warm)*.28);
  background:
    linear-gradient(180deg,rgba(5,5,5,.62),transparent 30%),
    linear-gradient(0deg,rgba(5,5,5,.72),transparent 40%);
  transition:opacity .5s linear;
}
/* Kept small and GPU-only. A grain layer inset far past the frame
   is a lot of extra pixels to composite on every scrubbed frame. */
.grain{
  position:absolute;inset:-30px;z-index:4;pointer-events:none;
  opacity:.028;background-image:var(--noise);background-size:180px 180px;
  animation:grain 1.05s steps(4) infinite;
  will-change:transform;
}
@keyframes grain{
  0%{transform:translate3d(0,0,0)}25%{transform:translate3d(-11px,6px,0)}
  50%{transform:translate3d(7px,-9px,0)}75%{transform:translate3d(-4px,-5px,0)}100%{transform:translate3d(0,0,0)}
}
/* No transition: the engine writes --gate every frame already, and a
   transition on top of that just adds a second animation to resolve.
   The bar is a fixed 3vh tall and SCALED, so the per-frame write is a
   transform the compositor handles rather than a height the layout
   engine has to re-resolve. */
.gate{
  position:absolute;left:0;right:0;z-index:5;background:#000;pointer-events:none;
  height:3svh;transform:scaleY(var(--gate,0));will-change:transform;
}
.gate--t{top:0;transform-origin:50% 0}
.gate--b{bottom:0;transform-origin:50% 100%}

/* --- callout markers, anchored to the real video content box --- */
.videobox{position:absolute;z-index:8;pointer-events:none}
/* The dot sits exactly on the target; the label always extends
   INWARD from it, so a marker near an edge never gets clipped. */
.mark{
  position:absolute;transform:translate(-4.5px,-50%);
  opacity:0;transition:opacity .5s var(--ease);
  display:flex;align-items:center;gap:0;
}
.mark.on{opacity:1}
.mark i{
  width:9px;height:9px;flex:0 0 auto;border:1px solid var(--lime);border-radius:50%;
  position:relative;background:rgba(172,255,41,.14);
}
.mark i::after{
  content:"";position:absolute;inset:-7px;border:1px solid rgba(172,255,41,.4);border-radius:50%;
  opacity:0;
}
/* only the markers actually showing ping — nine rings pinging behind
   opacity:0 were nine animations ticking on every frame of the tour */
.mark.on i::after{animation:ping 2.6s var(--ease) infinite}
@keyframes ping{0%{transform:scale(.7);opacity:.85}70%,100%{transform:scale(1.7);opacity:0}}
.mark span{
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--white);white-space:nowrap;
  padding:5px 10px 5px 0;margin-left:0;
  position:relative;
  transform:translateX(0);
}
.mark span::before{ /* the thin leader line */
  content:"";display:inline-block;vertical-align:middle;
  width:34px;height:1px;background:linear-gradient(90deg,var(--lime),rgba(172,255,41,.25));
  margin-right:10px;
}
.mark--flip{flex-direction:row-reverse;transform:translate(calc(-100% + 4.5px),-50%)}
.mark--flip span{padding:5px 0 5px 10px;direction:rtl}
.mark--flip span::before{
  margin:0 0 0 10px;
  background:linear-gradient(270deg,var(--lime),rgba(172,255,41,.25));
}
.mark--flip span *{direction:ltr}

/* --- copy layers --- */
.layers{position:absolute;inset:0;z-index:10;transform-style:preserve-3d;pointer-events:none}
.layer{
  position:absolute;inset:0;display:flex;
  padding:calc(13svh + 26px) var(--pad) calc(15svh + 26px);
  opacity:0;visibility:hidden;
}
/* keep right-aligned copy clear of the chapter rail's column */
@media (min-width:961px){
  /* enough for the rail's longest active label plus its dash */
  .layer{padding-right:calc(var(--pad) + 170px)}
}
/* will-change is set from script.js, and only on the one or two layers that
   are actually on screen: written here it promoted all eight, all the time */
.layer__in{max-width:min(880px,92vw);transform-style:preserve-3d;position:relative;z-index:1}
.layer--center{align-items:center;justify-content:center;text-align:center;flex-direction:column}
.layer--left{align-items:center;justify-content:flex-start}
.layer--right{align-items:center;justify-content:flex-end;text-align:right}
.layer--bl{align-items:flex-end;justify-content:flex-start}
.layer--right .lede,.layer--right .chips{margin-left:auto}
.layer--right .chips{justify-content:flex-end}

/* A directional scrim, only under the copy. It fades in and out
   WITH the layer, so the room is never permanently darkened —
   the shade arrives with the sentence and leaves with it. */
.layer::before{
  content:"";position:absolute;inset:0;pointer-events:none;
}
.layer--left::before{
  background:linear-gradient(90deg,rgba(4,4,4,.80),rgba(4,4,4,.46) 30%,transparent 62%);
}
.layer--right::before{
  background:linear-gradient(270deg,rgba(4,4,4,.80),rgba(4,4,4,.46) 30%,transparent 62%);
}
.layer--bl::before{
  background:linear-gradient(6deg,rgba(4,4,4,.86),rgba(4,4,4,.42) 38%,transparent 66%);
}
.layer--center::before{
  background:radial-gradient(70% 62% at 50% 52%,rgba(4,4,4,.62),transparent 72%);
}
/* the private studio is white, so its scrim has to be heavier to
   hold light type — but still only on the side the copy sits */
.layer[data-chapter="7"]::before{
  background:linear-gradient(270deg,rgba(4,4,4,.88),rgba(4,4,4,.58) 34%,transparent 66%);
}

/* Tour typography sits a good step smaller than a normal hero:
   the room is the subject, the words are the caption. */
.hero__title{font-size:clamp(32px,5.4vw,80px);line-height:.9}
.layer--hero .lede{max-width:36ch}
.hero__title em{text-shadow:0 0 60px rgba(172,255,41,.3)}
.hero__sub{
  font-family:var(--mono);font-size:clamp(10px,.95vw,12px);letter-spacing:.36em;
  text-transform:uppercase;color:var(--led);margin:20px 0 0;
}
.sec__title{font-size:clamp(30px,4.6vw,68px);line-height:.92}
.sec__title em{text-shadow:0 0 50px rgba(172,255,41,.26)}

.chips{display:flex;flex-wrap:wrap;gap:7px;margin:22px 0 0}
.chips li{
  font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:rgba(244,244,241,.88);
  border:1px solid var(--line-2);padding:6px 11px;
  /* deliberately NO backdrop-filter: blurring a live video backdrop
     on every scrubbed frame is the single most expensive thing you
     can put over this stage */
  background:rgba(10,10,11,.42);
}
/* The private studio is the one bright room in the building. It
   doesn't need a panel — the scrim on the right side carries the
   type, and the white studio stays fully visible behind it. */

.hint{
  display:inline-flex;align-items:center;gap:12px;margin:44px 0 0;
  font-size:10px;letter-spacing:.26em;text-transform:uppercase;color:var(--gray);
  transition:opacity .5s;
}
.hint__line{display:block;width:1px;height:34px;background:rgba(255,255,255,.16);position:relative;overflow:hidden}
.hint__line i{position:absolute;left:0;right:0;top:0;height:12px;background:var(--lime);animation:drip 1.9s var(--ease) infinite}
/* the hint fades out a moment into the tour; its drip stops with it */
.hint.is-gone .hint__line i{animation:none}
/* transform, not top: a moving `top` is a layout on every frame */
@keyframes drip{0%{transform:translateY(-14px)}100%{transform:translateY(36px)}}

/* --- HUD --- */
.hud{position:absolute;inset:0;z-index:14;pointer-events:none}
/* flat translucency, no backdrop-filter — see the note on .chips */
.glass{background:rgba(10,10,11,.5);border:1px solid var(--line)}
.hud__tr{
  position:absolute;top:calc(64px + env(safe-area-inset-top,0px));
  right:var(--pad);color:var(--lime);
  font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  padding:8px 13px;
}

/* --- chapter rail (desktop) --- */
.rail{
  position:absolute;right:var(--pad);top:50%;transform:translateY(-50%);
  z-index:15;display:flex;flex-direction:column;gap:2px;
}
.rail__item{
  display:flex;align-items:center;gap:12px;justify-content:flex-end;
  padding:7px 0;position:relative;
  font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--gray-dim);transition:color .4s var(--ease);
}
.rail__item b{font-weight:400;opacity:.7}
.rail__item span{
  opacity:0;transform:translateX(8px);
  transition:opacity .4s var(--ease),transform .4s var(--ease);
}
.rail__item i{
  width:26px;height:1px;background:rgba(255,255,255,.2);flex:0 0 auto;
  transition:width .45s var(--ease),background .45s;
}
.rail:hover .rail__item span{opacity:.65;transform:none}
.rail__item:hover{color:var(--white)}
.rail__item.on{color:var(--lime)}
.rail__item.on span{opacity:1;transform:none}
.rail__item.on i{width:46px;background:var(--lime);box-shadow:0 0 12px rgba(172,255,41,.6)}
/* the tour ends in a white studio — the rail needs its own ground
   there, or the numbers vanish into the wall */
.rail__item b,.rail__item span{text-shadow:0 1px 10px rgba(0,0,0,.85)}
.rail::before{
  content:"";position:absolute;inset:-24px -18px;z-index:-1;pointer-events:none;
  background:radial-gradient(60% 55% at 70% 50%,rgba(4,4,4,.62),transparent 75%);
}

/* --- transport / progress --- */
.transport{
  position:absolute;left:var(--pad);right:var(--pad);
  bottom:calc(24px + env(safe-area-inset-bottom,0px));
  height:1px;background:rgba(255,255,255,.14);z-index:15;
}
/* Full width and scaled from the left edge, not a width that grows:
   the progress bar is written on every animation frame, and a width is
   layout while a transform is the compositor. */
.transport i{
  position:absolute;inset:0 auto 0 0;width:100%;background:var(--lime);
  box-shadow:0 0 10px rgba(172,255,41,.7);
  transform:scaleX(0);transform-origin:0 50%;will-change:transform;
}
.transport b{position:absolute;top:-2px;width:1px;height:5px;background:rgba(255,255,255,.3)}

/* --- mobile chapter pill --- */
.mchapter{
  display:none;position:absolute;left:50%;transform:translateX(-50%);
  bottom:calc(44px + env(safe-area-inset-bottom,0px));z-index:15;
  font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  padding:8px 15px;color:var(--white);
  background:rgba(10,10,11,.55);
  border:1px solid var(--line);
}
.mchapter b{color:var(--lime);font-weight:400;margin-right:8px}

/* ============================================================
   6. STANDARD SECTIONS
   ============================================================ */
.section{padding:clamp(80px,10vw,170px) 0;position:relative}
.section--edge{border-top:1px solid var(--line);background:var(--ink-2)}
.wrap{width:min(1360px,100% - var(--pad)*2);margin-inline:auto}
.sec__h{font-size:clamp(34px,6.4vw,92px);margin:0 0 clamp(36px,5vw,64px)}

.reveal{opacity:0;transform:translateY(26px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.reveal.in{opacity:1;transform:none}





/* ------------------------------------------------------------
   MOBILE MENU
   A sheet in three parts — mark, list, actions — so the eye has
   somewhere to start and the thumb has somewhere to land. The rows
   are hairline-separated because eight shouted words with nothing
   between them is what made the old one look unfinished.
   ------------------------------------------------------------ */
/* The sheet became a PANEL, anchored to the left edge and sliding in
   from it, over a scrim that closes the menu when you tap past it.
   Two reasons it is better than the full-screen sheet it replaces:
   the page stays visible behind it, so you never lose your place, and
   a panel that slides has a direction — it comes from somewhere and
   goes back there. */
.menu{
  position:fixed;inset:0;z-index:110;
  background:rgba(3,3,3,.72);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  opacity:0;visibility:hidden;
  transition:opacity .38s var(--ease),visibility .38s;
}
.menu[hidden]{display:block} /* we animate it; JS toggles the attribute for a11y */
body.menu-open .menu{opacity:1;visibility:visible}

/* The dimming lives on .menu; this is only the tap target, and it
   starts where the panel ends rather than running underneath it —
   a full-width button under the panel is a hit area whose centre is
   somewhere you cannot actually tap. */
.menu__scrim{
  position:absolute;top:0;bottom:0;right:0;left:min(340px,86vw);
  background:transparent;border:0;padding:0;cursor:pointer;
}

.menu__panel{
  position:absolute;top:0;bottom:0;left:0;
  width:min(340px,86vw);
  display:flex;flex-direction:column;
  background:
    radial-gradient(120% 40% at 0% 0%,rgba(172,255,41,.10),transparent 62%),
    linear-gradient(180deg,#0A0A0B,#050505 55%);
  border-right:1px solid rgba(172,255,41,.18);
  box-shadow:24px 0 60px rgba(0,0,0,.6);
  padding:calc(var(--navh,64px) + 16px) 20px calc(20px + env(safe-area-inset-bottom,0px));
  overflow-y:auto;overscroll-behavior:contain;
  transform:translate3d(-101%,0,0);
  transition:transform .36s var(--ease);
  will-change:transform;
}
body.menu-open .menu__panel{transform:translate3d(0,0,0)}

.menu__head{display:flex;align-items:center;gap:12px;padding-bottom:14px}
.menu__logo{width:44px;height:auto;flex:0 0 auto}
.menu__eyebrow{margin:0;font-size:8.5px;letter-spacing:.24em;text-transform:uppercase;color:var(--gray-dim)}

.menu__nav{display:flex;flex-direction:column;margin:auto 0}
.menu__nav a{
  display:grid;grid-template-columns:22px 1fr 14px;align-items:center;gap:10px;
  padding:11px 2px;border-bottom:1px solid rgba(255,255,255,.07);
  opacity:0;transform:translateX(-12px);
  transition:opacity .3s var(--ease),transform .3s var(--ease),
             color .28s,border-color .28s,padding-left .3s var(--ease);
}
.menu__nav a:first-child{border-top:1px solid rgba(255,255,255,.07)}
.menu__nav a small{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;color:var(--lime);opacity:.6}
.menu__nav a span{
  font-family:var(--display);font-weight:800;text-transform:uppercase;
  font-size:clamp(17px,4.8vw,23px);letter-spacing:-.02em;line-height:1;
}
.menu__nav a i{font-style:normal;color:var(--lime);opacity:0;transform:translateX(-5px);transition:.3s var(--ease)}
body.menu-open .menu__nav a{opacity:1;transform:none}
.menu__nav a:nth-child(1){transition-delay:.07s}
.menu__nav a:nth-child(2){transition-delay:.09s}
.menu__nav a:nth-child(3){transition-delay:.11s}
.menu__nav a:nth-child(4){transition-delay:.13s}
.menu__nav a:nth-child(5){transition-delay:.15s}
.menu__nav a:nth-child(6){transition-delay:.17s}
.menu__nav a:nth-child(7){transition-delay:.19s}
.menu__nav a:nth-child(8){transition-delay:.21s}
.menu__nav a:active,.menu__nav a:focus-visible{
  color:var(--lime);border-color:rgba(172,255,41,.4);padding-left:7px;
}
.menu__nav a:active i,.menu__nav a:focus-visible i{opacity:1;transform:none}

.menu__foot{
  padding-top:16px;border-top:1px solid rgba(255,255,255,.07);
  opacity:0;transform:translateX(-12px);
  transition:opacity .3s .22s var(--ease),transform .3s .22s var(--ease);
}
body.menu-open .menu__foot{opacity:1;transform:none}
.menu__acts{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.menu__cta{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  background:var(--lime);color:#080808;padding:13px 6px;
}
.menu__cta svg{width:14px;height:14px;fill:currentColor}
.menu__cta--wa{background:#25D366;color:#062B14}
.menu__label{
  font-size:8.5px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--gray-dim);margin:16px 0 10px;
}

/* ---- social buttons (menu and footer share them) ---- */
.social{display:flex;gap:9px}
.social__b{
  width:44px;height:44px;flex:0 0 auto;
  display:grid;place-items:center;border-radius:50%;
  border:1px solid var(--line-2);background:rgba(255,255,255,.03);
  transition:background .3s var(--ease),border-color .3s,transform .3s var(--ease);
}
.social__b svg{width:18px;height:18px;fill:var(--white);transition:fill .3s}
.social__b:hover,.social__b:active{background:var(--lime);border-color:var(--lime);transform:translateY(-2px)}
.social__b:hover svg,.social__b:active svg{fill:#080808}
.social__b--wa:hover,.social__b--wa:active{background:#25D366;border-color:#25D366}
.menu .social__b{width:40px;height:40px}
.menu .social__b svg{width:17px;height:17px}
.social--foot .social__b{width:40px;height:40px}
.social--foot .social__b svg{width:17px;height:17px}

/* ============================================================
   6. SECTION SYSTEM — the thing that makes the page feel like
   one piece. Every section opens the same way: eyebrow, heading,
   one sentence. Same spacing, same reveal, every time.
   ============================================================ */
.page{position:relative;background:var(--ink)}
.section{padding:clamp(84px,9.5vw,150px) 0;position:relative;z-index:1}
.section--edge{background:var(--ink-2);border-block:1px solid var(--line)}
.wrap{width:min(1360px,100% - var(--pad)*2);margin-inline:auto}

.shead{max-width:820px;margin-bottom:clamp(40px,5.2vw,72px)}
.shead__h{font-size:clamp(34px,6vw,86px);margin:0 0 22px}
.shead__lede{
  margin:0;color:var(--gray);font-size:clamp(15px,1.35vw,18px);
  line-height:1.65;max-width:62ch;
}
.sec__h{font-size:clamp(34px,6vw,86px);margin:0 0 clamp(36px,5vw,64px)}

.reveal{opacity:0;transform:translateY(26px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.reveal.in{opacity:1;transform:none}

/* ============================================================
   6a. AMBIENT BACKGROUND — the gym, moving, behind everything
   ------------------------------------------------------------
   Three cheap layers, all of them transform/opacity only so the
   compositor carries them and the main thread never sees a frame:
   two drifting lime glows (the LED wall), a faint plate grid, and
   three slow diagonal bars that read as barbells crossing the room.
   ============================================================ */
/* One screen tall, and it stays on screen.

   It used to be as tall as the whole lower page — ten thousand pixels on
   a phone — with an animated grid inset 40% beyond THAT, so the GPU was
   carrying several screens' worth of moving texture for a background
   nobody can see more than one screen of. Sticky, a viewport high, and
   pulled out of the flow with an equal negative margin: the reader sees
   exactly what they saw before, and the phone draws one screen of it. */
.bgfx{
  position:sticky;top:0;height:100vh;height:100svh;margin-bottom:-100vh;margin-bottom:-100svh;
  overflow:hidden;pointer-events:none;z-index:0;contain:strict;
}
.bgfx__glow{
  position:absolute;width:min(760px,80vw);aspect-ratio:1;border-radius:50%;
  background:radial-gradient(closest-side,rgba(172,255,41,.13),transparent 70%);
  will-change:transform;
}
.bgfx__glow--a{top:4%;left:-14%;animation:drifta 26s ease-in-out infinite alternate}
.bgfx__glow--b{top:52%;right:-18%;background:radial-gradient(closest-side,rgba(172,255,41,.10),transparent 70%);animation:driftb 32s ease-in-out infinite alternate}
@keyframes drifta{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(12vw,10vh,0) scale(1.18)}}
@keyframes driftb{from{transform:translate3d(0,0,0) scale(1.1)}to{transform:translate3d(-14vw,-12vh,0) scale(.92)}}

.bgfx__grid{
  position:absolute;inset:-40% -10%;opacity:.5;
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.028) 1px,transparent 1px);
  background-size:74px 74px;
  animation:gridpan 44s linear infinite;
}
@keyframes gridpan{from{transform:translate3d(0,0,0)}to{transform:translate3d(74px,74px,0)}}

/* the bars: long thin diagonals, like a barbell travelling the room */
.bgfx__bar{
  position:absolute;left:-30%;width:160%;height:1px;
  background:linear-gradient(90deg,transparent,rgba(172,255,41,.22),transparent);
  transform:rotate(-18deg);will-change:transform,opacity;
}
.bgfx__bar--1{top:18%;animation:barsweep 19s linear infinite}
.bgfx__bar--2{top:47%;animation:barsweep 27s linear infinite 6s}
.bgfx__bar--3{top:76%;animation:barsweep 23s linear infinite 12s}
@keyframes barsweep{
  0%{transform:translate3d(-40%,0,0) rotate(-18deg);opacity:0}
  12%{opacity:1}
  88%{opacity:1}
  100%{transform:translate3d(40%,0,0) rotate(-18deg);opacity:0}
}

/* ============================================================
   6b. MARQUEE — the band that carries the page between sections
   ------------------------------------------------------------
   Two identical sets side by side, translated by exactly -50%:
   the loop point is invisible because the second set is standing
   where the first one started.
   ============================================================ */
.marq{
  position:relative;z-index:1;overflow:hidden;
  border-block:1px solid var(--line);background:var(--ink);
  padding:clamp(16px,2vw,26px) 0;
}
.marq__row{display:flex;width:max-content;animation:marq 34s linear infinite;will-change:transform}
.marq--rev .marq__row{animation-direction:reverse}
.marq:hover .marq__row{animation-play-state:paused}
.marq__set{display:flex;align-items:center;flex:0 0 auto}
.marq__set span{
  font-family:var(--display);font-weight:800;text-transform:uppercase;
  font-size:clamp(22px,3.6vw,46px);letter-spacing:-.02em;line-height:1;
  padding:0 clamp(16px,2vw,30px);
  color:transparent;-webkit-text-stroke:1px rgba(244,244,241,.26);
}
.marq--rev .marq__set span{-webkit-text-stroke-color:rgba(172,255,41,.32)}
.marq__set i{width:7px;height:7px;flex:0 0 auto;background:var(--lime);transform:rotate(45deg);opacity:.75}
@keyframes marq{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}

/* ============================================================
   6c. ABOUT
   ============================================================ */
.about{display:grid;grid-template-columns:.85fr 1.15fr;gap:clamp(34px,5vw,80px);align-items:center}
.about__mark{position:relative;max-width:380px;justify-self:center}
.about__mark img{
  position:relative;z-index:1;width:100%;height:auto;
  filter:drop-shadow(0 0 60px rgba(172,255,41,.18));
  animation:markfloat 9s ease-in-out infinite alternate;
}
@keyframes markfloat{from{transform:translateY(-6px)}to{transform:translateY(6px)}}
/* A circle centred on the mark, with NO centring transform.
   `aspect-ratio` plus `translate(-50%,-50%)` asks the engine to resolve
   a percentage transform against a height it derived from a width, and
   engines disagree about when that height is known — which is how this
   ring ended up sitting to the right of the logo on a phone while it
   was perfectly centred on a desktop. Here the square comes from
   `padding-bottom` and the centring from negative margins; BOTH resolve
   against the parent's width, so there is nothing left to disagree
   about, and the transform is free to carry the pulse alone. */
.about__ring{
  position:absolute;left:50%;top:50%;
  width:112%;height:0;padding-bottom:112%;
  margin-left:-56%;margin-top:-56%;
  border-radius:50%;
  border:1px solid rgba(172,255,41,.18);
  animation:ringpulse 6s ease-in-out infinite;
}
@keyframes ringpulse{0%,100%{transform:scale(1);opacity:.45}50%{transform:scale(1.05);opacity:.95}}

.stats{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--line);border-left:1px solid var(--line)}
.stat{padding:clamp(20px,2.2vw,30px);border-right:1px solid var(--line);border-bottom:1px solid var(--line)}
.stat.reveal{transition-delay:calc(var(--i,0)*.09s)}
.stat__n{
  display:block;font-family:var(--display);font-weight:800;line-height:1;
  font-size:clamp(34px,4vw,54px);letter-spacing:-.03em;color:var(--lime);
  font-variant-numeric:tabular-nums;
}
.stat__k{display:block;margin-top:10px;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--gray-dim)}

.facts{margin:clamp(24px,3vw,40px) 0 0;display:grid;border-top:1px solid var(--line)}
.facts>div{display:grid;grid-template-columns:130px 1fr;gap:20px;padding:18px 0;border-bottom:1px solid var(--line);transition:background .35s var(--ease)}
.facts>div:hover{background:var(--ink-3)}
.facts dt{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--gray-dim)}
.facts dd{margin:0;font-size:14.5px;color:rgba(244,244,241,.86)}

/* ============================================================
   6d. TRAINING TILES
   ------------------------------------------------------------
   The old ones were six flat boxes with a number. These carry a
   ghost numeral, an icon and a rule that draws itself across the
   bottom on hover — the same rule the pricing cards use, so the
   two sections read as the same family.
   ============================================================ */
.tiles{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--line);border-left:1px solid var(--line)}
.tile{
  position:relative;overflow:hidden;
  border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:clamp(28px,3vw,46px);
  transition:background .45s var(--ease),transform .5s var(--ease);
}
.tile.reveal{transition-delay:calc(var(--i,0)*.07s)}
/* Top-right and clipped by the tile's own overflow. Sitting at the
   bottom it landed square on the paragraph, which is the one thing a
   decorative numeral must never do. */
.tile__ghost{
  position:absolute;right:-14px;top:-30px;pointer-events:none;
  font-family:var(--display);font-weight:900;font-size:clamp(84px,8vw,132px);
  line-height:1;color:transparent;-webkit-text-stroke:1px rgba(255,255,255,.055);
  transition:transform .6s var(--ease),-webkit-text-stroke-color .5s;
}
.tile__ico{
  display:grid;place-items:center;width:46px;height:46px;
  border:1px solid var(--line-2);color:var(--lime);margin-bottom:24px;
  transition:background .4s var(--ease),color .4s,border-color .4s,transform .5s var(--ease);
}
.tile__ico svg{width:22px;height:22px}
.tile__n{display:block;font-size:10px;letter-spacing:.2em;color:var(--lime);margin-bottom:12px}
.tile__h{
  position:relative;font-family:var(--display);font-weight:700;text-transform:uppercase;
  font-size:clamp(18px,1.8vw,24px);letter-spacing:-.01em;margin:0 0 12px;
}
.tile__p{position:relative;margin:0;color:var(--gray);font-size:14.5px;line-height:1.65;max-width:38ch}
.tile__rule{position:absolute;left:0;bottom:0;height:2px;width:0;background:var(--lime);transition:width .6s var(--ease)}
.tile:hover{background:var(--ink-3)}
.tile:hover .tile__rule{width:100%}
.tile:hover .tile__ico{background:var(--lime);color:#080808;border-color:var(--lime);transform:translateY(-3px)}
.tile:hover .tile__ghost{transform:translateY(8px);-webkit-text-stroke-color:rgba(172,255,41,.18)}

/* ============================================================
   6e. PRICING
   ------------------------------------------------------------
   Six plans, and the only honest comparison is by the month —
   which is why every card states its own per-month figure instead
   of leaving somebody to divide 4,490 by 12 in their head.
   ============================================================ */
.plans{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.5vw,22px)}
.plan{
  position:relative;display:flex;flex-direction:column;overflow:hidden;
  background:var(--ink-3);border:1px solid var(--line);
  padding:clamp(26px,2.4vw,36px);
  transition:transform .55s var(--ease),border-color .45s,background .45s,box-shadow .55s var(--ease);
}
.plan.reveal{transition-delay:calc(var(--i,0)*.07s)}
.plan__top{position:absolute;left:0;top:0;height:2px;width:0;background:var(--lime);transition:width .7s var(--ease)}
.plan.in .plan__top{width:100%;transition-delay:calc(var(--i,0)*.07s + .25s)}
.plan::before{
  content:"";position:absolute;top:0;left:-140%;width:60%;height:100%;
  background:linear-gradient(100deg,transparent,rgba(172,255,41,.13),transparent);
  transform:skewX(-18deg);transition:left .85s var(--ease);pointer-events:none;
}
.plan:hover{transform:translateY(-8px);border-color:rgba(172,255,41,.5);background:var(--ink-4);box-shadow:0 34px 80px rgba(0,0,0,.62)}
.plan:hover::before{left:130%}
.plan__head{display:flex;flex-direction:column;gap:16px;margin-bottom:18px}
.plan__tag{
  align-self:flex-start;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--lime);border:1px solid rgba(172,255,41,.3);padding:5px 10px;
}
.plan__name{
  font-family:var(--display);font-weight:700;text-transform:uppercase;
  font-size:clamp(18px,1.8vw,24px);letter-spacing:-.01em;margin:0;
}
.plan__price{display:flex;align-items:baseline;gap:8px;margin:0}
.plan__num{
  font-family:var(--display);font-weight:800;line-height:1;
  font-size:clamp(42px,4.4vw,62px);letter-spacing:-.035em;font-variant-numeric:tabular-nums;
}
.plan__price small{font-size:10px;letter-spacing:.2em;color:var(--gray-dim)}
.plan__per{margin:10px 0 0;font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--lime);opacity:.85}
.plan__desc{margin:16px 0 22px;color:var(--gray);font-size:14px;line-height:1.6}
.plan__list{list-style:none;margin:0 0 28px;padding:0;display:grid;gap:10px}
.plan__list li{position:relative;padding-left:20px;font-size:13.5px;color:rgba(244,244,241,.8)}
.plan__list li::before{content:"";position:absolute;left:0;top:.55em;width:8px;height:1px;background:var(--lime)}
.plan__go{
  margin-top:auto;display:inline-flex;align-items:center;justify-content:center;gap:10px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  border:1px solid var(--line-2);padding:14px 16px;
  transition:background .35s var(--ease),color .35s,border-color .35s;
}
.plan__goIco{display:inline-flex}
.plan__goIco svg{width:15px;height:15px;fill:#25D366;transition:fill .35s}
.plan:hover .plan__go{background:#25D366;border-color:#25D366;color:#062B14}
.plan:hover .plan__goIco svg{fill:#062B14}

.plan--best{border-color:rgba(172,255,41,.45);background:var(--ink-4)}
.plan--best .plan__tag{background:var(--lime);color:#080808;border-color:var(--lime)}
.plan--best .plan__num{color:var(--lime)}
.plan--best::after{
  content:"";position:absolute;inset:-1px;pointer-events:none;
  border:1px solid rgba(172,255,41,.28);animation:bestpulse 3.4s ease-in-out infinite;
}
@keyframes bestpulse{0%,100%{opacity:.25}50%{opacity:.85}}
.plans__note{margin:clamp(24px,3vw,38px) 0 0;font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--gray-dim)}

/* ============================================================
   6f. JOIN
   ============================================================ */
.join{text-align:center;overflow:hidden}
.join__bg{
  position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(58% 70% at 50% 100%,rgba(172,255,41,.16),transparent 70%);
  animation:joinbreathe 7s ease-in-out infinite alternate;
}
@keyframes joinbreathe{from{opacity:.6;transform:scale(1)}to{opacity:1;transform:scale(1.08)}}
.join__in{position:relative;z-index:1}
.join .eyebrow{display:block}
.join__h{font-size:clamp(38px,8vw,120px);margin:0 0 22px}
.join__lede{margin:0 auto;max-width:52ch;color:var(--gray);font-size:clamp(15px,1.3vw,17px);line-height:1.65}
.join__tel{
  display:inline-block;margin-top:30px;
  font-family:var(--display);font-weight:800;letter-spacing:-.02em;
  font-size:clamp(26px,4vw,50px);
  background-image:linear-gradient(var(--lime),var(--lime));
  background-repeat:no-repeat;background-position:0 100%;background-size:0 2px;
  transition:background-size .5s var(--ease),color .35s;
}
.join__tel:hover{color:var(--lime);background-size:100% 2px}
.btns{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-top:34px}
.btn__ico{display:inline-flex;margin-right:9px}
.btn__ico svg{width:15px;height:15px;fill:currentColor}
.btn--wa{border-color:rgba(37,211,102,.45);color:#EAFBF0}
.btn--wa:hover{background:#25D366;border-color:#25D366;color:#062B14}

/* ============================================================
   6g. CONTACT
   ------------------------------------------------------------
   The old version was a column of seven rows you had to read to
   the end of. These are targets: one tap each, labelled, with the
   address and the hours kept together beside them.
   ============================================================ */
.contact{display:grid;grid-template-columns:1.25fr .95fr;gap:clamp(18px,2vw,28px);align-items:stretch}
.ctiles{display:grid;grid-template-columns:repeat(3,1fr);grid-auto-rows:1fr;border-top:1px solid var(--line);border-left:1px solid var(--line)}
.ctile{
  position:relative;display:flex;flex-direction:column;justify-content:center;gap:10px;
  border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:clamp(22px,2.2vw,30px);
  transition:background .4s var(--ease),transform .45s var(--ease);
}
.ctile.reveal{transition-delay:calc(var(--i,0)*.06s)}
.ctile__ico{display:grid;place-items:center;width:40px;height:40px;border:1px solid var(--line-2);color:var(--lime);transition:.4s var(--ease)}
.ctile__ico svg{width:19px;height:19px;fill:currentColor}
.ctile__k{font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--gray-dim);font-weight:400}
.ctile__v{
  font-family:var(--display);font-weight:600;font-size:clamp(14px,1.15vw,17px);
  letter-spacing:-.005em;word-break:break-word;
}
.ctile__go{position:absolute;top:16px;right:16px;font-style:normal;color:var(--lime);opacity:0;transform:translate(-4px,4px);transition:.35s var(--ease)}
.ctile:hover{background:var(--ink-3);transform:translateY(-3px)}
.ctile:hover .ctile__ico{background:var(--lime);color:#080808;border-color:var(--lime)}
.ctile:hover .ctile__go{opacity:1;transform:none}
.ctile--wa:hover .ctile__ico{background:#25D366;border-color:#25D366;color:#062B14}

.cwhere{border:1px solid var(--line);background:var(--ink);overflow:hidden}
.cwhere__map{
  position:relative;display:grid;place-items:center;aspect-ratio:16/9;
  background:linear-gradient(140deg,#0E0F0C,#141712 60%,#0A0B09);
  border-bottom:1px solid var(--line);overflow:hidden;
}
.cwhere__grid{
  position:absolute;inset:-20%;
  background-image:
    linear-gradient(rgba(172,255,41,.08) 1px,transparent 1px),
    linear-gradient(90deg,rgba(172,255,41,.08) 1px,transparent 1px);
  background-size:36px 36px;
  animation:gridpan 30s linear infinite;
}
.cwhere__pin{position:relative;z-index:1;color:var(--lime);display:grid;place-items:center}
.cwhere__pin svg{width:44px;height:44px;fill:currentColor;filter:drop-shadow(0 0 18px rgba(172,255,41,.5))}
.cwhere__pin::after{
  content:"";position:absolute;width:64px;height:64px;border-radius:50%;
  border:1px solid rgba(172,255,41,.5);animation:pinping 2.6s var(--ease) infinite;
}
@keyframes pinping{0%{transform:scale(.6);opacity:.9}70%{transform:scale(1.7);opacity:0}100%{opacity:0}}
.cwhere__body{padding:clamp(22px,2.2vw,30px)}
.cwhere__body b{display:block;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--gray-dim);font-weight:400;margin-bottom:8px}
.cwhere__body b+p{margin:0 0 22px;font-size:14.5px;line-height:1.65;color:rgba(244,244,241,.86)}
.cwhere__body strong{color:var(--lime);font-weight:600}
.cwhere__cta{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--lime);border-bottom:1px solid rgba(172,255,41,.35);padding-bottom:5px;
  transition:gap .3s var(--ease)
}
.cwhere__cta:hover{gap:14px}
.cwhere__cta i{font-style:normal}

/* ============================================================
   6h. FOOTER
   ============================================================ */
.foot{position:relative;z-index:1;border-top:1px solid var(--line);background:var(--ink-2);padding:clamp(52px,6vw,84px) 0 0}
.foot__top{display:grid;grid-template-columns:1.6fr 1fr 1fr 1.2fr;gap:clamp(28px,3vw,56px)}
.foot__brand img{width:64px;height:auto;display:block}
.foot__tag{margin:16px 0 0;font-size:9.5px;letter-spacing:.24em;text-transform:uppercase;color:var(--lime)}
.foot__blurb{margin:14px 0 22px;color:var(--gray);font-size:14px;line-height:1.65;max-width:34ch}
.social--foot{display:flex;gap:9px}
.foot__col{display:flex;flex-direction:column;align-items:flex-start;gap:12px}
.foot__k{font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--gray-dim);font-weight:400;margin-bottom:4px}
.foot__col a{font-size:14px;color:rgba(244,244,241,.78);transition:color .3s,transform .3s var(--ease)}
.foot__col a:hover{color:var(--lime);transform:translateX(3px)}
.foot__open{display:inline-flex;align-items:center;gap:9px;font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--gray-dim)}
.foot__open i{width:7px;height:7px;border-radius:50%;background:var(--lime);position:relative}
/* the pulse is a ring that scales and fades — the compositor's job —
   rather than an animated box-shadow, which is a repaint every frame */
.foot__open i::after{content:"";position:absolute;inset:0;border-radius:50%;background:rgba(172,255,41,.55);animation:livedot 2.4s ease-out infinite}
@keyframes livedot{0%{transform:scale(1);opacity:.8}70%{transform:scale(3.6);opacity:0}100%{transform:scale(3.6);opacity:0}}
.foot__bar{
  margin-top:clamp(38px,4vw,60px);padding:22px 0;border-top:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;
}
.foot__bar p{margin:0;font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--gray-dim)}
/* Unilira credit: the U mark, "Proudly powered by", Unilira */
.by{display:inline-flex;align-items:center;gap:12px;color:rgba(244,244,241,.66);font:400 15px/1 "Inter",system-ui,sans-serif;letter-spacing:0;text-transform:none;white-space:nowrap;transition:color .3s}
.by__mark{width:auto;height:30px;color:#fff;flex:0 0 auto;transition:color .3s}
.by__n{font:700 17px/1 "Archivo","Inter",system-ui,sans-serif;color:#fff;letter-spacing:-.01em;transition:color .3s}
.by:hover .by__mark,.by:hover .by__n{color:var(--lime)}
.by:focus-visible{outline:2px solid var(--lime);outline-offset:6px;border-radius:6px}

/* ============================================================
   6i. SOUND TOGGLE — four bars that dance while it plays
   ============================================================ */
.sound{
  width:40px;height:40px;flex:0 0 auto;position:relative;
  display:grid;place-items:center;border:1px solid var(--line-2);
  transition:border-color .35s,background .35s var(--ease);
}
.sound:hover{border-color:var(--lime)}
.sound__bars{display:flex;align-items:flex-end;gap:2.5px;height:15px}
.sound__bars i{width:2.5px;background:var(--gray);height:15px;transform:scaleY(.27);transform-origin:50% 100%;transition:background .35s}
.sound[aria-pressed="true"]{border-color:rgba(172,255,41,.55)}
.sound[aria-pressed="true"] .sound__bars i{background:var(--lime);animation:eq .9s ease-in-out infinite alternate}
.sound[aria-pressed="true"] .sound__bars i:nth-child(1){animation-delay:0s}
.sound[aria-pressed="true"] .sound__bars i:nth-child(2){animation-delay:.18s}
.sound[aria-pressed="true"] .sound__bars i:nth-child(3){animation-delay:.36s}
.sound[aria-pressed="true"] .sound__bars i:nth-child(4){animation-delay:.1s}
/* scaleY, not height: the bars used to be four layouts a frame for as
   long as the music played, anywhere on the page */
@keyframes eq{from{transform:scaleY(.2)}to{transform:scaleY(1)}}
/* still while the page scrolls (script.js sets it) */
.sound.is-held .sound__bars i{animation-play-state:paused}
/* the slash that says "muted" — gone the moment it plays */
.sound__off{
  position:absolute;width:22px;height:1.5px;background:var(--gray);
  transform:rotate(-45deg);transition:opacity .3s,background .35s;
}
.sound:hover .sound__off{background:var(--white)}
.sound[aria-pressed="true"] .sound__off{opacity:0}
/* a one-shot ring the first time it can be turned on, so the button
   is noticed without anything making noise on its own */
.sound.is-hint::after{
  content:"";position:absolute;inset:-1px;border:1px solid var(--lime);
  animation:soundhint 2s var(--ease) 3;
}
@keyframes soundhint{0%{opacity:.9;transform:scale(1)}70%{opacity:0;transform:scale(1.5)}100%{opacity:0}}

/* ============================================================
   6j. BUTTONS · FACILITY CARDS · FLOATING WHATSAPP
   ============================================================ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  border:1px solid var(--line-2);padding:16px 30px;white-space:nowrap;
  transition:background .35s var(--ease),color .35s,border-color .35s;
}
.btn:hover{background:rgba(255,255,255,.06);border-color:var(--white)}
.btn--solid{background:var(--lime);border-color:var(--lime);color:#080808}
.btn--solid:hover{background:#BFFF52;border-color:#BFFF52;color:#080808}

.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,24px)}
.card{
  position:relative;overflow:hidden;background:var(--ink-3);
  border:1px solid var(--line);transform-style:preserve-3d;will-change:transform;
  transition:border-color .45s,box-shadow .55s var(--ease),transform .5s var(--ease);
}
.card:hover{border-color:rgba(172,255,41,.5);box-shadow:0 30px 70px rgba(0,0,0,.6)}
.card__img{overflow:hidden;aspect-ratio:16/9;background:#000}
.card__img img{
  width:100%;height:100%;object-fit:cover;display:block;
  filter:saturate(.92) brightness(.94);
  transition:transform .8s var(--ease),filter .6s var(--ease);
}
.card:hover .card__img img{transform:scale(1.06);filter:saturate(1.05) brightness(1)}
.card__body{position:relative;padding:clamp(20px,2.1vw,30px)}
.card{cursor:pointer}
.card:focus-visible{outline:2px solid var(--lime);outline-offset:3px}
.card__body b{font-size:10px;letter-spacing:.2em;color:var(--lime);display:block;margin-bottom:14px}

/* A card that jumps you into the footage should say so. The badge sits
   on the picture, always visible on a touch screen (where there is no
   hover to reveal it) and arriving on hover on a desktop. */
.card__watch{
  position:absolute;top:12px;left:12px;z-index:2;
  display:inline-flex;align-items:center;gap:7px;
  font-family:var(--mono);font-size:9px;letter-spacing:.16em;text-transform:uppercase;
  color:#080808;background:var(--lime);padding:6px 10px;
  opacity:0;transform:translateY(-6px);
  transition:opacity .35s var(--ease),transform .35s var(--ease);
  pointer-events:none;
}
.card__watch svg{width:11px;height:11px;fill:currentColor}
.card:hover .card__watch,.card:focus-visible .card__watch{opacity:1;transform:none}
@media (hover:none){
  /* no tilt on a touch screen, so no 3D context either */
  .card{transform-style:flat;cursor:default}
  /* the label is the button here (see the [data-go] handler in script.js) */
  .card__watch{opacity:.94;transform:none;font-size:10px;padding:9px 13px;pointer-events:auto;cursor:pointer}
  /* a thumb-sized target around the label, since it is now the only
     part of the card that jumps to the walkthrough */
  .card__watch::after{content:"";position:absolute;inset:-10px -12px}
}
.card__body h3{
  font-family:var(--display);font-weight:700;text-transform:uppercase;
  font-size:clamp(17px,1.7vw,23px);letter-spacing:-.01em;margin:0 0 10px;
  transition:letter-spacing .45s var(--ease);
}
.card:hover .card__body h3{letter-spacing:.01em}
.card__body p{margin:0;color:var(--gray);font-size:14px;line-height:1.6}
.card--bright .card__img img{filter:saturate(.9) brightness(1.02)}

.wafab{
  position:fixed;z-index:115;
  right:calc(var(--pad) * .6);bottom:calc(22px + env(safe-area-inset-bottom,0px));
  width:56px;height:56px;border-radius:50%;
  display:grid;place-items:center;background:#25D366;
  box-shadow:0 14px 34px rgba(0,0,0,.5),0 0 0 1px rgba(255,255,255,.08) inset;
  transition:transform .35s var(--ease),box-shadow .35s var(--ease),
             opacity .35s var(--ease),visibility .35s;
}
.wafab svg{width:28px;height:28px;fill:#062B14;position:relative;z-index:1}
.wafab:hover{transform:scale(1.07);box-shadow:0 18px 44px rgba(37,211,102,.4)}
/* over the cinematic stage and behind the open menu it stays out of
   the way — it is the page's button, not the film's */
body.in-tour .wafab,body.menu-open .wafab,body.at-foot .wafab{
  opacity:0;transform:scale(.7);pointer-events:none;visibility:hidden;
}
.wafab__pulse{
  position:absolute;inset:0;border-radius:50%;border:2px solid rgba(37,211,102,.6);
  animation:wapulse 2.6s var(--ease) infinite;
}
/* while the button is put away, so is its ring */
body.in-tour .wafab__pulse,body.menu-open .wafab__pulse,body.at-foot .wafab__pulse{animation:none}
@keyframes wapulse{
  0%{transform:scale(1);opacity:.7}
  70%{transform:scale(1.75);opacity:0}
  100%{transform:scale(1.75);opacity:0}
}
@media (prefers-reduced-motion:reduce){.wafab__pulse{display:none}}

/* ============================================================
   7. RESPONSIVE
   ============================================================ */
@media (max-width:1180px){
  .grid--3{grid-template-columns:repeat(2,1fr)}
  .cards{grid-template-columns:repeat(2,1fr)}
  .tiles{grid-template-columns:repeat(2,1fr)}
  .contact{grid-template-columns:1fr}
  .ctiles{grid-template-columns:repeat(3,1fr)}
  .foot__top{grid-template-columns:1fr 1fr;gap:36px}
  .foot__brand{grid-column:1/-1}
}

/* Plan columns are a question about width, not about which cut of the
   cinematic stage a device gets — an upright tablet is 820px wide and
   holds two plans comfortably even though it takes the phone layout
   everywhere else. Kept as one ladder so the order is obvious. */
@media (max-width:1180px){.plans{grid-template-columns:repeat(2,1fr)}}
@media (max-width:720px) {.plans{grid-template-columns:1fr}}

@media (max-width:960px){
  .nav__links,.nav__cta{display:none}
  .about{grid-template-columns:1fr}
  .about__mark{max-width:260px}
  .nav__burger{display:block}
  .about{grid-template-columns:1fr;gap:40px}
  .about__mark{max-width:300px}
  .rail{display:none}
  .mchapter{display:block}
  .hud__tr{display:none}
}

/* ============================================================
   PHONES — one fullscreen cinematic frame, everything on it
   ------------------------------------------------------------
   The earlier build letterboxed the 16:9 master into a portrait
   screen, which left the footage small, the copy stranded on
   black below it, and the HUD floating in the middle of nowhere.
   A phone gets a real full-bleed frame instead: the walkthrough
   was shot on a very wide lens, so the centre of every frame
   already holds the room — a centred cover crop keeps the
   equipment and throws away the barrel-distorted edges.
   ============================================================ */
/* A tablet held upright crops the wide frame just as hard as a phone
   does, so it gets the same cut rather than a third layout to keep
   in step. Anything landscape and wider stays on the desktop rules. */
@media (max-width:768px), (max-width:1024px) and (orientation:portrait){

  /* upright tablets sit above the 960px breakpoint, so claim the
     phone chrome here too rather than widening that one */
  .nav__links,.nav__cta{display:none}
  .nav__burger{display:block}
  .rail{display:none}
  .hud__tr{display:none}
  .mchapter{display:block}

  /* ---- ordinary page sections ---- */
  .grid--3{grid-template-columns:1fr}
  .shead{margin-bottom:32px}
  .shead__h{margin-bottom:16px}
  .shead__lede{font-size:15px}

  /* two columns, not one: six one-per-row tiles is a minute of
     scrolling that says the same thing six times */
  .tiles{grid-template-columns:repeat(2,1fr)}
  .tile{padding:20px 16px}
  .tile__ico{width:38px;height:38px;margin-bottom:16px}
  .tile__ico svg{width:19px;height:19px}
  .tile__h{font-size:15px}
  .tile__p{font-size:13px;line-height:1.55}
  .tile__ghost{font-size:70px;top:-20px;right:-8px}

  .about{gap:26px}
  .about__mark{max-width:190px;margin-inline:auto}
  .stats{grid-template-columns:1fr;}
  .stat{display:flex;align-items:baseline;gap:14px;padding:16px 18px}
  .stat__n{font-size:30px}
  .stat__k{margin-top:0}
  .facts>div{grid-template-columns:1fr;gap:6px;padding:16px 0}

  .ctiles{grid-template-columns:repeat(2,1fr)}
  .ctile{padding:18px 16px;gap:8px}
  .ctile__ico{width:34px;height:34px}
  .ctile__ico svg{width:17px;height:17px}
  .ctile__v{font-size:13.5px}
  .ctile__go{display:none}
  .cwhere__map{aspect-ratio:2/1}

  .join__tel{font-size:clamp(24px,7.4vw,34px);margin-top:22px}
  .join__lede{font-size:14.5px}

  .marq{padding:14px 0}
  .marq__set span{font-size:26px;padding:0 14px}

  .foot{padding-top:48px}
  .foot__top{grid-template-columns:1fr 1fr;gap:26px}
  .foot__brand{grid-column:1/-1}
  .foot__bar{justify-content:flex-start;gap:10px}

  /* Facilities as a swipeable rail. Stacked, six tall cards were a
     minute of scrolling that said the same thing six times; side by
     side with snap points it reads as one shelf you flick through.
     No JS drives the scrolling — the browser does, so it stays at
     60fps on a cheap phone. The dots below only mirror it. */
  .cards{
    display:flex;grid-template-columns:none;
    gap:14px;overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    /* bleed to the screen edges, so a card can sit flush while the
       first and last still line up with the text above them */
    margin-inline:calc(var(--pad) * -1);
    padding:2px var(--pad) 4px;
    scrollbar-width:none;
  }
  .cards::-webkit-scrollbar{display:none}
  .card{
    flex:0 0 78%;max-width:340px;scroll-snap-align:center;
    transform:none!important;
  }
  .card__img{aspect-ratio:4/3}
  .sdots{
    display:flex;gap:7px;justify-content:center;margin-top:18px;
  }
  .sdots b{
    width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.22);
    transition:background .3s var(--ease),width .3s var(--ease);
  }
  .sdots b.on{background:var(--lime);width:18px;border-radius:3px}

  .facts>div{grid-template-columns:1fr;gap:6px}
  .contact__row{grid-template-columns:1fr;gap:6px;padding-block:18px}
  .contact__row span small{font-size:13px;margin-top:5px}
  .contact__row i{display:none}
  a.contact__row:hover{padding-left:0}
  .btns{flex-direction:column}
  .btn{width:100%}
  .lede{font-size:15px}

  /* ---- compact nav: logo + burger, ~64px, no wasted height ----
     The links carry `margin-inline:auto` to centre them on a desktop,
     and they are display:none here — so without this the bar packs
     everything against the left edge and the burger lands in the
     middle of the screen. */
  :root{--navh:64px}
  .nav{justify-content:space-between}
  .sound{margin-left:auto}
  .nav{padding:14px 20px;gap:12px}
  .nav__brand img{width:36px}
  .nav.is-solid .nav__brand img{transform:none}
  .nav__word{font-size:11.5px;letter-spacing:.14em}
  .nav__burger{width:34px;height:34px;margin-left:2px}
  .sound{width:36px;height:36px}
  .sound__bars{height:13px;gap:2px}
  .sound__bars i{width:2px}
  .sound__off{width:19px}
  .nav__burger i{left:6px;right:6px}
  .nav__burger i:nth-child(1){top:13px}
  .nav__burger i:nth-child(2){bottom:13px}

  /* ---- the stage IS the screen ---- */
  .track{height:720vh;height:720svh;height:calc(var(--sv,1svh) * 720)}
  .stage{height:100vh;height:100svh}
  .frame__video,.frame__poster{
    object-fit:cover;object-position:50% 50%;
    width:100%;max-width:none;left:0;right:auto;
  }
  /* the tour ends in a white studio, so the bottom scrim carries a
     little more weight than on desktop — the copy has to hold on a
     bright wall as well as on a dark shell */
  .atmo::after{
    opacity:calc(.62 - var(--warm)*.24);
    background:
      linear-gradient(180deg,rgba(5,5,5,.66),transparent 22%),
      linear-gradient(0deg,rgba(5,5,5,.9),rgba(5,5,5,.4) 30%,transparent 56%);
  }
  /* a full-screen animated grain layer is a whole extra composited
     surface on every scrubbed frame, and at phone pixel density
     nobody can see it. Smoothness is worth more than texture. */
  .grain{display:none}

  /* ---- every word stays ON the footage ----
     .layer is absolute inset:0 already, so none of this can add a
     single pixel to the document: the copy sits in the lower third
     of the frame and the scroll track stays a pure timeline. */
  .layer{
    padding:calc(var(--navh) + 14px) 20px calc(13svh + env(safe-area-inset-bottom,0px));
    align-items:flex-end;justify-content:flex-start;text-align:left;
  }
  .layer--left,.layer--right,.layer--bl{align-items:flex-end;justify-content:flex-start;text-align:left}
  .layer--right .lede,.layer--right .chips{margin-left:0}
  .layer--right .chips{justify-content:flex-start}
  /* .layer--center is a COLUMN flex box, so "push it to the
     bottom" is justify-content, not align-items */
  .layer--center{justify-content:flex-end;align-items:stretch;text-align:left}
  /* width, not just max-width: the inner block is a flex child, so
     without it the copy shrink-wraps and every `max-width:%` inside
     resolves against a box that has no width of its own yet — which
     is what breaks "Increase energy." across two lines */
  .layer__in{max-width:100%;width:100%}
  /* one scrim shape on a phone: bottom-up, so copy always lands on
     ground and the top two-thirds of the room stays clean */
  .layer--left::before,.layer--right::before,.layer--bl::before,.layer--center::before{
    background:linear-gradient(0deg,rgba(4,4,4,.9),rgba(4,4,4,.5) 36%,transparent 66%);
  }
  .layer[data-chapter="7"]::before{
    background:linear-gradient(0deg,rgba(4,4,4,.94),rgba(4,4,4,.6) 40%,transparent 72%);
  }

  /* ---- mobile cinematic type ---- */
  .hero__title{font-size:clamp(42px,13vw,72px);line-height:.86}
  .sec__title{font-size:clamp(34px,11vw,62px);line-height:.88}
  .display{overflow-wrap:break-word}
  .layer .eyebrow{font-size:9.5px;letter-spacing:.2em;margin-bottom:12px}
  .hero__sub{font-size:10px;letter-spacing:.26em;margin-top:14px}
  .layer .lede{font-size:14.5px;line-height:1.55;max-width:90%;margin-top:12px}
  .layer--hero .lede{max-width:90%}
  /* The keyword chips are the widest, boxiest thing in the copy and
     they only repeat what the line above already says. Dropping them
     on a phone buys back the band the equipment labels need, and
     leaves the frame with a headline and one sentence — which is the
     whole point of the mobile cut. They stay on desktop. */
  .layer .chips{display:none}
  .hint{margin-top:22px;font-size:9px;letter-spacing:.2em;gap:10px}
  .hint__line{height:26px}

  /* ---- HUD rides the bottom of the frame, not a black band ---- */
  .mchapter{
    bottom:calc(52px + env(safe-area-inset-bottom,0px));
    font-size:9.5px;letter-spacing:.18em;padding:7px 13px;
  }
  .transport{
    left:20px;right:20px;height:2px;
    bottom:calc(26px + env(safe-area-inset-bottom,0px));
  }
  .transport b{top:-1px;height:4px}

  /* ---- about: the mark was eating a whole screen ---- */
  .about{gap:26px}
  .about__mark{max-width:150px;margin-inline:auto}
  .about__mark img{filter:drop-shadow(0 0 40px rgba(172,255,41,.14))}
  .about__copy{text-align:left}
  .facts{margin-top:30px}

  /* ---- pricing: a swipeable rail, like the facilities shelf ----
     Six stacked plan cards is four screens of scrolling to compare
     six numbers, and comparing them is the whole point of a price
     list. Side by side with snap points they are one flick apart.
     The scrolling is the browser's — `scroll-snap-type` and nothing
     else — so a flick never touches the main thread. */
  .plans{
    display:flex;grid-template-columns:none;
    gap:12px;overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    margin-inline:calc(var(--pad) * -1);
    padding:2px var(--pad) 6px;
    scrollbar-width:none;
  }
  .plans::-webkit-scrollbar{display:none}
  .plan{
    flex:0 0 82%;max-width:330px;scroll-snap-align:center;
    padding:24px 20px;transform:none!important;
  }
  .plan.reveal{transition-delay:calc(var(--i,0) * .04s)}
  .plan__per{margin-top:8px}
  .plan__num{font-size:42px}
  .plan__list{margin-bottom:20px}
  /* no hover on a touch screen: the sheen and the lift would only
     ever fire on tap-and-hold, so the card states its colours flat */
  .plan__go{padding:14px 16px;background:rgba(37,211,102,.1);border-color:rgba(37,211,102,.4)}
  .plan--best{box-shadow:0 0 0 1px rgba(172,255,41,.35)}
  .plans__note{margin-top:14px;text-align:center}
  /* ---- the floating button clears the transport bar ---- */
  .wafab{
    right:16px;width:52px;height:52px;
    bottom:calc(18px + env(safe-area-inset-bottom,0px));
  }
  .wafab svg{width:26px;height:26px}

  /* ---- markers: all of them (never more than two at once), but
     quieter — a hairline and a whisper of type, not a card ---- */
  .mark i{width:7px;height:7px}
  .mark i::after{inset:-5px}
  .mark span{
    font-size:9px;letter-spacing:.1em;padding:4px 7px 4px 0;
    text-shadow:0 1px 7px rgba(0,0,0,.95),0 0 18px rgba(0,0,0,.75);
  }
  .mark i{box-shadow:0 0 10px rgba(172,255,41,.55)}
  .mark span::before{width:18px;margin-right:6px}
  .mark--flip span{padding:4px 0 4px 7px}
  .mark--flip span::before{margin:0 0 0 6px}
}

/* Phone on its side: the screen is now shorter than the nav and the
   copy were sized for, so both give height back rather than pushing
   the sentence off the bottom of the frame. */
@media (max-height:500px) and (orientation:landscape){
  :root{--navh:54px}
  .nav{padding:10px var(--pad)}
  .nav__brand img{width:30px}
  .layer{padding-top:calc(var(--navh) + 10px);padding-bottom:calc(13svh + 12px)}
  .hero__title{font-size:clamp(28px,5.6vw,46px)}
  .sec__title{font-size:clamp(26px,5vw,42px)}
  .layer .lede{font-size:13.5px;margin-top:8px}
  .hint{display:none}
  .mchapter{bottom:calc(38px + env(safe-area-inset-bottom,0px))}
  .transport{bottom:calc(18px + env(safe-area-inset-bottom,0px))}
}

/* Short screens — an SE, or any phone with the browser chrome showing.
   The menu is the one full-height thing on the site, so it is the one
   thing that has to give height back rather than scroll. */
@media (max-height:720px){
  .menu__panel{padding-top:calc(var(--navh,64px) + 8px);padding-bottom:calc(14px + env(safe-area-inset-bottom,0px))}
  .menu__head{padding-bottom:10px}
  .menu__logo{width:38px}
  .menu__nav a{padding:8px 2px}
  .menu__nav a span{font-size:clamp(16px,4.4vw,21px)}
  .menu__foot{padding-top:12px}
  .menu__label{margin:12px 0 9px}
  .social__b{width:40px;height:40px}
  .social__b svg{width:17px;height:17px}
  .menu__cta{padding:12px 8px}
}
/* An SE with the browser chrome showing has about 560px to play with.
   The mark is the first thing to go: it is decoration, and the list is
   the reason the sheet exists. */
@media (max-height:620px){
  .menu__panel{padding:calc(var(--navh,64px) + 4px) 18px calc(10px + env(safe-area-inset-bottom,0px))}
  .menu__head{display:none}
  .menu__nav a{padding:4px 2px;grid-template-columns:20px 1fr 14px;gap:9px}
  .menu__nav a span{font-size:14px}
  .menu__nav a small{font-size:8px;width:16px}
  .menu__foot{padding-top:9px}
  /* on a screen this short the social row is the thing that goes:
     every one of those four is also reachable from the footer */
  .menu__label,.menu .social{display:none}
  .menu__cta{padding:11px 6px;font-size:10px;letter-spacing:.1em}
}

/* the narrowest phones still in service */
@media (max-width:380px){
  .card{flex:0 0 84%}
  .plan__num{font-size:38px}
  .menu__nav a{padding:12px 2px}
  .hero__title{font-size:clamp(36px,12.5vw,52px)}
  .layer .lede{font-size:13.5px}
  .mchapter{bottom:calc(48px + env(safe-area-inset-bottom,0px))}
}

@media (hover:none){
  .rail:hover .rail__item span{opacity:0}
  .card:hover{transform:none!important}
}

/* ============================================================
   8. REDUCED MOTION — a calm, complete version of the same site
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;
  }
  .grain,.hint__line{display:none}
}
body.reduced .track{height:auto}
body.reduced .stage{position:relative;height:auto;min-height:0}
body.reduced .frame{position:relative;inset:auto;aspect-ratio:16/9;height:auto}
body.reduced .frame__video,body.reduced .frame__poster{position:absolute;inset:0}
body.reduced .layers{position:static;display:grid;gap:1px;background:var(--line);margin-top:1px}
/* !important: the rAF loop writes inline opacity/visibility onto
   the layers, and those would otherwise outrank these rules if a
   visitor turns reduced motion on mid-session */
body.reduced .layer{
  position:relative;inset:auto;opacity:1!important;visibility:visible!important;
  background:var(--ink);padding:clamp(34px,6vw,72px) var(--pad);
  align-items:flex-start;justify-content:flex-start;text-align:left;
}
body.reduced .layer--bright{background:#F2F2EE}
body.reduced .layer__in{transform:none!important;filter:none!important}
body.reduced .rail,body.reduced .hud,body.reduced .transport,
body.reduced .mchapter,body.reduced .videobox,body.reduced .hint{display:none}
body.reduced .reveal{opacity:1;transform:none}
body.reduced .plan{transition-delay:0s!important}


/* ============================================================
   8. SCROLL PERFORMANCE ON PHONES
   ------------------------------------------------------------
   Everything below was found by measuring a mid-range phone scrolling
   from "About" to the footer (perf-lower.js).

   The walkthrough's own decoration — the pinging markers, the scroll
   hint — has no business animating while the reader is further down the
   page. And on a touch screen the ambient background stands still: the
   drifting glows, the panning grid and the sweeping bars each needed
   their own GPU layer, and anything drawn on top of a moving layer had
   to be layered too, so the whole lower page ended up as a stack of
   screen-sized textures being re-composited on every frame of a scroll.
   Still, the same background is one flat paint.
   ============================================================ */
/* (a class on the stage itself, not body:not(.in-tour) — a :not() on
   the body made every crossing in or out of the tour restyle the whole
   page, ~900 elements, in one frame) */
.stage.is-away *,
.stage.is-away *::before,
.stage.is-away *::after{animation-play-state:paused}

/* The walkthrough and the marquee bands each keep their moving parts to
   themselves. Without this, the engine had to assume the sticky video
   stage might be under anything that came after it, and drew the entire
   lower page as one more 5,600px texture on top of the page itself. */
.track{contain:paint}
.marq{contain:paint}

@media (hover:none), (max-width:820px){
  /* on a phone the background is painted with the page, not carried
     above it as its own layer: nothing in it moves any more */
  .bgfx{position:absolute;inset:0;height:auto;margin:0;contain:none}
  .bgfx *{animation:none !important;will-change:auto !important}
  /* the 3D tilt is a mouse effect; on glass the cards need no layer */
  .card{will-change:auto}
  .plan--best::after{animation:none;opacity:.55}
  /* the WhatsApp ring says "tap me" a few times when it appears, then
     rests: a ring pulsing forever is a style recalculation on every
     frame of every scroll for as long as the page is open */
  .wafab__pulse{animation-iteration-count:4}
  .bgfx__bar{opacity:.55}
  .about__mark img{animation:none;filter:none}
  .about__ring{animation:none;opacity:.6}
  .join__bg{animation:none}
  .cwhere__grid{animation:none}
}
/* things that only matter when you can see them stop when you cannot */
.is-offscreen,.is-offscreen *,.is-offscreen *::before,.is-offscreen *::after{animation-play-state:paused !important}

/* ---------- joining online (shown only once it is switched on) ---------- */
.plan__online{
  margin-top:auto;display:inline-flex;align-items:center;justify-content:center;gap:10px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;font-weight:700;
  background:var(--lime);color:#080808;border:1px solid var(--lime);padding:14px 16px;
  transition:background .3s var(--ease),transform .3s var(--ease);
}
.plan__online svg{width:15px;height:15px}
.plan__online:hover{background:#C2FF5C}
.plan__online + .plan__go{margin-top:8px}
.btn--online{background:var(--lime);color:#080808;border-color:var(--lime)}
.btn--online .btn__ico svg{width:18px;height:18px}

/* ---------- the shop, when the gym switches it on ----------
   Hidden in the HTML and shown only after the system says the shop is open,
   so a switched-off shop leaves no trace on the page — not even a gap. */
[data-shop-link][hidden],.shopsec[hidden]{display:none!important}
.shopsec__head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:20px 40px;max-width:none}
.shopsec__head > div{max-width:820px}
.shopsec__all{flex:0 0 auto}
.shoprail{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(12px,1.4vw,20px)}
@media (max-width:1180px){.shoprail{grid-template-columns:repeat(3,minmax(0,1fr))}}
.shopcard{position:relative;display:flex;flex-direction:column;background:var(--ink-3);border:1px solid var(--line);overflow:hidden;
  text-decoration:none;color:var(--white);transition:transform .5s var(--ease),border-color .4s,box-shadow .5s var(--ease)}
.shopcard__img{position:relative;aspect-ratio:1;background:radial-gradient(90% 90% at 50% 40%,#1D1D21,#0C0C0E);overflow:hidden}
.shopcard__img img{width:100%;height:100%;object-fit:contain;padding:9%;transition:transform .7s var(--ease)}
.shopcard__badge{position:absolute;top:12px;left:12px;padding:5px 9px;font:700 10.5px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;background:var(--white);color:#060606}
.shopcard__badge--sale{background:var(--lime)}
.shopcard__badge--soldout{background:#2A2A2E;color:var(--gray)}
.shopcard__badge--best{background:#FFC24D}
.shopcard__body{display:flex;flex-direction:column;gap:6px;padding:16px 16px 18px;flex:1}
.shopcard__brand{font:500 10px/1.2 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--gray)}
.shopcard__name{font:700 16px/1.3 var(--display);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.shopcard__price{margin-top:auto;padding-top:8px;display:flex;align-items:baseline;gap:10px}
.shopcard__price b{font:800 18px/1 var(--display);color:var(--lime)}
.shopcard__price s{font-size:13px;color:var(--gray-dim)}
@media (hover:hover){.shopcard:hover{transform:translateY(-6px);border-color:rgba(172,255,41,.4);box-shadow:0 30px 60px -30px rgba(172,255,41,.35)}
  .shopcard:hover .shopcard__img img{transform:scale(1.05)}}
.shopsec__ways{display:flex;flex-wrap:wrap;gap:8px 22px;list-style:none;padding:0;margin:clamp(22px,2.6vw,34px) 0 0;
  font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--gray)}
.shopsec__ways li{display:flex;align-items:center;gap:8px}
.shopsec__ways li::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--lime)}
@media (max-width:720px){
  .shoprail{display:flex;gap:12px;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    margin-inline:calc(var(--pad) * -1);padding:2px var(--pad) 6px;scrollbar-width:none}
  .shoprail::-webkit-scrollbar{display:none}
  .shopcard{flex:0 0 62%;max-width:250px;scroll-snap-align:start;transform:none!important}
  .shopcard__body{padding:13px 13px 15px}
  .shopcard__name{font-size:14.5px}
  .shopsec__all{width:100%;justify-content:center}
}
