/* ============================================================
   IN TOP FORM — fitnesstrainer.ae
   Shared stylesheet for index / ladies / men.
   Tokens per PLAN.md §2 / §2b. Every accent value is anchored to
   clothing worn in the brand's own photography.
   ============================================================ */
:root{
  --noir:#0B0A09; --charcoal:#131211; --graphite:#1D1B19; --line:#2A2725;
  --ivory:#F2EFE9; --ivory-muted:#A8A29A;

  /* Core scope — gold. Sourced from the team-kit ochre, not the slash yellow. */
  --accent:#C9A961; --accent-bright:#E3C888; --accent-deep:#8C6F3C;
  /* Faintest fill of the accent — used to mark nav items on hover. Declared
     per scope so the marker follows the page's colour, not always gold. */
  --accent-wash:rgba(201,169,97,.10);

  /* Fixed brand gold. Unlike --accent, the scope blocks below MUST NOT redefine
     these: the wordmark reads the same gold on every page, ladies included. */
  --gold:#C9A961; --gold-bright:#E3C888;

  --ease:cubic-bezier(.16,1,.3,1);
  --t-micro:180ms; --t-std:320ms; --t-reveal:760ms;
  --gutter:clamp(1.25rem,5vw,5.5rem);
  --spine:clamp(1.1rem,3.2vw,3.25rem);
  --maxw:1440px;
}
/* Ladies' scope — rose. Sourced from the training top. */
[data-scope="women"]{--accent:#D6A0A8; --accent-bright:#EFC2CC; --accent-deep:#9A6B74;
  --accent-wash:rgba(214,160,168,.12);}
/* Mobility scope — sage. Sourced from the eucalyptus kit, not the collage grass green. */
[data-scope="mobility"]{--accent:#A3B295; --accent-bright:#C8D3BC; --accent-deep:#6E7A64;
  --accent-wash:rgba(163,178,149,.12);}
/* Jade scope — a cooler, deeper green tied to the teal training kit in the
   ladies' photography. Matched to the gold ramp step for step (spread 0.19)
   so it reads as the same system, not a different brand. Deliberately
   desaturated: a bright emerald measures fine but looks cheap on black. */
[data-scope="jade"]{--accent:#93B3A8; --accent-bright:#C0D6CD; --accent-deep:#5E7A72;
  --accent-wash:rgba(147,179,168,.12);}

*,*::before,*::after{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;}
body{
  margin:0; background:var(--noir); color:var(--ivory);
  font-family:"Instrument Sans",system-ui,sans-serif;
  font-size:1.0625rem; line-height:1.65;
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
}
img{max-width:100%;display:block;}
a{color:inherit;text-decoration:none;}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:1px;}

/* ---------- type ---------- */
.display{
  font-family:Archivo,system-ui,sans-serif; font-weight:800;
  font-stretch:125%; letter-spacing:-.03em; line-height:.92;
  text-transform:uppercase; margin:0;
}
.h2{
  font-family:Archivo,system-ui,sans-serif; font-weight:700;
  font-stretch:118%; letter-spacing:-.02em; line-height:1;
  text-transform:uppercase; margin:0;
  font-size:clamp(2rem,4.5vw,4rem);
}
.mono{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:.75rem; letter-spacing:.18em; text-transform:uppercase;
  color:var(--ivory-muted);
}
.gold{color:var(--accent);}
/* Available to screen readers and search engines, invisible on screen. Used where
   a page needs a real <h1> but the design does not show a headline. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;}
.lede{font-size:clamp(1.0625rem,1.6vw,1.25rem);line-height:1.6;color:var(--ivory-muted);max-width:52ch;}
p{max-width:68ch;}

/* ---------- ITF mark ---------- */
.mark{display:block;flex:none;color:var(--ivory);}
.mark--mono{--mark-deep:var(--ivory);--mark-bright:rgba(242,239,233,.5);}
.mark--accent{--mark-deep:var(--accent);--mark-bright:var(--accent-bright);}
.lockup{display:flex;flex-direction:column;align-items:flex-start;gap:.7rem;}
.lockup__word{font-family:Archivo,sans-serif;font-weight:600;font-stretch:112%;
  letter-spacing:.22em;text-transform:uppercase;font-size:.7rem;color:var(--accent);}

/* ---------- caliper spine (the signature) ---------- */
.spine{position:fixed;top:0;left:var(--spine);width:1px;height:100vh;background:var(--line);z-index:40;pointer-events:none;}
.spine__fill{position:absolute;top:0;left:0;width:100%;height:0;background:var(--accent);transition:background var(--t-std) var(--ease);}
.spine__cursor{position:absolute;left:-3px;width:7px;height:1px;background:var(--accent);transition:background var(--t-std) var(--ease);}
@media(max-width:767px){.spine{left:0;}.spine__cursor{display:none;}}

/* ---------- layout ---------- */
.wrap{max-width:var(--maxw);margin:0 auto;padding-left:var(--gutter);padding-right:var(--gutter);}
.section{position:relative;padding-block:clamp(5rem,11vw,10rem);}
.section--alt{background:var(--charcoal);}
.tick{display:flex;align-items:center;gap:1rem;margin-bottom:clamp(2rem,4vw,3.5rem);}
.tick__rule{height:1px;width:clamp(1.5rem,4vw,4rem);background:var(--accent-deep);flex:none;}
.tick__num{color:var(--accent);}

/* ---------- nav ---------- */
.nav{
  position:fixed;top:0;left:0;right:0;z-index:50;
  display:flex;align-items:center;justify-content:space-between;
  gap:1.5rem; padding:1.1rem var(--gutter);
  border-bottom:none;
}
/* The header sits on a scrim, never on a bar. Over the pale collages the links
   were disappearing into the photograph, but a solid bar with a hairline cut a
   hard edge straight across whoever was standing behind it. This gradient is
   opaque enough at the top to hold ivory text and fades to nothing well below
   the links, so there is no line and no boundary to notice — only the light
   going out of the photograph where the type needs it to. Extends past the
   nav's own box, hence the negative bottom inset. */
/* NO backdrop-filter here. This was tried and it is the one thing that cannot
   work: Chrome clips the filtered backdrop to the element box and treats a mask
   on it as a threshold rather than a fade, so the blur always terminates in a
   hard horizontal line straight across the picture — the exact edge this scrim
   exists to avoid. Removing it is what makes the transition seamless.

   The softness comes from the ramp instead. Eleven stops trace an ease-out
   curve rather than a straight line: the alpha falls slowly at first and then
   away to nothing, so there is no point where the rate of change jumps and
   therefore no line for the eye to catch. Evenly spaced stops also keep the
   steps below one 8-bit level each, which is what stops it banding. */
.nav::before{
  content:"";position:absolute;left:0;right:0;top:0;bottom:-7rem;z-index:-1;
  pointer-events:none;
  background:linear-gradient(180deg,
    rgba(9,9,8,.95)  0%,  rgba(9,9,8,.93) 10%, rgba(9,9,8,.88) 20%,
    rgba(9,9,8,.80) 30%,  rgba(9,9,8,.70) 40%, rgba(9,9,8,.58) 50%,
    rgba(9,9,8,.45) 60%,  rgba(9,9,8,.32) 70%, rgba(9,9,8,.19) 80%,
    rgba(9,9,8,.08) 90%,  rgba(9,9,8,0)  100%);
  transition:background var(--t-std) var(--ease);
}
/* Scrolled: the same curve, denser and reaching further. No border — a rule
   here would reintroduce exactly the edge this replaces. */
.nav.is-stuck::before{
  background:linear-gradient(180deg,
    rgba(9,9,8,.98)  0%,  rgba(9,9,8,.97) 10%, rgba(9,9,8,.95) 20%,
    rgba(9,9,8,.91) 30%,  rgba(9,9,8,.84) 40%, rgba(9,9,8,.74) 50%,
    rgba(9,9,8,.60) 60%,  rgba(9,9,8,.44) 70%, rgba(9,9,8,.27) 80%,
    rgba(9,9,8,.12) 90%,  rgba(9,9,8,0)  100%);
}

/* The wordmark takes you home and lights up on the way.

   Three things are deliberate here:
   · The TEXT COLOUR DOES NOT CHANGE. The gold goes behind the letterforms, not
     on them — the ivory wordmark stays ivory and the mark stays as it is.
   · The glow is SHARP, not a halo. Stacked drop-shadows at 1–3px blur trace the
     edges of each glyph instead of blooming out into a soft cloud. Raising these
     radii is what turns it back into the halo that was rejected.
   · It is --gold, never --accent. The wordmark reads identically on every page;
     the ladies pages do not get a jade wordmark.

   drop-shadow on the anchor follows the alpha of everything it renders, so the
   mark and the letters are rimmed together from one declaration. */
.nav__brand{
  transition:filter var(--t-std) var(--ease);}
.nav__brand:hover,.nav__brand:focus-visible{
  filter:drop-shadow(0 0 1px var(--gold-bright))
         drop-shadow(0 0 2px var(--gold))
         drop-shadow(0 0 4px rgba(201,169,97,.55));
  animation:brandFlash 1.5s ease-in-out infinite;}
@keyframes brandFlash{
  0%,100%{filter:drop-shadow(0 0 1px var(--gold))
                 drop-shadow(0 0 2px rgba(201,169,97,.55));}
  50%    {filter:drop-shadow(0 0 1px var(--gold-bright))
                 drop-shadow(0 0 3px var(--gold-bright))
                 drop-shadow(0 0 6px rgba(227,200,136,.5));}
}
@media(prefers-reduced-motion:reduce){
  .nav__brand:hover,.nav__brand:focus-visible{animation:none;}
}
.nav__brand{display:flex;align-items:center;gap:.6rem;font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;letter-spacing:.04em;font-size:.9rem;text-transform:uppercase;white-space:nowrap;}
.nav__cta-short{display:none;}
@media(max-width:560px){
  .nav{padding-inline:1rem;gap:.75rem;}
  .nav__brand{font-size:.78rem;gap:.45rem;}
  .nav__brand svg{width:22px;height:15px;}
  .nav__cta-long{display:none;}
  .nav__cta-short{display:inline;}
}
@media(max-width:900px){
  .btn{min-height:48px;}
  .btn--sm{min-height:44px;}
  .nav__links a{padding-block:.35rem;}
}
.nav__links{display:flex;gap:clamp(1rem,1.8vw,2rem);align-items:center;flex-wrap:nowrap;}
/* nowrap matters for "1-2-1": hyphens are line-break opportunities, so without
   it the label splits across lines. */
.nav__links a{font-size:.8rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ivory-muted);white-space:nowrap;
  padding:.42rem .6rem;border:1px solid transparent;border-radius:2px;
  transition:color var(--t-micro) var(--ease),background var(--t-micro) var(--ease),
             border-color var(--t-micro) var(--ease);}
/* Hovering marks the item — it fills and outlines rather than growing, so the
   bar never reflows under the cursor. The current page is marked the same way. */
.nav__links a:hover,
.nav__links a:focus-visible,
.nav__links a[aria-current="page"]{
  color:var(--accent);
  background:var(--accent-wash);
  border-color:var(--accent-deep);}
@media(max-width:900px){.nav__links{display:none;}}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.6rem;
  font-family:"IBM Plex Mono",monospace;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;
  padding:1rem 1.75rem;border:1px solid var(--accent);cursor:pointer;
  transition:background var(--t-micro) var(--ease),color var(--t-micro) var(--ease),
             border-color var(--t-micro) var(--ease),transform var(--t-micro) var(--ease);
}
.btn--solid{background:var(--accent);color:var(--noir);font-weight:500;}
.btn--solid:hover{background:var(--accent-bright);border-color:var(--accent-bright);transform:translateY(-1px);}
.btn--ghost{background:transparent;color:var(--ivory);border-color:var(--line);}
.btn--ghost:hover{border-color:var(--accent);color:var(--accent);transform:translateY(-1px);}
.btn--sm{padding:.7rem 1.15rem;}

/* ---------- hero ---------- */
.hero{position:relative;min-height:100svh;display:flex;align-items:flex-end;
  padding-top:clamp(7rem,14vh,10rem);padding-bottom:clamp(3rem,7vw,6rem);overflow:hidden;}
.hero__media{position:absolute;inset:0;z-index:0;
  background-color:var(--noir);
  background-image:
    radial-gradient(120% 90% at 78% 55%,rgba(201,169,97,.10),transparent 60%),
    radial-gradient(90% 70% at 20% 20%,rgba(255,255,255,.045),transparent 60%),
    url("images/hero/team-group.jpg");
  background-size:cover;background-position:center right;
  transform:scale(1.06);
  animation:heroDrift 2s var(--ease) forwards;
}
@keyframes heroDrift{to{transform:scale(1);}}
.hero__video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity 1.2s var(--ease);}
.hero__video.is-playing{opacity:1;}
.hero__scrim{position:absolute;inset:0;z-index:1;
  background:linear-gradient(90deg,rgba(11,10,9,.94) 0%,rgba(11,10,9,.78) 45%,rgba(11,10,9,.35) 100%),
             linear-gradient(0deg,rgba(11,10,9,.9) 0%,transparent 55%);}
.hero__inner{position:relative;z-index:2;width:100%;}
.hero__eyebrow{margin-bottom:1.5rem;display:flex;align-items:center;gap:.9rem;}
.hero__eyebrow .tick__rule{background:var(--accent);}
.hero h1{font-size:clamp(2.1rem,5.4vw,5rem);margin-bottom:1.75rem;}
/* Hero lockup: a small "Our" sitting over a large "Results".
   Halved from the previous single-word size at every stop of the clamp. */
.hero h1.hero__word{font-size:clamp(2.25rem,7.5vw,6rem);letter-spacing:-.035em;margin-bottom:1.25rem;}
.hero__word-sm{
  display:block;
  font-size:clamp(.8rem,1.5vw,1.15rem);
  font-weight:600;font-stretch:112%;
  letter-spacing:.3em;
  /* letter-spacing adds a trailing gap on the last glyph; pull it back so the
     word still optically aligns to the left edge of RESULTS below it. */
  text-indent:.03em;margin-left:-.03em;
  color:var(--ivory-muted);
  line-height:1;margin-bottom:.55rem;
}
.hero__cta{display:flex;flex-wrap:wrap;gap:1rem;margin-top:2.5rem;}
.hero__note{margin:1.5rem 0 0;opacity:0;animation:fadeUp .9s var(--ease) .72s forwards;}

/* ---------- five stars ----------
   Drawn, not an image file: recolours with --accent, stays crisp at any size,
   and costs no request. The second polygon is a facet shadow over the right
   half, which is what makes it read as struck metal rather than a flat sticker. */
/* Rating block: stars over a serif caption, both centred, with generous space
   above and below so it reads as its own beat rather than crowding the hero. */
.rating{text-align:center;
  margin:clamp(1.5rem,3vw,2.75rem) 0 clamp(2.75rem,5.5vw,4.5rem);
  opacity:0;animation:fadeUp .9s var(--ease) .3s forwards;}
.stars{display:flex;gap:clamp(.35rem,.9vw,.7rem);align-items:center;
  justify-content:center;margin:0 0 clamp(.9rem,1.8vw,1.4rem);}
.stars svg{width:clamp(34px,4.6vw,54px);height:auto;
  filter:drop-shadow(0 2px 7px rgba(201,169,97,.32));}

/* ---------- turning stars ----------
   Each slot holds the drawn SVG and, once main.js has confirmed the browser
   composites an alpha WebM, a <video> stacked on top of it. The SVG is never
   removed: it is what shows while the clip loads, and it is what Safari keeps,
   since Safari plays VP9 but discards its alpha channel and would otherwise
   paint five blue squares. */
.stars--video .star{position:relative;display:inline-flex;
  width:clamp(34px,4.6vw,54px);aspect-ratio:1;}
.stars--video .star svg{width:100%;height:100%;
  transition:opacity var(--t-std) var(--ease);}
.stars--video .star video{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;background:transparent;pointer-events:none;
  opacity:0;transition:opacity 520ms var(--ease);
  /* The clip is a lit 3D render; the same warm shadow the SVG carries keeps the
     two versions reading as one object. */
  filter:drop-shadow(0 2px 7px rgba(201,169,97,.32));}
/* Swapped only once a frame is actually decoded — crossfading to a video that
   has not painted yet leaves a visible gap where the star was. */
.stars--video .star.is-live video{opacity:1;}
.stars--video .star.is-live svg{opacity:0;}
@media(prefers-reduced-motion:reduce){
  .stars--video .star video{display:none;}
  .stars--video .star svg{opacity:1;}
}

/* ---------- the five arrive one at a time ----------
   Each slot is struck in on its own beat rather than the row appearing at once.
   The animation is on the SLOT, not on its contents, so it works identically
   whether the star is the drawn SVG or the video that replaces it — neither
   knows this is happening.

   Delays start at .55s: the .rating block's own fadeUp runs from .3s, so the
   first star lands just as the block finishes arriving rather than racing it. */
.stars--video .star{
  opacity:0;transform:translateY(9px) scale(.82);
  animation:starIn .58s var(--ease) forwards;}
.stars--video .star:nth-child(1){animation-delay:.55s;}
.stars--video .star:nth-child(2){animation-delay:.70s;}
.stars--video .star:nth-child(3){animation-delay:.85s;}
.stars--video .star:nth-child(4){animation-delay:1.00s;}
.stars--video .star:nth-child(5){animation-delay:1.15s;}
@keyframes starIn{
  0%  {opacity:0;transform:translateY(9px) scale(.82);}
  60% {opacity:1;transform:translateY(0) scale(1.06);}
  100%{opacity:1;transform:none;}
}
/* Held until main.js confirms the row is in its final form — see the "turning
   stars" block there. The entrance is frozen at frame zero, and while frozen the
   SVG-to-video swap is made INSTANT rather than crossfaded: nothing is on screen
   to fade, and it means each star arrives already as the version it will stay as
   instead of a flat SVG star visibly turning into a video one. */
.stars--video.is-holding .star{animation-play-state:paused;}
.stars--video.is-holding .star.is-live svg{transition:none;opacity:0;}
.stars--video.is-holding .star.is-live video{transition:none;opacity:1;}

.stars__label{
  /* The global p{max-width:68ch} would pin this box to the left and centre the
     text inside that narrower box instead of under the stars. */
  max-width:none;margin:0 auto;
  font-family:"Cormorant Garamond",Georgia,"Times New Roman",serif;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.18em;
  font-size:clamp(15px,1.15vw,18px);
  line-height:1.4;
  color:var(--accent);
  /* letter-spacing adds a trailing gap on the last glyph; pull it back so the
     line stays optically centred under the stars. */
  text-indent:.18em;
}

/* ---------- a gold sweep reads across the caption ----------
   The gradient is painted INTO the glyphs (background-clip:text) and slid
   across, so the light travels through the letterforms rather than a highlight
   bar passing over them.

   Direction: the image is 300% of the element, so background-position 100%
   means it is shifted two widths LEFT and 0% means aligned. Animating 100% -> 0%
   therefore moves the image right, carrying the bright band left-to-right across
   the text. Reversing those two numbers reverses the sweep.

   The band sits in the middle third, so at both ends of the animation the
   visible third is flat --accent: the caption rests as plain gold and the sweep
   is an event, not a permanent shimmer. Hence the long hold to 100%. */
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .stars__label{
    background-image:linear-gradient(100deg,
      var(--accent)   0%,  var(--accent)   40%,
      #FFF1CE         48%, var(--accent-bright) 52%,
      var(--accent)   60%, var(--accent)   100%);
    background-size:300% 100%;
    background-repeat:no-repeat;
    background-position:100% 0;
    -webkit-background-clip:text;background-clip:text;
    -webkit-text-fill-color:transparent;color:transparent;
    /* NOT var(--ease). That curve is heavily front-loaded and collapsed the
       whole crossing into about half a second, which reads as a flicker rather
       than light travelling. ease-in-out over 28% of a 5.4s cycle gives a ~1.5s
       sweep and a ~3.9s rest between passes. */
    animation:capShine 5.4s ease-in-out 1.5s infinite;
  }
  @keyframes capShine{
    0%          {background-position:100% 0;}
    28%, 100%   {background-position:0% 0;}
  }
}
/* No clip support: the caption stays flat gold rather than turning invisible. */
@media(prefers-reduced-motion:reduce){
  .stars--video .star{opacity:1;transform:none;animation:none;}
  .stars__label{animation:none;background-image:none;
    -webkit-text-fill-color:var(--accent);color:var(--accent);}
}

/* ---------- the chooser: ladies / men ---------- */
/* Two boxes, each half the width. Hovering one grows it and lets the other
   recede — flex-grow does the work, so the pair always fills the row exactly
   and no layout gap ever opens up mid-transition. */
.chooser{display:flex;gap:clamp(.4rem,.9vw,.85rem);
  width:100%;max-width:none;margin-top:.25rem;
  opacity:0;animation:fadeUp .9s var(--ease) .46s forwards;}
.choice{
  position:relative;overflow:hidden;isolation:isolate;
  flex:1 1 0;min-width:0;
  display:flex;align-items:center;justify-content:center;
  /* Taller than it looks like it needs to be: the source photos are 16:9, and a
     short wide box makes `cover` crop the subjects' heads off. At this height
     the box aspect is close to the image aspect, so almost nothing is lost. */
  min-height:clamp(190px,31vw,400px);
  padding:clamp(1rem,2vw,1.75rem);
  border:1px solid var(--line);
  background:rgba(19,18,17,.5);
  transition:flex-grow var(--t-std) var(--ease),
             border-color var(--t-std) var(--ease),
             background var(--t-std) var(--ease),
             opacity var(--t-std) var(--ease),
             filter var(--t-std) var(--ease);
}
/* The image is the reward for hovering: it slides in from the box's own outer
   edge and settles behind the text. Hidden at rest, so the row stays quiet. */
.choice__media{position:absolute;inset:0;z-index:-1;
  background-size:cover;
  opacity:0;
  /* Rest sits slightly in; hover settles to 1 so the picture opens OUT rather
     than pushing further in. Keeps whole figures in frame. */
  transform:translateX(var(--slide-from,-12%)) scale(1.05);
  filter:grayscale(.55) brightness(.6);
  transition:opacity var(--t-reveal) var(--ease),
             transform var(--t-reveal) var(--ease),
             filter var(--t-reveal) var(--ease);}
/* Each slides in from its own side, and is framed on the people, not the room. */
.choice--ladies{--slide-from:-12%;}
.choice--men{--slide-from:12%;}
.choice--ladies .choice__media{background-position:center center;}
.choice--men .choice__media{background-position:72% center;}
/* Group photo: the two women sit at the far left and right of a wide frame
   whose left third is a filler shot of a pink gym. Cropping from the left
   (the initial 0% 0%) cuts the second woman off, so anchor right — that drops
   the filler and keeps both figures inside the box at every width. */
.choice__media[style*="group-class"]{background-position:100% center;}
.choice:hover .choice__media,.choice:focus-visible .choice__media{
  opacity:1;transform:translateX(0) scale(1);filter:grayscale(0) brightness(.66);}

/* ---------- the gold figure marks ----------
   A translucent gold pictogram on each chooser box — three figures for group,
   one for single — so the two boxes read as what they are without the label,
   and stay readable once the photograph slides in behind the title on hover.

   Cut from a supplied JPEG that had its "transparency" checkerboard baked in.
   Keyed on SATURATION, not colour: gold has a wide channel spread, the grey and
   white checker squares and the drop shadow have none, so alpha = spread. That
   is why the shadow vanished along with the checkerboard. The two figures
   overlap vertically in the source, so the group crop has its bottom-right
   corner punched to alpha 0 where the solo figure's dumbbells intruded.

   Layering inside .choice (isolation:isolate):
       -1  .choice__media   photograph (hover)
       -1  .choice::after   scrim, painted after the photo
        1  .choice__mark    this — above the scrim, so the gold is not dimmed
        2  .choice__title   the label, above everything */
.choice__mark{position:absolute;z-index:1;pointer-events:none;
  left:50%;top:50%;transform:translate(-50%,-56%);
  width:min(62%,300px);aspect-ratio:1.2;
  background-repeat:no-repeat;background-size:contain;background-position:center;
  opacity:.22;
  /* left/top/width are in here on purpose — they are what carry the mark to
     its corner on hover, and without them the retreat snaps instead of slides. */
  transition:opacity var(--t-std) var(--ease),transform var(--t-std) var(--ease),
             left var(--t-std) var(--ease),top var(--t-std) var(--ease),
             width var(--t-std) var(--ease);}
/* On hover the box widens and the photo arrives. The mark must not stay large
   over the picture, so it shrinks hard and retreats to a corner — a small badge
   that says "single" or "group" while the photograph is what you look at.

   Positioned with `left` in BOTH states so the move tweens: left 50% -> a corner
   value, transform -50% -> the corner's own offset. Switching to `right` for
   the top-right corner would snap instead of slide, because left->right is not
   animatable. Opacity goes UP as it shrinks — a small mark at .22 would vanish. */
.choice:hover .choice__mark,.choice:focus-visible .choice__mark{
  opacity:.6;top:calc(100% - .85rem);width:min(16%,76px);}
/* THE LEFT-HAND BOX OF EACH PAIR sends its badge to the BOTTOM-RIGHT, away from
   the box it expanded out of. `top`/`left` are the properties used — they tween —
   with the badge hung off its own bottom-right corner via transform.
   Single/Group on the sub-pages; Ladies on the homepage. */
.choice[href$="-single.html"]:hover .choice__mark,
.choice[href$="-single.html"]:focus-visible .choice__mark,
.choice--ladies:hover .choice__mark,
.choice--ladies:focus-visible .choice__mark{
  left:calc(100% - .85rem);transform:translate(-100%,-100%);}
/* THE RIGHT-HAND BOX sends its badge to the BOTTOM-LEFT.
   Group on the sub-pages; Men on the homepage. */
.choice[href$="-group.html"]:hover .choice__mark,
.choice[href$="-group.html"]:focus-visible .choice__mark,
.choice--men:hover .choice__mark,
.choice--men:focus-visible .choice__mark{
  left:.85rem;transform:translate(0,-100%);}
/* Per-glyph widths. The three-figure group and the two shield badges are wider
   drawings than the lone figure, so they need more box to read at the same
   visual weight beside it. */
.choice[href$="-group.html"]:hover .choice__mark,
.choice[href$="-group.html"]:focus-visible .choice__mark{width:min(19%,92px);}
.choice--ladies:hover .choice__mark,.choice--ladies:focus-visible .choice__mark,
.choice--men:hover .choice__mark,.choice--men:focus-visible .choice__mark{
  width:min(17%,84px);}
/* Per-glyph resting size and shape. The container's aspect-ratio is matched to
   each drawing so `background-size:contain` is not letterboxing inside a box of
   the wrong proportion — otherwise the effective size drifts per mark and they
   stop reading as a set. */
.choice__mark[style*="mark-single"]{width:min(44%,200px);aspect-ratio:.9;}
.choice__mark[style*="mark-group"] {aspect-ratio:.9;}
/* The two shields are denser drawings than the stick figures, so they rest a
   little smaller for the same weight. */
.choice__mark[style*="mark-men"]   {width:min(46%,220px);aspect-ratio:1.08;}
.choice__mark[style*="mark-ladies"]{width:min(40%,190px);aspect-ratio:.8;}
/* Lifted so the mark, a positioned layer, cannot paint over the label. */
.choice__title{position:relative;z-index:2;}

/* Scrim sits above the image (same stacking level, painted later) so the label
   stays legible over the bright pink studio shot as well as the dark team shot. */
.choice::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(0deg,rgba(11,10,9,.88),rgba(11,10,9,.52));
  transition:background var(--t-std) var(--ease);}
.choice:hover::after,.choice:focus-visible::after{
  background:linear-gradient(0deg,rgba(11,10,9,.78),rgba(11,10,9,.34));}
.choice__title{display:block;text-align:center;
  font-family:Archivo,sans-serif;font-weight:800;
  font-stretch:118%;text-transform:uppercase;letter-spacing:-.02em;
  font-size:clamp(1.4rem,3.6vw,2.75rem);line-height:1;
  transition:font-size var(--t-std) var(--ease),color var(--t-micro) var(--ease),
             opacity var(--t-std) var(--ease);}

/* On hover the label steps aside entirely so the photograph is the whole
   message — nothing sits in front of the image. Applies to every chooser. */
.choice:hover .choice__title,
.choice:focus-visible .choice__title{
  opacity:0;
  font-size:clamp(1.4rem,3.6vw,2.75rem);   /* hold size so it fades, not swells */
}

/* The grid background is very tall; anchor it to the top so the framing is
   predictable rather than landing mid-panel. */
.hero__media--grid{background-position:center top;background-size:cover;
  animation:none;transform:none;}

/* ---------- jade atmosphere ----------
   Green is carried by light rather than by flat fills: a cool cast in the
   scrim, a low glow behind the content, and a hairline at the section joins.
   Tints stay under 10% so the photography still reads as photography. */
[data-scope="jade"] .hero__scrim{
  background:
    linear-gradient(90deg,rgba(11,10,9,.94) 0%,rgba(11,10,9,.78) 45%,rgba(11,10,9,.38) 100%),
    radial-gradient(80% 60% at 18% 78%,rgba(147,179,168,.16),transparent 62%),
    linear-gradient(0deg,rgba(14,22,20,.92) 0%,rgba(11,10,9,.10) 58%);
}
[data-scope="jade"] .hero__media--grid{filter:saturate(.92) contrast(1.04);}
[data-scope="jade"] .section--alt{
  background:
    radial-gradient(120% 80% at 50% 0%,rgba(147,179,168,.055),transparent 60%),
    var(--charcoal);
}
[data-scope="jade"] .strip{
  background:linear-gradient(0deg,rgba(147,179,168,.045),transparent 70%),var(--noir);
}
[data-scope="jade"] .picker{
  background:
    radial-gradient(90% 70% at 50% 100%,rgba(147,179,168,.07),transparent 65%),
    var(--charcoal);
}
[data-scope="jade"] .close__scrim{
  background:linear-gradient(0deg,rgba(12,20,18,.94),rgba(11,10,9,.76));
}
/* Section rules pick up the green so the joins read as part of the scheme. */
[data-scope="jade"] .section--alt,
[data-scope="jade"] .strip{border-color:rgba(147,179,168,.16);}

/* Whole row dims AND blurs while a choice is being made, so the hovered box is
   the only thing in focus — literally. */
.chooser:hover .choice{flex-grow:.78;opacity:.55;filter:blur(2.5px);}
.chooser .choice:hover,.chooser .choice:focus-visible{filter:none;}
.chooser .choice:hover,.chooser .choice:focus-visible{
  flex-grow:1.5;opacity:1;
  border-color:var(--accent);
  background:rgba(29,27,25,.55);
}
/* NOTE: a duplicate `.choice:hover .choice__media` rule used to sit here from an
   earlier revision. It re-applied scale(1.1) and won on source order, which is
   what was cropping the subjects' heads. The single authoritative rule is with
   the other .choice__media declarations above — do not re-add one here. */
/* Ladies previews its rose accent on intent only, so the hero never rests
   with two accents on screen at once. */
.choice--ladies:hover,.choice--ladies:focus-visible{
  --accent:#D6A0A8;--accent-bright:#EFC2CC;--accent-deep:#9A6B74;}
.choice[aria-current="page"]{border-color:var(--accent-deep);}

/* No hover on touch, so the centred coach carries the zoom permanently —
   otherwise phone users never see it at all. */
@media(hover:none){
  .pcoach.is-active .pcoach__img img{transform:scale(1.45);}
}

/* Touch devices never fire hover, so nothing would ever reveal the image.
   Show it at rest there instead, and skip the grow/recede entirely. */
@media(hover:none){
  .chooser:hover .choice{flex-grow:1;opacity:1;}
  .chooser .choice:hover{flex-grow:1;}
  .choice:hover .choice__title{font-size:clamp(1.4rem,3.6vw,2.75rem);color:inherit;}
  .choice__media{opacity:1;transform:none;filter:grayscale(.15) brightness(.6);}
}

/* line-reveal animation for hero type */
.reveal-line{display:block;overflow:hidden;}
.reveal-line>span{display:block;transform:translateY(102%);animation:lineUp .95s var(--ease) forwards;}
.reveal-line:nth-child(2)>span{animation-delay:.09s;}
.hero .lede{opacity:0;animation:fadeUp .9s var(--ease) .34s forwards;}
.hero__cta{opacity:0;animation:fadeUp .9s var(--ease) .46s forwards;}
.hero__eyebrow{opacity:0;animation:fadeUp .8s var(--ease) .14s forwards;}
@keyframes lineUp{to{transform:translateY(0);}}
@keyframes fadeUp{from{opacity:0;transform:translateY(18px);}to{opacity:1;transform:none;}}

/* ---------- coach carousel ----------
   One coach centred and lit, the neighbours pulled back. The track is a single
   transformed flex row so the centring is exact at any width — a scroll-snap
   version drifts by a few pixels and the "centre" card never quite lines up. */
.picker{background:var(--charcoal);border-block:1px solid var(--line);
  padding-block:clamp(3rem,6vw,5.5rem);overflow:hidden;}
.picker__head{text-align:center;margin-bottom:clamp(1.75rem,3.5vw,2.75rem);}
.picker__title{font-family:Archivo,sans-serif;font-weight:800;font-stretch:120%;
  text-transform:uppercase;letter-spacing:-.025em;margin:0;
  font-size:clamp(1.9rem,4.5vw,3.5rem);}
.picker__head .mono{display:block;margin-top:.6rem;}

.picker__viewport{overflow:hidden;width:100%;}
.picker__track{
  display:flex;align-items:flex-start;
  gap:clamp(.75rem,1.8vw,1.5rem);
  will-change:transform;
  transition:transform 560ms var(--ease);
}
.pcoach{
  flex:0 0 clamp(200px,26vw,330px);
  display:block;position:relative;
  opacity:.5;                       /* neighbours sit at half strength */
  transform:scale(.88);
  transition:opacity 460ms var(--ease),transform 460ms var(--ease);
}
.pcoach.is-active{opacity:1;transform:scale(1);}

/* Images are never cropped: the frame is fixed, the picture is contained
   inside it on black. Mixed portrait and landscape sources therefore all sit
   centred and whole, which is the point. */
/* The desaturation lives on the IMG, not on this box. `filter` creates a
   stacking context, and with it here the "Watch video" button was trapped
   inside it — its z-index could not clear the stretched profile link, so the
   badge was covered and every click on it opened the profile instead of the
   clip. Filtering the picture alone leaves the box context-free, so the badge
   can sit above the link while the link still covers the photograph. */
.pcoach__img{aspect-ratio:3/4;position:relative;overflow:hidden;
  border:1px solid var(--line);background:var(--noir);
  display:flex;align-items:center;justify-content:center;
  transition:border-color var(--t-std) var(--ease);}
.pcoach__img img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;object-position:center;
  filter:grayscale(.7) brightness(.85);
  transform:scale(1);transform-origin:center 45%;
  transition:transform 620ms var(--ease),filter 460ms var(--ease);}
.pcoach.is-active .pcoach__img{border-color:var(--accent-deep);}
.pcoach.is-active .pcoach__img img{filter:grayscale(0) brightness(1);}
.pcoach.is-active:hover .pcoach__img{border-color:var(--accent);}
/* Hover pushes into the coach's own photo inside the poster. Origin is set
   just above centre because that is where the figure sits in these layouts. */
.pcoach.is-active:hover .pcoach__img img,
.pcoach.is-active:focus-visible .pcoach__img img{transform:scale(1.55);}
.pcoach__initial{font-family:Archivo,sans-serif;font-weight:800;font-stretch:125%;
  font-size:2.5rem;color:var(--accent-deep);opacity:.5;user-select:none;}
.pcoach__name{margin-top:.85rem;text-align:center;
  font-family:Archivo,sans-serif;font-weight:700;font-stretch:112%;
  text-transform:uppercase;font-size:1.05rem;letter-spacing:.01em;}
.pcoach__role{display:block;text-align:center;margin-top:.2rem;}

/* The profile link is stretched across the whole card, so the card still reads
   as one target while remaining a real link. The video button is its SIBLING,
   sitting on a higher layer — which is the whole reason the card is a div with
   two children rather than one anchor wrapping everything: a <button> inside an
   <a> is invalid, and every click on the play badge would also navigate.

   .pcoach__role itself must stay unpositioned, or the pseudo-element would
   stretch over the label instead of the card. .pcoach is the positioned
   ancestor it resolves against. */
.pcoach__role::after{content:"";position:absolute;inset:0;z-index:1;}

/* Video badge — pinned to the FOOT of the photograph, full width, divided from
   the picture by a single rule.

   It must be absolutely positioned: .pcoach__img is a centring flex container,
   so a static button lands in the middle of the picture instead of under it.

   z-index lifts it clear of the stretched profile link, which covers the whole
   card — without it the badge would navigate instead of opening the clip. */
.pcoach__video{
  position:absolute;left:0;right:0;bottom:0;z-index:3;
  width:100%;cursor:pointer;border:0;border-top:1px solid var(--accent-deep);
  display:flex;align-items:center;justify-content:center;gap:.55rem;
  padding:.7rem;
  background:linear-gradient(0deg,rgba(11,10,9,.96),rgba(11,10,9,.78));
  color:var(--accent);
  font-family:"IBM Plex Mono",monospace;font-size:.66rem;letter-spacing:.16em;
  text-transform:uppercase;
  transition:background var(--t-micro) var(--ease),color var(--t-micro) var(--ease);
}
/* Hover lights the bar from behind so it plainly reads as clickable: a warm
   gold wash comes up behind the words, the label brightens and picks up a glow,
   and the rule above it goes to full accent. */
.pcoach__video:hover,.pcoach__video:focus-visible{
  background:linear-gradient(0deg,rgba(201,169,97,.30),rgba(201,169,97,.16));
  border-top-color:var(--accent);
  color:var(--accent-bright);
  text-shadow:0 0 12px rgba(227,200,136,.75);}
.pcoach__video:hover svg,.pcoach__video:focus-visible svg{
  filter:drop-shadow(0 0 6px rgba(227,200,136,.9));}
@media(prefers-reduced-motion:reduce){
  .pcoach__video{transition:none;}
}
.pcoach__video svg{width:13px;height:13px;fill:currentColor;}

/* chevrons, centred under the track */
.picker__nav{display:flex;justify-content:center;align-items:center;gap:1.5rem;
  margin-top:clamp(1rem,2vw,1.5rem);}
.picker__btn{
  width:44px;height:44px;flex:none;display:grid;place-items:center;
  background:transparent;border:1px solid var(--line);color:var(--ivory);
  cursor:pointer;
  transition:border-color var(--t-micro) var(--ease),color var(--t-micro) var(--ease),
             background var(--t-micro) var(--ease),opacity var(--t-micro) var(--ease);}
.picker__btn:hover:not(:disabled){border-color:var(--accent);color:var(--accent);}
.picker__btn:disabled{opacity:.3;cursor:default;}
.picker__btn svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:square;}

/* ---------- trust strip ---------- */
.strip{border-block:1px solid var(--line);background:var(--noir);}
.strip__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));}
.strip__cell{padding:clamp(1.5rem,3vw,2.25rem) 0;border-left:1px solid var(--line);padding-left:clamp(1rem,2vw,2rem);}
.strip__cell:first-child{border-left:0;padding-left:0;}
.strip__fig{font-family:"IBM Plex Mono",monospace;font-weight:500;color:var(--accent);font-size:clamp(1.75rem,3.4vw,2.75rem);line-height:1;}
.strip__lbl{margin-top:.5rem;}

/* ---------- editorial two-column ---------- */
.split{display:grid;grid-template-columns:1fr;gap:clamp(2rem,5vw,4.5rem);align-items:start;}
@media(min-width:900px){.split{grid-template-columns:1.15fr .85fr;}}

/* ---------- cards ---------- */
.grid3{display:grid;grid-template-columns:1fr;gap:1px;background:var(--line);border:1px solid var(--line);}
@media(min-width:820px){.grid3{grid-template-columns:repeat(3,1fr);}}
.card{background:var(--noir);padding:clamp(1.75rem,3vw,2.75rem);display:flex;flex-direction:column;gap:1rem;
  transition:background var(--t-std) var(--ease);}
.card:hover{background:var(--graphite);}
/* ---------- programme cards: image at rest, text on hover ----------
   At rest the card is just the collage inside a gold frame — no copy, nothing
   over the picture. On hover the image falls back out of focus and a dark panel
   rises with the text on it, which is what makes the copy readable without ever
   dimming the photograph in its resting state.

   The image lives on ::before rather than on the card, because it has to be
   blurred INDEPENDENTLY of the text. A filter on the card itself would blur the
   words too. */
/* ---------- the programmes grid: three separated panels ----------
   The base .grid3 butts its cards together with a 1px gap over a shared --line
   background, which is what made these three touch. Here they are three
   free-standing framed panels instead, so that technique is switched off and a
   real gap put in: ~2cm at desktop.

   The whole block is also narrowed. Three 1:2 panels at full container width
   would be enormous; capping the row keeps them small, which is what lets the
   full collage show without the section running away down the page. */
#programmes .grid3{
  --bind-gap:clamp(2rem,8vw,5rem);   /* >= 2cm on any desktop width */
  position:relative;
  gap:var(--bind-gap);
  background:none;border:0;
  max-width:62rem;margin-inline:auto;}

/* A spiral binding was drawn down the two gutters here to make the row read as
   a bound prospectus. It was rejected and removed — the panels stand apart. */

/* THE CROP FIX. First attempt pinned the panel to the collage's own 1:2 ratio so
   `cover` could fill it without cutting anything. That did stop the crop, but it
   made the panel's height a function of its width — and at this row width that
   left the panel 29px shorter than the full-size copy needs, so the last bullet
   was clipped on hover. Ratio and text length cannot both drive one box.

   So the box is driven by the TEXT, and the picture is fitted inside it:
   `contain` shows the whole collage whatever shape the panel ends up, and the
   grid stretches all three to the tallest. Nothing is cropped and nothing
   overflows. Any slack shows as dark band, which under the veil is invisible. */
#programmes .card--photo{
  min-height:29rem;
  padding:clamp(1rem,2vw,1.5rem);
  /* Centred, not bottom-anchored: on hover the copy is meant to fill the panel
     rather than sit in the base of it. */
  justify-content:center;gap:.75rem;}
#programmes .card--photo::before{
  background-size:contain;background-position:center;background-repeat:no-repeat;}

.card--photo{
  position:relative;overflow:hidden;isolation:isolate;
  /* White frame. Pinned to --ivory rather than --accent because the ladies' and
     mobility cards carry data-scope, which would otherwise tint two of the three
     a different colour — all three must match. */
  border:8px solid var(--ivory);
  background-color:var(--noir);background-image:none;
  transition:border-color var(--t-std) var(--ease),transform var(--t-std) var(--ease);}
.card--photo:hover,.card--photo:focus-within{
  background-color:var(--noir);
  transform:translateY(-4px);}

.card--photo::before{
  content:"";position:absolute;inset:0;z-index:-2;
  background-image:var(--card-img);
  background-size:cover;background-position:center top;
  /* Scaled up slightly so the blur has pixels to sample past every edge —
     without it a blurred layer feathers to transparent at the frame. */
  transform:scale(1.04);
  transition:filter 520ms var(--ease),transform 520ms var(--ease);}
.card--photo:hover::before,.card--photo:focus-within::before{
  filter:blur(9px) brightness(.42) saturate(.85);transform:scale(1.12);}

/* The dark panel the text sits on. Separate from the blur so the two can be
   timed differently — the panel arrives a touch faster than the defocus.
   At rest it is not fully off: a light veil sits over every card so the three
   collages sit down into the page instead of shouting off it, and so the gold
   frame reads against them. Hover takes the same layer up to full. */
.card--photo::after{
  content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(11,10,9,.72),rgba(11,10,9,.9));
  opacity:.72;transition:opacity 380ms var(--ease);}
.card--photo:hover::after,.card--photo:focus-within::after{opacity:1;}

/* The copy. Present in the DOM at all times — hidden with opacity, not
   display:none, so it stays in the layout (the card keeps its height) and stays
   available to screen readers. */
.card--photo > *{position:relative;z-index:1;
  opacity:0;transform:translateY(10px);
  transition:opacity 340ms var(--ease),transform 340ms var(--ease);}
.card--photo:hover > *,.card--photo:focus-within > *{opacity:1;transform:none;}
/* Staggered so the block assembles rather than appearing all at once. */
.card--photo:hover > *:nth-child(1),.card--photo:focus-within > *:nth-child(1){transition-delay:60ms;}
.card--photo:hover > *:nth-child(2),.card--photo:focus-within > *:nth-child(2){transition-delay:110ms;}
.card--photo:hover > *:nth-child(3),.card--photo:focus-within > *:nth-child(3){transition-delay:150ms;}
.card--photo:hover > *:nth-child(4),.card--photo:focus-within > *:nth-child(4){transition-delay:190ms;}
.card--photo:hover > *:nth-child(5),.card--photo:focus-within > *:nth-child(5){transition-delay:230ms;}

/* No hover on touch: the text would never be reachable, so it is simply always
   shown there, over a permanently dimmed image. */
@media(hover:none){
  .card--photo::before{filter:blur(6px) brightness(.4) saturate(.85);transform:scale(1.12);}
  .card--photo::after{opacity:1;}
  .card--photo > *{opacity:1;transform:none;}
}
@media(prefers-reduced-motion:reduce){
  .card--photo,.card--photo::before,.card--photo::after,.card--photo > *{transition:none;}
}

.card__rule{height:1px;background:var(--accent);width:2.5rem;transition:width var(--t-std) var(--ease);}
.card:hover .card__rule{width:100%;}
.card h3{font-family:Archivo,sans-serif;font-weight:700;font-stretch:112%;text-transform:uppercase;letter-spacing:-.01em;font-size:1.375rem;margin:0;}
.card ul{list-style:none;margin:.5rem 0 0;padding:0;display:flex;flex-direction:column;gap:.55rem;}
.card li{display:flex;gap:.7rem;font-size:.95rem;color:var(--ivory-muted);}
.card li::before{content:"";flex:none;width:5px;height:5px;margin-top:.6rem;background:var(--accent);}

/* ---------- method ---------- */
.steps{display:grid;grid-template-columns:1fr;gap:0;}
@media(min-width:820px){.steps{grid-template-columns:repeat(4,1fr);}}
.step{padding:clamp(1.5rem,2.5vw,2.25rem) 0;border-top:1px solid var(--line);padding-right:1.5rem;position:relative;}
@media(min-width:820px){.step{padding-left:1.5rem;border-left:1px solid var(--line);border-top:1px solid var(--accent-deep);}
  .step:first-child{border-left:0;padding-left:0;}}
.step__n{font-family:"IBM Plex Mono",monospace;color:var(--accent);font-size:.75rem;letter-spacing:.18em;}
.step h3{font-family:Archivo,sans-serif;font-weight:700;font-stretch:112%;text-transform:uppercase;font-size:1.125rem;margin:.75rem 0 .5rem;}
.step p{font-size:.925rem;color:var(--ivory-muted);margin:0;}

/* ---------- coaches ---------- */
.coaches{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(.75rem,1.6vw,1.5rem);}
@media(min-width:700px){.coaches{grid-template-columns:repeat(3,1fr);}}
@media(min-width:1100px){.coaches{grid-template-columns:repeat(6,1fr);}}
.coach{position:relative;}
.coach__img{aspect-ratio:3/4;position:relative;overflow:hidden;
  background:var(--graphite);
  background-image:repeating-linear-gradient(135deg,rgba(255,255,255,.022) 0 2px,transparent 2px 9px);
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);
  filter:grayscale(1) contrast(1.08) brightness(.8);
  transition:filter var(--t-std) var(--ease),border-color var(--t-std) var(--ease);}
.coach:hover .coach__img{border-color:var(--accent-deep);filter:grayscale(.25) contrast(1.02) brightness(.95);}
.coach__initial{font-family:Archivo,sans-serif;font-weight:800;font-stretch:125%;
  font-size:2.25rem;color:var(--accent-deep);opacity:.5;user-select:none;}
.coach__img img{position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:cover;}
.coach__img::after{content:"";position:absolute;inset:0;z-index:2;background:linear-gradient(0deg,rgba(11,10,9,.75),transparent 55%);}
.coach__name{margin-top:.75rem;font-family:Archivo,sans-serif;font-weight:700;font-stretch:112%;text-transform:uppercase;font-size:.9rem;letter-spacing:.01em;}
.coach__rule{height:1px;width:1.25rem;background:var(--accent);margin-top:.5rem;transition:width var(--t-std) var(--ease);}
.coach:hover .coach__rule{width:3rem;}

/* ---------- testimonials ---------- */
.quotes{display:grid;grid-template-columns:1fr;gap:1px;background:var(--line);border-block:1px solid var(--line);}
@media(min-width:820px){.quotes{grid-template-columns:repeat(3,1fr);}}
.quote{background:var(--charcoal);padding:clamp(1.75rem,3vw,2.5rem);display:flex;flex-direction:column;gap:1.25rem;}
.quote blockquote{margin:0;font-size:1.0625rem;line-height:1.6;}
.quote figcaption{display:flex;align-items:center;gap:.85rem;margin-top:auto;}
/* Monogram by default, photograph when one is supplied. Sized and ringed the
   same either way so swapping one for the other changes nothing else. */
.quote__av{width:44px;height:44px;flex:none;border-radius:50%;
  display:grid;place-items:center;
  background:radial-gradient(120% 120% at 30% 25%,rgba(201,169,97,.18),var(--graphite) 70%);
  border:1px solid var(--accent-deep);
  font-family:Archivo,sans-serif;font-weight:800;font-stretch:115%;
  font-size:1.05rem;line-height:1;color:var(--accent);
  letter-spacing:.02em;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.5);}
.quote__av--photo{background-size:cover;background-position:center;
  color:transparent;}

/* ---------- assessment ---------- */
.assess{border:1px solid var(--accent);background:
  linear-gradient(180deg,rgba(201,169,97,.07),transparent 55%),var(--noir);
  padding:clamp(1.75rem,4vw,3.25rem);margin-bottom:clamp(2rem,4vw,3.25rem);
  display:grid;grid-template-columns:1fr;gap:clamp(1.5rem,3vw,3rem);align-items:center;}
@media(min-width:900px){.assess{grid-template-columns:1.35fr .65fr;}}
.assess__badge{display:inline-block;background:var(--accent);color:var(--noir);
  font-family:"IBM Plex Mono",monospace;font-size:.65rem;letter-spacing:.16em;
  text-transform:uppercase;padding:.35rem .7rem;margin-bottom:1.1rem;font-weight:500;}
.assess h3{font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  text-transform:uppercase;letter-spacing:-.02em;line-height:1.02;
  font-size:clamp(1.6rem,3.4vw,2.6rem);margin:0 0 1rem;}
.assess__list{list-style:none;margin:1.25rem 0 0;padding:0;display:grid;gap:.55rem;}
@media(min-width:600px){.assess__list{grid-template-columns:1fr 1fr;}}
.assess__list li{display:flex;gap:.7rem;font-size:.95rem;color:var(--ivory-muted);}
.assess__list li::before{content:"";flex:none;width:5px;height:5px;margin-top:.6rem;background:var(--accent);}
.assess__price{text-align:left;border-top:1px solid var(--line);padding-top:1.5rem;}
@media(min-width:900px){.assess__price{text-align:right;border-top:0;border-left:1px solid var(--line);
  padding:0 0 0 clamp(1.5rem,3vw,2.5rem);}}
.assess__fig{font-family:"IBM Plex Mono",monospace;font-weight:500;color:var(--accent);
  font-size:clamp(2.5rem,6vw,3.75rem);line-height:1;}
.assess__cur{font-size:.9rem;color:var(--ivory-muted);letter-spacing:.14em;}
.assess__price .btn{margin-top:1.5rem;width:100%;}

/* ---------- pricing ---------- */
.tier__each{font-family:"IBM Plex Mono",monospace;font-size:.7rem;letter-spacing:.1em;
  color:var(--ivory-muted);text-transform:uppercase;}
.tier__sessions{font-family:"IBM Plex Mono",monospace;font-size:.8rem;color:var(--ivory);}
.tiers{display:grid;grid-template-columns:1fr;gap:1px;background:var(--line);border:1px solid var(--line);}
@media(min-width:900px){.tiers{grid-template-columns:repeat(3,1fr);}}
.tier{background:var(--noir);padding:clamp(1.75rem,3vw,2.75rem);display:flex;flex-direction:column;gap:1.1rem;}
.tier--featured{background:var(--graphite);position:relative;}
.tier--featured::before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--accent);}
.tier__badge{align-self:flex-start;border:1px solid var(--accent);color:var(--accent);padding:.3rem .7rem;font-family:"IBM Plex Mono",monospace;font-size:.65rem;letter-spacing:.16em;text-transform:uppercase;}
.tier h3{font-family:Archivo,sans-serif;font-weight:700;font-stretch:112%;text-transform:uppercase;font-size:1.25rem;margin:0;}
.tier__price{font-family:"IBM Plex Mono",monospace;font-size:1.9rem;color:var(--accent);line-height:1;}
/* struck former price, sized to lead the new one as on the plan rows */
.tier__was{font-size:1.35rem;color:var(--ivory-muted);opacity:.7;
  text-decoration:line-through;text-decoration-thickness:1.5px;margin-right:.3rem;}
.tier ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.6rem;}
.tier li{font-size:.925rem;color:var(--ivory-muted);display:flex;gap:.7rem;}
.tier li::before{content:"";flex:none;width:5px;height:5px;margin-top:.55rem;background:var(--accent-deep);}
.tier .btn{margin-top:auto;}

/* ---------- closing CTA ---------- */
.close{position:relative;text-align:center;overflow:hidden;}
.close__media{position:absolute;inset:0;z-index:0;background:var(--noir);
  background-image:radial-gradient(90% 120% at 50% 100%,rgba(201,169,97,.16),transparent 62%),url("images/hero/closing.jpg");
  background-size:cover;background-position:center;}
.close__scrim{position:absolute;inset:0;z-index:1;background:linear-gradient(0deg,rgba(11,10,9,.93),rgba(11,10,9,.78));}
.close .wrap{position:relative;z-index:2;}
.close h2{font-size:clamp(2rem,5.5vw,4.5rem);margin-bottom:1.5rem;}
.close .lede{margin-inline:auto;}

/* ---------- footer ---------- */
/* The footer is the same wall the opening logo is mounted on. Two layers: a
   blurred, logo-free piece of that wall, and a warm pool of light sitting where
   the mark sits. Measured, not guessed - the plate reads 18 luma and the clip's
   own surroundings read 35 to 61, so the pool lifts the plate to about 47 right
   where the video sits and falls away from there. Without it the video's lit
   side would float as a bright patch on a flat wall. */
.foot{
  /* No border. A hairline is exactly the sharp transfer we are removing - the
     wall now emerges out of the charcoal above it over 200px instead. */
  background-color:#121110;
  /* No wash, no correction. This IS the wall from the logo footage: the frame's
     own band above the mark blended into its own band below it, which removes
     the logo and leaves the real gradient, the real texture and - the point of
     all this - the real colour. Nothing is being matched to anything, so
     nothing can be mismatched. */
  /* Charcoal at both ends, wall through the middle - the same shape as section
     04, so the page opens and closes that surface the same way instead of
     stopping dead on it at the very bottom edge. */
  background-image:
    linear-gradient(to bottom,
      #131211 0,
      rgba(19,18,17,.90) 30px,
      rgba(19,18,17,.40) 120px,
      rgba(19,18,17,0) 220px,
      rgba(19,18,17,0) calc(100% - 200px),
      rgba(19,18,17,.40) calc(100% - 110px),
      rgba(19,18,17,.90) calc(100% - 30px),
      #131211 100%),
    url("images/hero/footer-wall.jpg?v=147");
  background-size:cover,cover;
  background-position:center,center;
  background-repeat:no-repeat,no-repeat;}

/* The mark. Left-aligned exactly where the old lockup sat - a signature in
   the corner, not a centrepiece. The PNG supplies only the shape; the colour is
   var(--accent), so it follows the page scope and can be retuned in one line. */
.footmark{margin-bottom:1.25rem;}
.footmark__mark{
  display:block;width:min(100%,11rem);aspect-ratio:640 / 503;
  background-color:var(--accent);
  -webkit-mask:url("images/brand/itf-logo.png?v=147") left center / contain no-repeat;
          mask:url("images/brand/itf-logo.png?v=147") left center / contain no-repeat;}

/* The footer's own divider would cut across the wall, so it softens to suit. */
.foot__bottom{border-top-color:rgba(232,230,227,.10);}
.foot__grid{display:grid;grid-template-columns:1fr;gap:2.5rem;padding-block:clamp(3rem,6vw,4.5rem);}
@media(min-width:820px){.foot__grid{grid-template-columns:2fr 1fr 1fr;}}
.foot h4{font-family:"IBM Plex Mono",monospace;font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ivory-muted);margin:0 0 1.1rem;font-weight:400;}
.foot ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.6rem;}
.foot a:hover{color:var(--accent);}
.foot__bottom{border-top:1px solid var(--line);padding-block:1.5rem;display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;}

/* ---------- full-page cover ----------
   The collage becomes the page itself: pinned behind everything and never
   dimmed, so it stays fully visible the whole way down.

   A fixed pseudo-element, not `background-attachment:fixed` — iOS Safari
   ignores that on body and it costs a repaint on every scroll frame. */
body.page--cover::before{
  content:"";position:fixed;inset:0;z-index:-2;
  background-image:var(--page-cover);
  background-size:cover;background-position:center top;background-repeat:no-repeat;}
/* An even veil over the cover — deep enough to sit the type on, light enough
   that the collage still reads. Fixed alongside the image so it never slides. */
body.page--cover::after{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(9,9,8,.94) 0%, rgba(9,9,8,.89) 14%, rgba(9,9,8,.79) 40%,
    rgba(9,9,8,.71) 70%, rgba(9,9,8,.67) 100%);}

/* hero runs clean: its own image and scrim step aside for the cover */
body.page--cover .hero__media,
body.page--cover .hero__scrim{display:none;}
body.page--cover .hero{background:transparent;min-height:100svh;}

/* Sections lose their solid fills so the collage shows through end to end. */
body.page--cover .section,
body.page--cover .section--alt,
body.page--cover .strip,
body.page--cover .picker,
body.page--cover .foot,
body.page--cover .close{background:transparent;border-color:transparent;}
body.page--cover .close__media,
body.page--cover .close__scrim{display:none;}

/* The picture is never darkened — but ivory text over a pale collage is
   unreadable, so each block of copy carries its own panel instead. The image
   stays at full strength around and between them. */
body.page--cover .section > .wrap,
body.page--cover .strip > .wrap,
body.page--cover .picker > .wrap,
body.page--cover .foot > .wrap{
  background:rgba(11,10,9,.88);
  border:1px solid rgba(147,179,168,.22);
  padding-block:clamp(1.6rem,3.2vw,2.6rem);
  border-radius:2px;}
body.page--cover .foot__bottom{border-top:1px solid var(--line);}
/* keep a little of the collage visible between panels */
body.page--cover .section{padding-block:clamp(1.6rem,3.4vw,2.8rem);}

/* ---------- booking modal ----------
   Opens over the page instead of scrolling to the bottom. The page behind is
   blurred by the overlay itself, so no filter has to be applied to <body> —
   filtering body would break the fixed nav and the spine. */
.modal{position:fixed;inset:0;z-index:200;display:grid;place-items:center;
  padding:clamp(1rem,4vw,2.5rem);
  background:rgba(6,6,5,.72);
  -webkit-backdrop-filter:blur(14px) saturate(.85);
  backdrop-filter:blur(14px) saturate(.85);
  opacity:0;visibility:hidden;
  /* visibility is stepped, not eased: transitioning it would keep the dialog
     `hidden` for the whole 320ms, and an element that is hidden cannot take
     focus — so the close button could never be focused on open. Instead it
     flips instantly when opening, and is delayed on close so the fade shows. */
  transition:opacity var(--t-std) var(--ease),visibility 0s linear var(--t-std);}
.modal.is-open{opacity:1;visibility:visible;
  transition:opacity var(--t-std) var(--ease),visibility 0s linear 0s;}

/* Sized to fit one screen with no scrolling: the panel is capped below the
   viewport height and the media column flexes to whatever height the copy
   needs, rather than the copy stretching past the fold. */
.modal__panel{
  position:relative;width:min(760px,100%);max-height:calc(100dvh - 2rem);
  overflow:hidden;background:var(--noir);border:1px solid var(--accent-deep);
  display:grid;grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr);
  transform:translateY(14px) scale(.985);
  transition:transform 460ms var(--ease);}
.modal.is-open .modal__panel{transform:none;}
/* two columns as early as possible — stacking is what made it tall */
@media(min-width:660px){.modal__panel{grid-template-columns:.8fr 1.2fr;
  grid-template-rows:minmax(0,1fr);}}

.modal__media{position:relative;background:var(--graphite);
  background-image:repeating-linear-gradient(135deg,rgba(255,255,255,.02) 0 2px,transparent 2px 9px);
  background-size:cover;background-position:center;}
/* stacked layout: keep the image a short band so the panel still fits */
@media(max-width:659px){.modal__media{height:clamp(120px,22vh,180px);}}

/* The panel is capped to the viewport and clips; the BODY is what scrolls.
   Without this a tall dialog — the plans list, now that group coaching is
   priced — silently swallowed its own lower rows, the countdown and the Book
   button, with no way to reach them. Scrolling the body rather than the panel
   keeps the picture column and the close button fixed in place.
   min-height:0 is required: a grid item's default min-height is auto, which
   refuses to shrink below its content and makes overflow-y a no-op. */
.modal__body{padding:clamp(1.25rem,2.6vw,1.9rem);display:flex;flex-direction:column;gap:.85rem;
  min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;}
.modal__eyebrow{color:var(--accent);}
.modal__title{font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  text-transform:uppercase;letter-spacing:-.02em;line-height:1.02;
  font-size:clamp(1.4rem,2.8vw,2.1rem);margin:0;}
/* word-by-word reveal: each word is its own span, staggered by JS */
.modal__title .w,.modal__lede .w{display:inline-block;opacity:0;
  transform:translateY(.35em);
  transition:opacity .42s var(--ease),transform .42s var(--ease);}
.modal__title .w.in,.modal__lede .w.in{opacity:1;transform:none;}
.modal__lede{margin:0;color:var(--ivory-muted);font-size:.98rem;line-height:1.55;}

.modal__price{display:flex;align-items:baseline;gap:.6rem;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:.85rem 0;margin-top:.2rem;
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--ease),transform .5s var(--ease);}
.modal__price.in{opacity:1;transform:none;}
.modal__fig{font-family:"IBM Plex Mono",monospace;font-weight:500;color:var(--accent);
  font-size:clamp(2rem,4.5vw,3rem);line-height:1;}
.modal__cur{font-family:"IBM Plex Mono",monospace;font-size:.85rem;letter-spacing:.14em;
  color:var(--ivory-muted);}

.modal__actions{display:flex;flex-wrap:wrap;gap:.75rem;margin-top:.4rem;
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--ease),transform .5s var(--ease);}
.modal__actions.in{opacity:1;transform:none;}
.modal__actions .btn{flex:1 1 auto;}
.btn--wa{background:var(--accent);color:var(--noir);border-color:var(--accent);
  font-weight:500;padding-block:.9rem;gap:.7rem;}
.btn--wa:hover{background:var(--accent-bright);border-color:var(--accent-bright);}
/* "Book" carries the button; the WhatsApp glyph is the quiet signal beside it. */
.wa-label{font-size:1.05rem;letter-spacing:.16em;font-weight:600;}
/* Green on gold is muddy, so the mark sits on its own dark disc — that is what
   keeps the brand green readable without cheapening the button. */
.wa-badge{width:28px;height:28px;flex:none;border-radius:50%;
  background:var(--noir);display:grid;place-items:center;}
.wa-badge svg{width:16px;height:16px;fill:#3FBF6F;}

/* ---------- promo dialog ---------- */
/* Row tracks are declared next to every column rule on purpose: the scrolling
   body only works if its grid row is allowed to shrink below its content
   (minmax(0,1fr)). Stacked layouts carry a picture band above it, hence the
   leading `auto`; two-column layouts have a single row. Change one, change the
   other, or the dialog goes back to clipping its own footer. */
.modal--promo .modal__panel{width:min(720px,100%);grid-template-columns:1fr;
  grid-template-rows:auto minmax(0,1fr);}
@media(min-width:640px){.modal--promo .modal__panel{grid-template-columns:.85fr 1.15fr;
  grid-template-rows:minmax(0,1fr);}}
.modal--promo .modal__media{background-size:cover;background-position:60% center;
  border-right:1px solid var(--line);}
/* Stacked layout: the picture becomes a short band across the top. Both promo
   images are tall portraits framed differently, so each supplies its own
   --promo-pos — a shared value crops one of them straight through the head. */
@media(max-width:639px){.modal--promo .modal__media{height:clamp(140px,24vh,200px);
  background-position:var(--promo-pos,center 25%);
  border-right:0;border-bottom:1px solid var(--line);}}
.promo__flag{align-self:flex-start;display:inline-flex;align-items:center;gap:.45rem;
  background:#E8483C;color:#0B0A09;font-family:"IBM Plex Mono",monospace;
  font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;
  font-weight:500;padding:.35rem .7rem;}
/* Three terms stacked, one row each. The figure is the only thing set large —
   the term and the note stay quiet so the eye lands on the price and then the
   saving, in that order. */
.promo__prices{display:flex;flex-direction:column;
  border-top:1px solid var(--line);padding:.2rem 0;margin:.2rem 0;}
.promo__row{display:grid;grid-template-columns:1fr auto;align-items:baseline;
  column-gap:.9rem;row-gap:.2rem;padding:.7rem 0;
  border-bottom:1px solid var(--line);}
.promo__row.is-mark{padding-inline:.7rem;margin-inline:-.7rem;
  background:var(--accent-wash);border-bottom-color:var(--accent-deep);}
.promo__term{font-family:"IBM Plex Mono",monospace;font-size:.68rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ivory);}
.promo__fig{display:flex;align-items:baseline;gap:.5rem;justify-self:end;}
.promo__note{grid-column:1/-1;font-family:"IBM Plex Mono",monospace;font-size:.6rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ivory-muted);}
.promo__old{font-family:"IBM Plex Mono",monospace;font-size:1rem;color:var(--ivory-muted);
  text-decoration:line-through;text-decoration-thickness:2px;opacity:.7;line-height:1;}
.promo__new{font-family:"IBM Plex Mono",monospace;font-weight:500;color:var(--accent);
  font-size:clamp(1.6rem,3.4vw,2.15rem);line-height:1;}
.promo__unit{font-family:"IBM Plex Mono",monospace;font-size:.58rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ivory-muted);}
/* Same unit label inside the membership modal's plan rows. */
.plan__unit{font-family:"IBM Plex Mono",monospace;font-size:.58rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ivory-muted);}

/* ---------- membership plans: poster layout ----------
   Modelled on the supplied reference: logo, figure, then price rows with the
   old price struck through. Rendered in the brand gold, not the reference red. */
/* Single column at every width. The side photograph was removed with the old
   plan-row layout — the poster below carries the artwork now, so a second grid
   column would leave the body stranded in a narrow track. */
.modal--plans .modal__panel{width:min(720px,100%);grid-template-columns:1fr;
  grid-template-rows:minmax(0,1fr);}

/* ---------- gold foil behind the whole membership window ----------
   The same texture for men and ladies — this is the brand surface the window
   sits on, not a per-scope photograph. Two layers on the panel itself rather
   than on the body, so the foil stays put while the body scrolls over it.

   The foil is painted entirely with gradients, so there is no photograph to
   fetch and nothing that can 404. To use a real foil photograph instead, add it
   as a first background-image layer below and give background-size a matching
   first value. */
.modal--plans .modal__panel{position:relative;background-color:var(--noir);}
.modal--plans .modal__panel::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:
    /* creases: two sets of streaks at opposing angles, which is what stops the
       painted version reading as a flat gradient */
    repeating-linear-gradient(114deg,
      rgba(255,255,255,.16) 0 3px, rgba(0,0,0,.13) 3px 7px, transparent 7px 19px),
    repeating-linear-gradient(64deg,
      rgba(0,0,0,.12) 0 4px, rgba(255,255,255,.11) 4px 9px, transparent 9px 23px),
    linear-gradient(128deg,
      #F3E0AC 0%, #C9A961 26%, #8C6F3C 48%, #E0C687 70%, #A9873F 88%, #D9BE7B 100%);
  background-size:cover;background-position:center;}
/* The foil is bright and busy and the dialog is dense with numbers. Held back
   far enough that it reads as a surface, but nowhere near as heavily as before —
   the price rows and the accordion bars are opaque in their own right, so the
   gold only ever shows in the margins and the gaps between them, where it can
   be strong without costing any legibility. */
.modal--plans .modal__panel::after{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(125% 95% at 50% 40%, rgba(11,10,9,.62) 0%, rgba(11,10,9,.5) 48%, rgba(11,10,9,.34) 78%, rgba(11,10,9,.24) 100%);}
/* Everything real sits above both layers. */
.modal--plans .modal__body{position:relative;z-index:1;}
.modal--plans .modal__close{z-index:2;}

.modal--plans .modal__body{padding:clamp(1.1rem,2.4vw,1.75rem);gap:.7rem;}
.plans__head{display:flex;align-items:center;gap:.7rem;}
.plans__head .mark{width:30px;height:22px;}
.plans__brand{font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  letter-spacing:.05em;text-transform:uppercase;font-size:.74rem;color:var(--ivory);}
.plans__title{font-family:Archivo,sans-serif;font-weight:800;font-stretch:120%;
  text-transform:uppercase;letter-spacing:.06em;font-size:clamp(.95rem,1.8vw,1.15rem);
  margin:.15rem 0 .2rem;color:var(--ivory);
  display:flex;align-items:center;gap:.7rem;}
.plans__title::before,.plans__title::after{content:"";height:1px;flex:1;background:var(--accent-deep);}

/* ---- the membership poster ----
   Modelled on the torn gold-foil reference: black above, a ragged gold band
   below, the price where the reference sets "LUXURY CONCEPT", and the session
   count on the gold. The gold band is the button.

   The band is painted entirely with gradients — there is no artwork file to
   fetch and nothing that can 404. To use a real foil photograph instead, add it
   as a layer in the stack below and give background-size a matching value. */
/* flex:none matters: the body is a flex column that scrolls, and without it the
   poster shrinks below its own content and overflow:hidden clips the gold band
   clean off. */
.modal--plans .modal__body > *{flex:none;}
.mposter{position:relative;overflow:hidden;isolation:isolate;
  border:1px solid var(--accent-deep);background:var(--noir);
  display:flex;flex-direction:column;}
/* The price panel carries a photograph behind it. --mposter-img is set per page
   by main.js; when the file is absent the layer simply paints nothing and the
   panel stays black, which is exactly how it looked before — so a missing photo
   costs nothing and dropping one in needs no other change. */
.mposter__top{position:relative;isolation:isolate;
  padding:clamp(1.1rem,2.6vw,1.9rem);
  display:flex;flex-direction:column;gap:.35rem;}
.mposter__top::before{content:"";position:absolute;inset:0;z-index:-2;
  background-image:var(--mposter-img,none);
  background-size:cover;background-position:center 28%;
  filter:grayscale(.25) brightness(.72);}
/* Scrim: the price is set large in ivory and has to hold over a photograph that
   is bright on one side. Weighted to the left, where the figure sits. */
.mposter__top::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(90deg,rgba(11,10,9,.92) 0%,rgba(11,10,9,.72) 42%,rgba(11,10,9,.30) 100%),
             linear-gradient(0deg,rgba(11,10,9,.80) 0%,rgba(11,10,9,.28) 62%,rgba(11,10,9,.18) 100%);}
.mposter__head{display:flex;align-items:center;gap:.6rem;margin-bottom:.2rem;}
.mposter__head .mark{width:26px;height:19px;}
.mposter__kind{font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  text-transform:uppercase;letter-spacing:.06em;font-size:.72rem;color:var(--ivory);}
.mposter__label{font-size:.6rem;letter-spacing:.24em;text-transform:uppercase;
  color:var(--ivory-muted);}
/* The price sits where the reference reads "LUXURY CONCEPT" — same weight, same
   place, so the artwork keeps its composition. */
.mposter__price{display:flex;align-items:baseline;gap:.5rem;}
.mposter__cur{font-family:"IBM Plex Mono",monospace;font-size:.8rem;letter-spacing:.14em;
  color:var(--ivory-muted);}
.mposter__fig{font-family:Archivo,sans-serif;font-weight:800;font-stretch:120%;
  letter-spacing:-.02em;line-height:.94;color:var(--ivory);
  font-size:clamp(2.6rem,8vw,4.4rem);}
.mposter__was{min-height:1.1em;}
.mposter__was s{font-family:"IBM Plex Mono",monospace;font-size:.95rem;
  color:var(--ivory-muted);text-decoration-thickness:2px;opacity:.75;}
.mposter__term{font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--accent);}

/* The gold band. A ragged top edge cut with a polygon clip so it reads as torn
   paper rather than a rectangle sitting on black. */
.mposter__cta{position:relative;display:flex;flex-direction:column;gap:.3rem;
  padding:clamp(2.4rem,6vw,3.4rem) clamp(1.1rem,2.6vw,1.9rem) clamp(1.1rem,2.4vw,1.6rem);
  margin-top:-1px;text-decoration:none;color:#1A1408;
  background-color:#C9A961;
  background-image:
    linear-gradient(118deg,rgba(255,255,255,.34) 0%,rgba(255,255,255,0) 26%),
    linear-gradient(200deg,rgba(0,0,0,.30) 0%,rgba(0,0,0,0) 34%),
    repeating-linear-gradient(104deg,rgba(255,255,255,.13) 0 2px,rgba(0,0,0,.10) 2px 5px,transparent 5px 13px),
    repeating-linear-gradient(72deg,rgba(0,0,0,.10) 0 3px,rgba(255,255,255,.09) 3px 7px,transparent 7px 16px),
    linear-gradient(160deg,#F0DCA4 0%,#C9A961 34%,#8C6F3C 66%,#D8BE7C 100%);
  background-size:cover;
  clip-path:polygon(0 12%,7% 7%,16% 11%,27% 4%,38% 9%,49% 3%,60% 8%,71% 2%,82% 7%,92% 3%,100% 8%,100% 100%,0 100%);
  transition:filter var(--t-std) var(--ease),transform var(--t-std) var(--ease);}
.mposter__cta:hover,.mposter__cta:focus-visible{filter:brightness(1.08) saturate(1.06);}
.mposter__units{font-family:Archivo,sans-serif;font-weight:800;font-stretch:115%;
  text-transform:uppercase;letter-spacing:-.01em;line-height:1;
  font-size:clamp(1.05rem,3vw,1.55rem);}
.mposter__each{font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(26,20,8,.72);}
.mposter__go{margin-top:.45rem;display:inline-flex;align-items:center;gap:.5rem;
  align-self:flex-start;
  font-family:"IBM Plex Mono",monospace;font-size:.66rem;letter-spacing:.2em;
  text-transform:uppercase;font-weight:500;
  border-bottom:1.5px solid rgba(26,20,8,.55);padding-bottom:.15rem;}
.mposter__go svg{width:14px;height:10px;fill:currentColor;
  transition:transform var(--t-std) var(--ease);}
.mposter__cta:hover .mposter__go svg{transform:translateX(4px);}
/* Painted foil, no artwork file. Two gradient layers: a sheen across the top
   and the gold body underneath. */
.mposter__cta{
  background-image:
    linear-gradient(118deg,rgba(255,255,255,.18) 0%,rgba(255,255,255,0) 28%),
    linear-gradient(160deg,#F0DCA4 0%,#C9A961 34%,#8C6F3C 66%,#D8BE7C 100%);
  background-size:cover,cover;
  background-position:center,center;
  background-repeat:no-repeat;}

/* ---- the two bars ----
   Personal sits on top and opens downward. Group sits under it and opens
   upward, which is the whole reason its inner layout is column-reversed rather
   than a second copy of the same block. Only one is ever open. */
.mbars{display:flex;flex-direction:column;gap:.4rem;}
.mbar{border:1px solid var(--line);background:var(--noir);
  transition:border-color var(--t-std) var(--ease);}
.mbar.is-open{border-color:var(--accent-deep);}
.mbar[data-k="group"]{display:flex;flex-direction:column-reverse;}
.mbar__tab{display:flex;align-items:center;gap:.7rem;width:100%;
  padding:.8rem .95rem;background:none;border:0;cursor:pointer;text-align:left;
  color:inherit;font:inherit;
  transition:background var(--t-micro) var(--ease);}
.mbar__tab:hover,.mbar__tab:focus-visible{background:rgba(201,169,97,.08);}
.mbar__name{font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  text-transform:uppercase;letter-spacing:.05em;font-size:.95rem;color:var(--ivory-muted);}
.mbar.is-open .mbar__name{color:var(--accent);}
.mbar__note{font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ivory-muted);margin-left:auto;}
/* 0fr -> 1fr animates to a height the content decides. The single inner wrapper
   is required: grid-template-rows only sizes the FIRST row, so a second child
   would land in an implicit auto row and never fold. */
.mbar__body{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows var(--t-std) var(--ease);}
.mbar.is-open .mbar__body{grid-template-rows:1fr;}
.mbar__inner{overflow:hidden;min-height:0;}

.mterms{display:grid;grid-template-columns:1fr 1fr 1fr;gap:.4rem;padding:0 .6rem .7rem;}
.mterm{display:flex;flex-direction:column;gap:.25rem;align-items:flex-start;
  padding:.6rem .65rem;cursor:pointer;color:inherit;font:inherit;text-align:left;
  border:1px solid var(--line);background:var(--charcoal);
  transition:border-color var(--t-micro) var(--ease),background var(--t-micro) var(--ease);}
.mterm:hover{border-color:var(--accent-deep);}
.mterm[aria-pressed="true"]{border-color:var(--accent);
  background:linear-gradient(160deg,rgba(201,169,97,.16),transparent 70%),var(--charcoal);}
.mterm__t{font-family:Archivo,sans-serif;font-weight:800;font-stretch:112%;
  text-transform:uppercase;font-size:.82rem;color:var(--ivory);line-height:1;}
.mterm__p{font-family:"IBM Plex Mono",monospace;font-size:.66rem;color:var(--accent);}

@media(prefers-reduced-motion:reduce){
  .mbar__body{transition:none;}
}
/* ---- countdown ----
   #E8483C is an alarm red at 5.11:1 on the dark ground — urgent without going
   neon. It now sits in normal flow near the foot of the dialog instead of
   floating over the middle of the plans, which it used to cover. */
.countdown{
  display:flex;align-items:center;justify-content:center;gap:.7rem;
  width:100%;padding:.5rem .8rem;margin-top:.2rem;
  background:rgba(11,10,9,.9);border:1px solid #E8483C;cursor:default;
  box-shadow:0 0 0 1px rgba(232,72,60,.18),0 0 22px rgba(232,72,60,.28);
  animation:alarmPulse 1.15s ease-in-out infinite;}
.countdown__label{font-family:"IBM Plex Mono",monospace;font-size:.58rem;
  letter-spacing:.16em;text-transform:uppercase;color:#F0857C;}
.countdown__time{font-family:"IBM Plex Mono",monospace;font-weight:500;color:#E8483C;
  font-size:1.15rem;line-height:1;letter-spacing:.06em;
  text-shadow:0 0 14px rgba(232,72,60,.5);}
@keyframes alarmPulse{
  0%,100%{box-shadow:0 0 0 1px rgba(232,72,60,.18),0 0 18px rgba(232,72,60,.22);}
  50%    {box-shadow:0 0 0 1px rgba(232,72,60,.42),0 0 30px rgba(232,72,60,.45);}
}
.countdown--done{border-color:var(--line);animation:none;box-shadow:none;}
.countdown--done .countdown__time,.countdown--done .countdown__label{color:var(--ivory-muted);text-shadow:none;}

/* A permanently flashing element is a genuine problem for photosensitivity and
   for anyone who finds motion distracting — so it holds still here. */
@media(prefers-reduced-motion:reduce){
  .countdown{animation:none;}
}

.plans__offer{align-self:flex-start;display:inline-flex;align-items:center;gap:.45rem;
  border:1px solid var(--accent);color:var(--accent);
  font-family:"IBM Plex Mono",monospace;font-size:.6rem;letter-spacing:.16em;
  text-transform:uppercase;padding:.35rem .7rem;margin-top:.15rem;}
.plans__foot{display:flex;flex-wrap:wrap;gap:.5rem 1.2rem;align-items:center;
  border-top:1px solid var(--line);padding-top:.7rem;margin-top:.2rem;}
.plans__cta{margin-left:auto;}

/* ---------- membership variant: one box, split three ---------- */
.modal--wide .modal__panel{width:min(1060px,100%);grid-template-columns:1fr;
  grid-template-rows:minmax(0,1fr);}
.modal--wide .modal__body{padding:clamp(1.25rem,2.6vw,2rem);gap:.9rem;}
.tiers3{display:grid;grid-template-columns:1fr;gap:1px;background:var(--line);
  border:1px solid var(--line);margin-top:.4rem;
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--ease),transform .5s var(--ease);}
.tiers3.in{opacity:1;transform:none;}
@media(min-width:720px){.tiers3{grid-template-columns:repeat(3,1fr);}}
.tier3{background:var(--noir);padding:clamp(.9rem,1.9vw,1.35rem);
  display:flex;flex-direction:column;gap:.45rem;position:relative;
  transition:background var(--t-std) var(--ease);}
.tier3:hover{background:var(--graphite);}
/* Prestige rises left to right: the top tier carries a gold wash and a rule,
   the middle a marker, the entry tier nothing. */
.tier3--top{background:linear-gradient(180deg,rgba(201,169,97,.10),transparent 58%),var(--noir);}
.tier3--top::before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--accent);}
.tier3__mark{font-family:"IBM Plex Mono",monospace;font-size:.6rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--accent);min-height:1em;}
.tier3__name{font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  text-transform:uppercase;letter-spacing:.01em;font-size:1.05rem;margin:0;color:var(--ivory);}
.tier3__term{font-family:"IBM Plex Mono",monospace;font-size:.66rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ivory-muted);}
.tier3__price{font-family:"IBM Plex Mono",monospace;font-weight:500;color:var(--accent);
  font-size:1.5rem;line-height:1;margin-top:.2rem;}
.tier3__each{font-family:"IBM Plex Mono",monospace;font-size:.62rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ivory-muted);}
.tier3 ul{list-style:none;margin:.5rem 0 0;padding:0;display:flex;flex-direction:column;gap:.3rem;}
.tier3 li{display:flex;gap:.5rem;font-size:.82rem;color:var(--ivory-muted);line-height:1.35;}
.tier3 li::before{content:"";flex:none;width:4px;height:4px;margin-top:.5rem;background:var(--accent-deep);}
.tier3__go{margin-top:auto;padding-top:.8rem;display:inline-flex;align-items:center;gap:.45rem;
  font-family:"IBM Plex Mono",monospace;font-size:.65rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent);}
.tier3:hover .tier3__go{color:var(--accent-bright);}
.tier3__go .wa-badge{width:20px;height:20px;}
.tier3__go .wa-badge svg{width:12px;height:12px;}

.modal__close{position:absolute;top:.65rem;right:.65rem;z-index:3;
  width:42px;height:42px;display:grid;place-items:center;
  background:rgba(11,10,9,.72);border:1px solid var(--line);color:var(--ivory);
  cursor:pointer;transition:border-color var(--t-micro) var(--ease),color var(--t-micro) var(--ease);}
.modal__close:hover{border-color:var(--accent);color:var(--accent);}
.modal__close svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;}

body.modal-open{overflow:hidden;}

@media(prefers-reduced-motion:reduce){
  .modal__title .w,.modal__lede .w{opacity:1;transform:none;}
  .modal__price,.modal__actions{opacity:1;transform:none;}
  .modal__panel{transform:none;}
}

/* ---------- scroll reveal ---------- */
.r{opacity:0;transform:translateY(24px);transition:opacity var(--t-reveal) var(--ease),transform var(--t-reveal) var(--ease);}
.r.in{opacity:1;transform:none;}

/* ---------- reduced motion ---------- */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{animation-duration:.001ms!important;animation-delay:0ms!important;transition-duration:.001ms!important;}
  .reveal-line>span{transform:none;}
  .r,.stars,.chooser,.hero__note{opacity:1;transform:none;}
  .hero__media{transform:none;}
  .choice:hover,.choice:focus-visible{transform:none;}
}

/* ---------- coach card <-> coach page morph ----------
   Cross-document view transitions. Chrome runs them; Safari and Firefox ignore
   the at-rule entirely and navigate normally, so this is purely additive — no
   fallback needed and nothing to feature-detect in JS.

   One shared name, `itf-coach-card`, is on exactly ONE element per page at a
   time: the profile card on coach.html, and (assigned by main.js) the card of
   the coach you actually clicked on the home page. Two elements sharing a
   view-transition-name in the same document is an error that silently cancels
   the whole transition, which is why the home page assigns it dynamically
   rather than putting it on all twelve cards. */
@view-transition{ navigation:auto; }

/* The card morph is the point of the effect, so it gets the longer, softer
   curve; the rest of the page cross-fades underneath it more quickly. */
::view-transition-group(itf-coach-card){
  animation-duration:560ms;
  animation-timing-function:cubic-bezier(.16,1,.3,1);}
::view-transition-old(root),
::view-transition-new(root){
  animation-duration:340ms;
  animation-timing-function:cubic-bezier(.16,1,.3,1);}

/* The coach page has exactly one profile card, so it can be named in CSS. */
.profile__card{view-transition-name:itf-coach-card;}

@media(prefers-reduced-motion:reduce){
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){animation-duration:.001ms!important;}
}

/* ---------- positioning section: skyline, word reveal, news ticker ---------- */
.section--grad{position:relative;overflow:hidden;isolation:isolate;}
.grad__media{position:absolute;inset:0;z-index:-2;
  background-image:url('images/hero/grad-web.jpg');
  background-size:cover;background-position:center 62%;
  /* Left bright enough to actually read as Abu Dhabi. An earlier pass sat at
     brightness(.42) under a full-bleed scrim and the skyline was effectively
     invisible — all cost, no picture. Only lightly desaturated now, so it keeps
     the site's temperature without being crushed. */
  filter:grayscale(.14) brightness(1.02) contrast(1.02);}

/* The section scrim no longer darkens the middle: it only feathers the top and
   bottom edges so the photograph dissolves into the black page above and below
   rather than starting and stopping at a line. */
.grad__scrim{position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,
    rgba(11,10,9,.9) 0%, rgba(11,10,9,.34) 14%, rgba(11,10,9,.1) 32%,
    rgba(11,10,9,.1) 68%, rgba(11,10,9,.4) 86%, rgba(11,10,9,.94) 100%);}

/* The darkening that the TYPE needs now travels with the type instead of being
   painted over the whole frame. A soft radial bed sits behind the copy and
   fades to nothing well before the edges, so the skyline stays visible around
   it while the headline and ticker keep a genuinely dark ground underneath.
   Anchored left-of-centre because that is where the headline block sits. */
.section--grad .wrap{position:relative;}
.section--grad .wrap::before{
  content:"";position:absolute;inset:-14% -10% -12% -12%;z-index:-1;
  pointer-events:none;
  background:radial-gradient(105% 112% at 26% 54%,
    rgba(9,9,8,.9) 0%, rgba(9,9,8,.82) 28%, rgba(9,9,8,.55) 52%,
    rgba(9,9,8,.22) 74%, rgba(9,9,8,0) 100%);}

.grad__h{max-width:20ch;margin-bottom:clamp(1.5rem,3.5vw,2.4rem);}

/* Word-by-word intro. This heading deliberately does NOT carry the site-wide
   `.r` reveal class: two independent gates on one element means the words can
   finish staging while the block is still at opacity 0, and the headline never
   appears. The word animation owns this element on its own.

   Each word is its own span so the line assembles rather
   than fading in as a block — the staggering is what makes it read as
   deliberate. Words are inline-block because transform does nothing on inline. */
.grad__h .w{display:inline-block;opacity:0;transform:translateY(.5em) rotate(1.2deg);
  transition:opacity .6s var(--ease),transform .6s var(--ease);}
.grad__h .w.in{opacity:1;transform:none;}

/* The ticker. Two identical rails scroll as one and the second is aria-hidden,
   so the loop is seamless without reading the sentence twice. translateX(-50%)
   lands exactly on the start of the copy, which is why the duplicate has to be
   an exact duplicate. */
.ticker{position:relative;overflow:hidden;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:.9rem 0;
  /* Fade both ends so text enters and leaves rather than being cut by an edge. */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 6%,#000 94%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 6%,#000 94%,transparent 100%);}
.ticker__rail{display:flex;width:max-content;
  animation:tickerRun 42s linear infinite;}
.ticker__item{flex:none;padding-right:4rem;white-space:nowrap;
  color:var(--ivory-muted);font-size:clamp(.95rem,1.3vw,1.05rem);}
.ticker__item b{color:var(--accent);font-weight:500;}
@keyframes tickerRun{ from{transform:translateX(0);} to{transform:translateX(-50%);} }
.ticker:hover .ticker__rail{animation-play-state:paused;}

@media(prefers-reduced-motion:reduce){
  .grad__h .w{opacity:1;transform:none;}
  .ticker__rail{animation:none;}
  /* Without the marquee the duplicate is dead weight and would just repeat. */
  .ticker__item[aria-hidden="true"]{display:none;}
  .ticker__item{white-space:normal;}
}

/* ---------- coach clip dialog ----------
   One dialog, one <video>, src swapped per coach — twelve cards must not mean
   twelve idle decoders. Sized to the clip rather than the panel so a 16:9 video
   never sits in a letterboxed box. */
.modal--clip .modal__panel{
  width:min(980px,100%);grid-template-columns:1fr;grid-template-rows:auto auto;
  background:#000;border-color:var(--accent-deep);}
.clip__video{display:block;width:100%;height:auto;max-height:76vh;
  background:#000;aspect-ratio:16/9;}
/* A vertical clip in a 980px-wide 16:9 box is a postage stamp between two black
   slabs. When main.js reports the loaded video is taller than it is wide, the
   panel narrows and the box flips to 9:16 so the picture fills it.
   aspect-ratio is kept (rather than left to the intrinsic size) so the panel
   does not resize under the viewer between metadata and first frame. */
/* Width is derived from the height cap, not chosen independently: at 9/16 a
   panel 430px wide wants to be 764px tall, so on any normal viewport the
   max-height would kick in and letterback the video sideways inside its own
   box. 45vh is exactly 80vh × 9/16 — the widest the panel can be while the
   clip still fits vertically, so the picture fills it edge to edge. */
.modal--clip.is-portrait .modal__panel{width:min(430px,45vh);}
.modal--clip.is-portrait .clip__video{aspect-ratio:9/16;max-height:80vh;}
.clip__who{margin:0;padding:.85rem clamp(1rem,2.4vw,1.5rem);
  font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--accent);border-top:1px solid var(--line);background:var(--noir);}
/* The close button sits over the video, so it needs its own ground to stay
   visible against whatever frame is playing behind it. */
.modal--clip .modal__close{background:rgba(11,10,9,.72);}

/* ---------- "why here" figure ----------
   Carries the door-to-door claim on the ladies' pages: a coach arriving at a
   home with her own mat. It replaced a stock shot of a women-only gym floor —
   which was another company's branded premises AND depicted a facility this
   business does not have. Both reasons matter; keep this one honest. */
/* In the left column beneath the headline, so it fills that column rather than
   the whole wrap — that is what keeps this section short. */
.whyfig{margin:clamp(1.25rem,2.5vw,1.75rem) 0 0;}
.whyfig img{display:block;width:100%;height:auto;
  border:1px solid var(--line);
  /* Cooled and pulled down a touch: the source is a warm, brightly-lit living
     room and sits next to near-black sections on either side. */
  filter:brightness(.9) saturate(.94);}
.whyfig figcaption{margin-top:.7rem;font-size:.62rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ivory-muted);}

/* ---------- "why here": headline over, picture and copy level beneath ----------
   Three children in one grid rather than two columns each holding a stack. The
   headline spans the full row, then the figure and the copy start on the SAME
   grid row — which is what puts them level. Nesting the figure under the h2 in a
   left-hand column instead left the copy starting 200px higher. */
@media(min-width:900px){
  .split--why{grid-template-columns:1.05fr .95fr;
    column-gap:clamp(2rem,4vw,3.5rem);row-gap:clamp(1.25rem,2.5vw,2rem);}
  .split--why > .h2{grid-column:1 / -1;margin-bottom:0;}
  /* The figure carries its own top margin for the stacked layout; here the
     grid row-gap does that job, so zero it or it drops below the copy. */
  .split--why > .whyfig{margin-top:0;}
}

/* ---------- the session count as a struck-gold plaque ----------
   The number of sessions is what people actually compare between tiers, so it
   is set as a gold plaque with a sheen travelling across it rather than left as
   body text. The sweep is a moving background-position on a wide gradient — the
   same technique as the caption shine, and cheap because only one property
   animates.

   Pinned to --gold, not --accent: the ladies' pages re-point the accent to jade
   and the plaque has to read as gold on every page. */
.tier__n{
  display:inline-block;vertical-align:-.08em;
  font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  font-size:clamp(1.5rem,3vw,2.1rem);line-height:1;letter-spacing:-.02em;
  padding:.16em .38em;margin-right:.34em;
  color:#1A1408;
  border:1px solid var(--gold-bright);
  background-image:linear-gradient(100deg,
    #8C6F3C 0%, var(--gold) 30%, #FFF3D4 46%, var(--gold-bright) 54%,
    var(--gold) 70%, #8C6F3C 100%);
  background-size:280% 100%;
  background-position:100% 0;
  box-shadow:0 0 0 1px rgba(0,0,0,.5),0 6px 18px rgba(201,169,97,.22);
  animation:plaqueSweep 4.6s var(--ease) 1s infinite;}

/* On the poster the plaque sits ON the gold band, so a gold-on-gold plaque
   would vanish. Inverted there: dark plaque, gold numeral. */
.mposter__n{
  display:inline-block;vertical-align:-.06em;
  font-family:Archivo,sans-serif;font-weight:800;font-stretch:118%;
  font-size:clamp(1.7rem,4.2vw,2.6rem);line-height:1;letter-spacing:-.02em;
  padding:.1em .32em;margin-right:.3em;
  color:var(--gold-bright);
  background-color:#120E06;
  background-image:linear-gradient(100deg,
    #120E06 0%, #221A0B 42%, #3A2D12 50%, #221A0B 58%, #120E06 100%);
  background-size:280% 100%;
  background-position:100% 0;
  border:1px solid rgba(0,0,0,.55);
  box-shadow:0 4px 14px rgba(0,0,0,.4);
  animation:plaqueSweep 4.6s var(--ease) 1s infinite;}

@keyframes plaqueSweep{
  0%        {background-position:100% 0;}
  42%,100%  {background-position:0% 0;}
}
@media(prefers-reduced-motion:reduce){
  .tier__n,.mposter__n{animation:none;background-position:0 0;}
}

/* ---------- membership poster: sessions lead, price follows ----------
   The three tiers differ by how much coaching you get, so the session count now
   holds the big slot the price used to, and the price drops to the gold band
   underneath it. Reversing that hierarchy is the whole point of this block. */
.mposter__hero{display:flex;align-items:baseline;gap:.55rem;flex-wrap:wrap;}
.mposter__count{
  font-family:Archivo,sans-serif;font-weight:800;font-stretch:120%;
  letter-spacing:-.03em;line-height:.9;color:var(--ivory);
  font-size:clamp(3.2rem,10vw,5.4rem);
  /* Gold sheen travelling through the numerals themselves — painted into the
     glyphs, so it reads as struck metal rather than a highlighter behind them. */
  background-image:linear-gradient(100deg,
    var(--gold) 0%, var(--gold) 34%, #FFF6DF 46%, var(--gold-bright) 54%,
    var(--gold) 66%, var(--gold) 100%);
  background-size:280% 100%;background-position:100% 0;
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
  animation:plaqueSweep 4.6s var(--ease) .8s infinite;}
.mposter__countlbl{font-size:.72rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ivory);}
/* No clip support: fall back to solid gold rather than invisible numerals. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .mposter__count{-webkit-text-fill-color:var(--gold);color:var(--gold);}
}

.mposter__save{min-height:1.1em;font-family:"IBM Plex Mono",monospace;
  font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--gold);}
.mposter__save span{color:var(--ivory-muted);}

/* The gold band: price on the left, one large centred action. */
.mposter__cta{display:flex;flex-direction:column;align-items:center;gap:.9rem;}
.mposter__money{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;
  justify-content:center;}
.mposter__money .mposter__cur{font-family:"IBM Plex Mono",monospace;
  font-size:.72rem;letter-spacing:.14em;color:#3A2D12;}
.mposter__money .mposter__fig{font-family:Archivo,sans-serif;font-weight:800;
  font-stretch:118%;letter-spacing:-.02em;line-height:1;color:#1A1408;
  font-size:clamp(1.5rem,4vw,2.1rem);}
.mposter__money .mposter__each{font-family:"IBM Plex Mono",monospace;
  font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;color:#3A2D12;}

/* Book now: the one action on the poster, so it is a real button — wide,
   centred, dark on gold so it reads against the band it sits on. */
.mposter__go{display:inline-flex;align-items:center;justify-content:center;gap:.6rem;
  /* Narrower than it was. The wordmark in the footage sits directly behind
     this button, and at 320px the button covered it end to end. */
  width:min(224px,100%);padding:.72rem 1.1rem;
  font-family:Archivo,sans-serif;font-weight:800;font-stretch:115%;
  font-size:.8rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--gold-bright);background:#120E06;text-decoration:none;
  border:1px solid rgba(0,0,0,.5);
  box-shadow:0 8px 24px rgba(0,0,0,.38);
  transition:transform var(--t-std) var(--ease),box-shadow var(--t-std) var(--ease),
             color var(--t-micro) var(--ease);}
.mposter__go svg{width:15px;height:11px;fill:currentColor;
  transition:transform var(--t-std) var(--ease);}
.mposter__go:hover,.mposter__go:focus-visible{
  color:#FFF6DF;transform:translateY(-2px);
  box-shadow:0 12px 30px rgba(0,0,0,.5);}
.mposter__go:hover svg,.mposter__go:focus-visible svg{transform:translateX(5px);}

/* ---------- team grid: whole card is the link ----------
   .coach is now an <a>, so it has to be reset from the site's default link
   styling and given the affordances a card needs: a pointer, a lift on hover,
   and a visible focus ring for keyboard users. */
.coach{display:block;text-decoration:none;color:inherit;cursor:pointer;
  transition:transform var(--t-std) var(--ease);}
.coach:hover,.coach:focus-visible{transform:translateY(-4px);}
.coach:focus-visible{outline:2px solid var(--accent);outline-offset:6px;}
/* The photograph is desaturated at rest and comes to life on hover — the same
   language the picker cards use, so both read as the same kind of object. */
.coach:hover .coach__img,.coach:focus-visible .coach__img{
  filter:grayscale(0) contrast(1.02) brightness(.95);
  border-color:var(--accent-deep);}
.coach__name{transition:color var(--t-micro) var(--ease);}
.coach:hover .coach__name,.coach:focus-visible .coach__name{color:var(--accent);}
/* "View profile" is the cue that the card goes somewhere. Held back until
   hover so the grid stays quiet when you are just scanning faces. */
.coach__go{display:block;margin-top:.4rem;
  font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);
  opacity:0;transform:translateY(-3px);
  transition:opacity var(--t-std) var(--ease),transform var(--t-std) var(--ease);}
.coach:hover .coach__go,.coach:focus-visible .coach__go{opacity:1;transform:none;}
/* Touch has no hover, so the cue is simply always visible there. */
@media(hover:none){
  .coach__go{opacity:1;transform:none;}
}

/* The line that closes the programmes row. Set in the same display face as the
   section heading above it, one step down in size, so the two read as a pair. */
.progs__pick{
  margin:clamp(1.75rem,3.5vw,2.75rem) auto 0;
  text-align:center;
  font-family:Archivo,system-ui,sans-serif; font-weight:700;
  font-stretch:118%; letter-spacing:-.02em; line-height:1.05;
  text-transform:uppercase;
  font-size:clamp(1.25rem,2.6vw,2rem);
  color:var(--ivory);}

/* ============================================================
   MOBILE ONLY — folded sections and the swiped quote rail
   Everything below is inside a narrow query. Nothing here reaches the desktop
   layout; above 819px the accordion headers are hidden and the wrapper the
   script inserts is a plain block, so the page renders exactly as before.
   ============================================================ */
@media(max-width:819px){

  /* The title line. Full width, tall enough to hit with a thumb, and carrying
     the section number so the folded page still reads as an ordered document. */
  .acc__head{
    -webkit-appearance:none;appearance:none;
    display:grid;grid-template-columns:auto 1fr auto;align-items:center;
    gap:.9rem;width:100%;
    padding:1.35rem clamp(1.25rem,5vw,1.75rem);
    background:var(--noir);color:var(--ivory);
    border:0;border-top:1px solid var(--line);
    text-align:left;cursor:pointer;
    font-family:Archivo,system-ui,sans-serif;font-weight:700;
    font-stretch:118%;letter-spacing:-.01em;line-height:1.1;
    font-size:1.0625rem;text-transform:uppercase;}
  [data-acc]:last-of-type .acc__head{border-bottom:1px solid var(--line);}
  .acc__num{font-size:.7rem;color:var(--accent);opacity:.9;letter-spacing:.14em;}
  .acc__label{min-width:0;}

  /* Plus turning to minus. Two bars, one rotated, so there is no icon font and
     nothing to load. */
  .acc__sign{position:relative;width:14px;height:14px;flex:none;}
  .acc__sign::before,.acc__sign::after{
    content:"";position:absolute;left:0;top:50%;width:14px;height:1.5px;
    background:var(--accent);transform-origin:50% 50%;
    transition:transform var(--t-med,.35s) var(--ease,ease);}
  .acc__sign::after{transform:rotate(90deg);}
  [data-acc-open="true"] > .acc__head .acc__sign::after{transform:rotate(0deg);}
  [data-acc-open="true"] > .acc__head{background:var(--charcoal);}
  [data-acc-open="true"] > .acc__head .acc__label{color:var(--accent);}

  /* Closed panels are removed from layout rather than merely clipped: these
     sections carry background images and a marquee, and a zero-height box with
     overflow hidden still costs paint and keeps the animation running. */
  [data-acc][data-acc-open="false"] > .acc__body{display:none;}
  [data-acc][data-acc-open="true"]  > .acc__body{
    display:block;
    animation:accIn .45s var(--ease,ease) both;}
  @keyframes accIn{from{opacity:0;transform:translateY(-8px);}to{opacity:1;transform:none;}}

  /* The section's own vertical padding now belongs to the header, otherwise a
     folded list has a finger-width of dead space between every line. */
  [data-acc]{padding-block:0 !important;}
  [data-acc] > .acc__body > .wrap{padding-block:clamp(2rem,7vw,3rem);}
  [data-acc].section--grad > .acc__body{position:relative;overflow:hidden;}

  /* The header already says the name, so drop the label that repeats it. */
  [data-acc] .tick{display:none;}
  [data-acc] .picker__title{display:none;}
  [data-acc] .picker__head{margin-bottom:1.5rem;}

  /* ---- quote rail ---- */
  .quotes{
    display:flex;gap:0;background:none;
    overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    scrollbar-width:none;}
  .quotes::-webkit-scrollbar{display:none;}
  .quote{
    flex:0 0 100%;scroll-snap-align:start;scroll-snap-stop:always;
    border-right:1px solid var(--line);}

  /* Bigger portrait circle: on a phone it is the only face in the section. */
  .quote__av{width:54px;height:54px;font-size:1.25rem;}

  .quotes__dots{display:flex;justify-content:center;gap:.6rem;
    padding:1.25rem 0 0;}
  .quotes__dot{-webkit-appearance:none;appearance:none;
    width:7px;height:7px;padding:0;border-radius:50%;cursor:pointer;
    border:1px solid var(--accent-deep);background:transparent;
    transition:background var(--t-fast,.2s) var(--ease,ease),
               transform var(--t-fast,.2s) var(--ease,ease);}
  .quotes__dot.is-on{background:var(--accent);transform:scale(1.35);}
}

/* Above the phone query the inserted wrapper must behave like the section's
   original child list, and the header and dots must not exist. */
@media(min-width:820px){
  .acc__head{display:none;}
  .acc__body{display:block;}
  .quotes__dots{display:none;}
}

/* ============================================================
   MEMBERSHIP POSTER — the photograph is the poster
   The gold torn band used to take the lower half, which meant half the
   photograph was never seen. It is gone. The picture now runs the full height
   and the price sits on it inside a framed plaque with a shine crossing it.
   ============================================================ */

/* The photograph, full bleed. --mposter-img now sits on .mposter itself, so
   the layer covers the whole card rather than only its top half. A missing
   file still paints nothing and costs nothing, exactly as before. */
.mposter{min-height:clamp(20rem,44vw,26rem);}
.mposter::before{content:"";position:absolute;inset:0;z-index:0;
  background-image:var(--mposter-img,none);
  background-size:cover;background-position:center 26%;
  filter:grayscale(.12) brightness(.86) contrast(1.04);}
/* Readability without hiding the picture: dark where the type sits — the top
   strip and the bottom plaque — and close to clear through the middle, which
   is the part of the frame worth showing. */
.mposter::after{content:"";position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(180deg,
      rgba(11,10,9,.90) 0%, rgba(11,10,9,.72) 18%, rgba(11,10,9,.34) 34%,
      rgba(11,10,9,.22) 50%, rgba(11,10,9,.52) 72%, rgba(11,10,9,.88) 100%),
    linear-gradient(90deg,
      rgba(11,10,9,.72) 0%, rgba(11,10,9,.34) 44%, rgba(11,10,9,.10) 100%);}
.mposter > *{position:relative;z-index:2;}

/* The old per-half image and scrim are retired — the card carries both now. */
.mposter__top::before,.mposter__top::after{content:none;}

/* The torn gold band is gone: no foil, no clip path, no artwork layer. What is
   left is a transparent footer pinned to the bottom of the picture. */
.mposter__cta{
  background:none;background-image:none;clip-path:none;
  margin-top:auto;padding:clamp(1rem,2.4vw,1.5rem) clamp(1.1rem,2.6vw,1.9rem)
                          clamp(1.3rem,2.8vw,1.8rem);
  gap:1rem;}
.mposter__cta:hover{filter:none;transform:none;}

/* ---- the price plaque ----
   A hairline gold rectangle with its corners drawn in, holding the figure over
   the photograph. The frame is what the eye lands on; the shine is what keeps
   it from looking like a plain box. */
.mposter__money{
  position:relative;isolation:isolate;overflow:hidden;
  padding:.85rem 1.75rem;
  background:linear-gradient(180deg,rgba(9,9,8,.82),rgba(9,9,8,.66));
  border:1px solid var(--gold);
  box-shadow:0 0 0 1px rgba(0,0,0,.55),
             0 18px 38px rgba(0,0,0,.45),
             0 0 26px rgba(201,169,97,.14);}

/* Corner ticks: eight one-pixel rules drawn as background layers, so four
   bracketed corners cost no extra elements. */
.mposter__money::before{content:"";position:absolute;inset:5px;z-index:1;
  pointer-events:none;opacity:.9;
  background-repeat:no-repeat;
  background-image:
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright)),
    linear-gradient(var(--gold-bright),var(--gold-bright));
  background-size:11px 1px,1px 11px, 11px 1px,1px 11px,
                  11px 1px,1px 11px, 11px 1px,1px 11px;
  background-position:
    left top,left top, right top,right top,
    left bottom,left bottom, right bottom,right bottom;}

/* The shine. A narrow band of warm white crossing the plaque on the same 4.6s
   beat as the session numerals above it, so the two read as one movement
   rather than two things blinking independently. */
.mposter__money::after{content:"";position:absolute;inset:0;z-index:2;
  pointer-events:none;
  background-image:linear-gradient(104deg,
    rgba(255,246,223,0) 40%,
    rgba(255,246,223,.10) 46%,
    rgba(255,246,223,.46) 50%,
    rgba(255,246,223,.10) 54%,
    rgba(255,246,223,0) 60%);
  background-size:260% 100%;background-repeat:no-repeat;
  background-position:170% 0;
  animation:plaqueShine 4.6s var(--ease) 1.1s infinite;}
@keyframes plaqueShine{
  0%       {background-position:170% 0;}
  36%,100% {background-position:-70% 0;}
}
@media(prefers-reduced-motion:reduce){
  .mposter__money::after{animation:none;background-position:-70% 0;}
}

/* On the photograph the figure has to be the bright thing, so it is ivory and
   the currency and rate around it drop to gold. */
.mposter__money .mposter__cur{color:var(--gold);}
.mposter__money .mposter__fig{color:var(--ivory);
  font-size:clamp(1.7rem,4.4vw,2.35rem);
  text-shadow:0 2px 12px rgba(0,0,0,.6);}
.mposter__money .mposter__each{color:var(--ivory-muted);}

/* Book now: solid gold against the picture — the only filled shape on the card
   now that the band is gone, so there is no question what to press. */
.mposter__go{
  /* The very first version of this button sat at the left edge of a gold band.
     It is centred under the plaque now, so that alignment has to be undone. */
  align-self:center;
  background:linear-gradient(160deg,#F0DCA4 0%,var(--gold) 38%,#B99A55 100%);
  color:#120E06;border:1px solid var(--gold-bright);
  box-shadow:0 10px 26px rgba(0,0,0,.45);}
.mposter__go:hover,.mposter__go:focus-visible{
  color:#120E06;filter:brightness(1.07);
  box-shadow:0 14px 32px rgba(0,0,0,.55),0 0 22px rgba(201,169,97,.3);}

/* The label reads as a caption to the number rather than a word beside it, so
   it stacks underneath. Baseline alignment has nothing left to align once the
   two are on separate lines, hence the reset to a column. */
.mposter__hero{flex-direction:column;align-items:flex-start;gap:.2rem;}
.mposter__countlbl{padding-left:.12em;}

/* ============================================================
   BRAND INTRO
   A full-screen logo that shrinks into the header wordmark. It covers the page
   for well under three seconds, once per session, and the document behind it is
   already parsed - nothing here gates content, only the view of it.
   ============================================================ */
[data-intro="off"] .intro{display:none;}

.intro{
  position:fixed;inset:0;z-index:9000;
  display:grid;place-items:center;
  /* The wall behind the logo, taken from a logo-free strip of the same footage
     and stretched across the whole viewport. It is blurred and 8 KB: it is a
     dark textured surface, so detail is wasted on it and scaling costs nothing
     that can be seen. The black underneath covers it if it ever fails. */
  background-color:var(--noir);
  /* Two layers. The plate is a flat piece of wall cut from the left of the
     frame; the gradient above it puts the light back. The footage is lit from
     the upper right - measured luma runs 16 on the left edge to 42 on the right
     - so a flat plate would leave the video's bright side glowing as a patch.
     This warm wash is tuned to land the top right near 40 and fade out before
     the bottom left, which is already the right value. */
  background-image:
    linear-gradient(205deg,
      rgba(214,190,140,.13) 0%,
      rgba(214,190,140,.05) 34%,
      rgba(214,190,140,0) 62%),
    url("images/hero/intro-plate.jpg?v=134");
  background-size:cover,cover;background-position:center,center;
  /* Its own stacking context so the shrinking video cannot be painted over by
     anything the page raises while the overlay is still up. */
  isolation:isolate;
  transition:opacity .5s var(--ease),visibility .5s var(--ease);}

/* The video stays exactly the size it was. Enlarging it to fill the screen
   would enlarge the logo past its own resolution, which is the one thing that
   cannot be undone - so the wall grows instead and the mark does not. */
.intro__vid{
  width:min(62vw,660px);height:auto;display:block;
  transform-origin:center center;
  will-change:transform,opacity;
  /* Its edges dissolve into the plate rather than ending on a seam. The opaque
     core runs to 72% of the half-height, and the artwork stops at 82% of the
     frame - so the feather only ever eats empty wall, never the lettering. */
  -webkit-mask-image:radial-gradient(ellipse closest-side at 50% 50%,
    #000 0 72%, rgba(0,0,0,.55) 88%, transparent 100%);
  mask-image:radial-gradient(ellipse closest-side at 50% 50%,
    #000 0 72%, rgba(0,0,0,.55) 88%, transparent 100%);}

/* The skip. Quiet until wanted - nobody should have to hunt for the way out,
   and nobody should be shouted at by an escape hatch either. */
.intro__skip{
  position:absolute;right:clamp(1rem,3vw,2rem);bottom:clamp(1rem,3vw,2rem);
  -webkit-appearance:none;appearance:none;cursor:pointer;
  background:none;border:1px solid rgba(232,230,227,.22);
  color:var(--ivory-muted);
  font-family:"IBM Plex Mono",monospace;font-size:.62rem;
  letter-spacing:.2em;text-transform:uppercase;
  padding:.55rem 1.1rem;
  opacity:0;animation:introSkipIn .4s var(--ease) 1s forwards;
  transition:color var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);}
.intro__skip:hover,.intro__skip:focus-visible{
  color:var(--gold);border-color:var(--gold);}
@keyframes introSkipIn{to{opacity:1;}}

/* The minimize. The video travels to the header wordmark and fades as it goes;
   JS supplies the distance and scale as custom properties because only it knows
   where the brand actually sits at this viewport. */
.intro.is-closing{background:transparent;}
.intro.is-closing .intro__vid{
  transform:translate(var(--intro-dx,0),var(--intro-dy,0)) scale(var(--intro-s,.12));
  opacity:0;
  transition:transform .85s cubic-bezier(.65,0,.2,1),
             opacity .85s cubic-bezier(.65,0,.2,1);}
.intro.is-closing .intro__skip{opacity:0;transition:opacity .2s;}
.intro.is-done{opacity:0;visibility:hidden;pointer-events:none;}

/* The header catches it: the wordmark flares gold exactly as the video lands. */
.nav__brand.is-caught{
  animation:brandCatch .9s var(--ease) both;}
@keyframes brandCatch{
  0%   {filter:none;}
  30%  {filter:drop-shadow(0 0 2px var(--gold-bright)) drop-shadow(0 0 9px rgba(201,169,97,.75));}
  100% {filter:none;}
}

/* While the overlay is up the page must not scroll under it. */
html[data-intro="on"].intro-lock,
html[data-intro="on"].intro-lock body{overflow:hidden;}

@media(prefers-reduced-motion:reduce){
  .intro{display:none;}
}

/* ============================================================
   WALL SECTIONS
   The same surface as the footer, on any section that asks for it. The wall is
   painted on a pseudo-element and MASKED at top and bottom rather than covered
   by a scrim in the neighbour's colour. That matters: these sections sit next
   to different things - charcoal on the homepage, the page's own noir on the
   ladies pages - and a mask fades the wall out to reveal whatever is actually
   behind it, so nothing has to be told what its neighbour is.
   ============================================================ */
.section--wall{position:relative;isolation:isolate;}
.section--wall::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:#121110 url("images/hero/footer-wall.jpg?v=158") center / cover no-repeat;
  -webkit-mask-image:linear-gradient(to bottom,
    transparent 0, #000 270px, #000 calc(100% - 270px), transparent 100%);
          mask-image:linear-gradient(to bottom,
    transparent 0, #000 270px, #000 calc(100% - 270px), transparent 100%);}
/* Short sections would be all fade and no wall, so they get a gentler one. */
@media(max-width:819px){
  .section--wall::before{
    -webkit-mask-image:linear-gradient(to bottom,
      transparent 0, #000 150px, #000 calc(100% - 150px), transparent 100%);
            mask-image:linear-gradient(to bottom,
      transparent 0, #000 150px, #000 calc(100% - 150px), transparent 100%);}
}

/* ---------- membership poster: the logo footage behind it ----------
   Replaces the photograph that --mposter-img used to paint. It sits in the same
   slot in the stack, so the existing scrim still does its job over the top. */
.mposter__vid{
  position:absolute;inset:0;z-index:-2;
  width:100%;height:100%;object-fit:cover;
  pointer-events:none;}
/* The photo layer is retired: nothing sets --mposter-img any more, but the rule
   would still paint the fallback, so it is switched off explicitly. */
.mposter::before{content:none;}
@media(prefers-reduced-motion:reduce){
  /* Still a background, just a still one - the poster frame is the same image. */
  .mposter__vid{display:block;}
}

/* ---------- membership poster: price to the top right ----------
   The plaque is lifted out of the flow and pinned into the corner, so the
   session count keeps the big slot on the left and the figure sits opposite it
   rather than underneath. Padding on the top block reserves the room, so the
   two can never run into each other. */
.mposter__top{position:relative;padding-right:clamp(9rem,30%,13rem);}
.mposter__money{
  position:absolute;
  top:clamp(1.1rem,2.6vw,1.9rem);
  right:clamp(1.1rem,2.6vw,1.9rem);
  flex-direction:column;align-items:flex-end;gap:.15rem;
  padding:.7rem 1rem;
  text-align:right;}
.mposter__money .mposter__fig{font-size:clamp(1.35rem,3.4vw,1.85rem);}
.mposter__money .mposter__each{font-size:.58rem;}

/* The band below now carries the one action, so it centres on it alone. */
.mposter__cta{justify-content:center;}

@media(max-width:560px){
  /* Too narrow for two columns: the plaque returns to the flow underneath the
     session count rather than being squeezed into a corner it cannot fit. */
  .mposter__top{padding-right:clamp(1.1rem,2.6vw,1.9rem);}
  .mposter__money{
    position:static;align-self:flex-start;align-items:baseline;
    flex-direction:row;text-align:left;margin-top:.9rem;}
}

/* ============================================================
   LADIES' MEMBERSHIP DIALOG — SILVER, NOT GOLD
   The ladies' dialog plays the silver cut of the logo film, so every gold
   surface in it would be arguing with the metal on screen. These values are
   sampled from that footage rather than invented: the metal measures
   rgb(210,212,216) at its highlights, rgb(159,163,167) through the body and
   rgb(122,127,132) on the shadow side - a genuinely COOL silver, blue a couple
   of points above red, which is why a neutral grey would still look wrong.
   Scoped to [data-scope="jade"], so the men's dialog is untouched.
   ============================================================ */
[data-scope="jade"]{
  --silver:#9FA3A7; --silver-bright:#D2D4D8; --silver-deep:#7A7F84;}

/* The frame: the foil border around the whole panel. */
[data-scope="jade"] .modal--plans .modal__panel::before{
  background-image:
    repeating-linear-gradient(114deg,
      rgba(255,255,255,.18) 0 3px, rgba(0,0,0,.13) 3px 7px, transparent 7px 19px),
    repeating-linear-gradient(64deg,
      rgba(0,0,0,.12) 0 4px, rgba(255,255,255,.12) 4px 9px, transparent 9px 23px),
    linear-gradient(128deg,
      #E4E7EA 0%, #9FA3A7 26%, #6B7076 48%, #D2D4D8 70%, #83888E 88%, #C3C7CB 100%);}

/* The price plaque and its corner ticks. */
[data-scope="jade"] .mposter__money{
  border-color:var(--silver);
  box-shadow:0 0 0 1px rgba(0,0,0,.55),
             0 18px 38px rgba(0,0,0,.45),
             0 0 26px rgba(159,163,167,.16);}
[data-scope="jade"] .mposter__money::before{
  background-image:
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright)),
    linear-gradient(var(--silver-bright),var(--silver-bright));}
[data-scope="jade"] .mposter__money .mposter__cur{color:var(--silver);}

/* Book now: silver on the same dark plate, dark text for contrast. */
[data-scope="jade"] .mposter__go{
  background:linear-gradient(160deg,#E4E7EA 0%,var(--silver) 38%,#7A7F84 100%);
  color:#14161A;border-color:var(--silver-bright);}
[data-scope="jade"] .mposter__go:hover,
[data-scope="jade"] .mposter__go:focus-visible{
  color:#14161A;
  box-shadow:0 14px 32px rgba(0,0,0,.55),0 0 22px rgba(159,163,167,.32);}

/* The session count keeps its struck-metal sweep, in silver. */
[data-scope="jade"] .mposter__count{
  background-image:linear-gradient(100deg,
    var(--silver) 0%, var(--silver) 34%, #FFFFFF 46%, var(--silver-bright) 54%,
    var(--silver) 66%, var(--silver) 100%);}
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  [data-scope="jade"] .mposter__count{
    -webkit-text-fill-color:var(--silver);color:var(--silver);}
}
[data-scope="jade"] .mposter__save{color:var(--silver);}

/* A trust-strip cell whose figure is a word, not a numeral. The display size is
   tuned for two or three digits; a nine-letter word at that size overflows the
   cell on a phone, so it steps down and stops competing with the real numbers
   either side of it. */
.strip__fig--word{
  font-size:clamp(1.35rem,3.4vw,2.1rem);
  letter-spacing:-.01em;}

/* ---------- chooser on phones: stacked, and square ----------
   Side by side, each box is barely wider than half a phone screen and the
   photograph inside it has almost no room. Stacked they get the full column
   width, so the same boxes become roughly four times the area and the artwork
   inside them is finally legible.

   aspect-ratio rather than a min-height: the boxes are full-width here, so a
   1:1 ratio makes them genuinely square at every phone size without a
   hand-tuned height per breakpoint. min-height has to be cleared or it would
   still win on the taller phones. */
@media(max-width:700px){
  .chooser{flex-direction:column;gap:.85rem;}
  .choice{
    flex:none;
    aspect-ratio:1 / 1;
    min-height:0;
  }
  /* The marks are sized as a percentage of the box. In a box this much larger
     the same percentage reads as oversized, so they step down to hold their
     original presence rather than their original share of the width. */
  .choice__mark[style*="mark-ladies"]{width:min(30%,150px);}
  .choice__mark[style*="mark-men"]   {width:min(34%,170px);}
  .choice__mark[style*="mark-single"]{width:min(33%,160px);}
  .choice__mark[style*="mark-group"] {width:min(38%,180px);}
}

/* ---------- phone hero: everything on the opening screen ----------
   Measured at 375x812: the hero ran 983px against an 812px viewport, so the
   Men box sat 171px below the fold and the page opened on a single choice.
   The budget is split rather than guessed --
     top padding   114 -> 76
     rating block  109 -> ~78   (stars up, caption smaller and tighter)
     two boxes     684 -> 548   (1:1 -> 5:4, still large, 268px each)
     bottom pad     48 -> 32
   which lands around 734 and leaves real air at the bottom. */
@media(max-width:700px){
  .hero{
    padding-top:76px;
    padding-bottom:32px;}

  /* The rating moves up and tightens. It is an endorsement line, not a
     headline, so it does not need a headline's clearance. */
  .rating{margin:0 0 1.15rem;}
  .stars{margin-bottom:.5rem;}
  .stars svg{width:30px;}
  .stars--video .star{width:30px;}
  .stars__label{font-size:.92rem;letter-spacing:.14em;}

  /* 5:4 rather than square. The boxes stay full-column width, so trimming the
     height is what buys the space -- narrowing them instead would leave odd
     margins and make the photographs smaller for no gain. */
  .choice{aspect-ratio:5 / 4;}
  .chooser{gap:.7rem;}
}

/* ============================================================
   PHONE NAVIGATION — burger, sliding panel, floating Book
   Below 900px .nav__links are hidden, which left the site with no navigation
   at all on a phone beyond the Book button. These three pieces replace it:
   a burger fixed top right, a panel that slides in from the right, and Book
   moved out of the header into a button that follows the scroll.
   All of it is phone-only; the desktop header is untouched.
   ============================================================ */
@media(max-width:900px){

  /* Book leaves the header — it lives at the bottom right now, and the corner
     it used to occupy is where the burger goes. */
  .nav > .btn--solid{display:none;}

  .navburger{
    position:fixed;z-index:210;
    top:.95rem;right:var(--gutter);
    width:44px;height:44px;                 /* a real touch target */
    display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:5px;padding:0;cursor:pointer;
    -webkit-appearance:none;appearance:none;
    background:rgba(11,10,9,.55);border:1px solid rgba(232,230,227,.16);
    backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);}
  .navburger span{
    display:block;width:19px;height:1.5px;background:var(--ivory);
    transition:transform var(--t-std) var(--ease),opacity var(--t-fast) var(--ease);}
  /* Three lines fold into a cross: the middle fades, the outer two rotate in
     from their own resting offsets, so it reads as one movement. */
  .navburger[aria-expanded="true"] span:nth-child(1){transform:translateY(6.5px) rotate(45deg);}
  .navburger[aria-expanded="true"] span:nth-child(2){opacity:0;}
  .navburger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg);}

  .navpanel__scrim{
    position:fixed;inset:0;z-index:205;
    background:rgba(6,6,5,.62);
    opacity:0;visibility:hidden;
    transition:opacity var(--t-std) var(--ease),visibility var(--t-std) var(--ease);}
  .navpanel.is-open + .navpanel__scrim,
  .navpanel__scrim.is-open{opacity:1;visibility:visible;}

  .navpanel{
    position:fixed;z-index:206;
    top:0;right:0;bottom:0;
    width:min(82vw,330px);
    padding:5.5rem var(--gutter) 2rem;
    background:#121110 url("images/hero/footer-wall.jpg?v=168") center / cover no-repeat;
    border-left:1px solid var(--line);
    transform:translateX(100%);
    transition:transform .38s var(--ease);
    overflow-y:auto;overscroll-behavior:contain;
    display:flex;flex-direction:column;}
  .navpanel.is-open{transform:none;}

  .navpanel a{
    display:flex;align-items:baseline;gap:.8rem;
    padding:.95rem 0;
    border-bottom:1px solid rgba(232,230,227,.09);
    font-family:Archivo,system-ui,sans-serif;font-weight:700;font-stretch:118%;
    letter-spacing:-.01em;text-transform:uppercase;
    font-size:1.05rem;color:var(--ivory);text-decoration:none;}
  .navpanel a .navpanel__n{
    font-family:"IBM Plex Mono",monospace;font-weight:400;
    font-size:.62rem;letter-spacing:.14em;color:var(--accent);}
  .navpanel a:hover,.navpanel a:focus-visible{color:var(--accent);}

  /* The last item is the action, so it stops being a list row and becomes a
     button — the same gold as every other primary control on the site. */
  .navpanel a.navpanel__cta{
    margin-top:1.4rem;border-bottom:0;justify-content:center;
    background:var(--accent);color:var(--noir);
    padding:.95rem 1rem;font-size:.82rem;letter-spacing:.12em;}
  .navpanel a.navpanel__cta .navpanel__n{color:rgba(11,10,9,.55);}

  /* Book, following the scroll. Sits clear of the panel so it never overlaps
     the sheet when that is open. */
  .fab-book{
    position:fixed;z-index:204;
    right:var(--gutter);bottom:1.1rem;
    display:inline-flex;align-items:center;gap:.5rem;
    padding:.85rem 1.25rem;
    background:var(--accent);color:var(--noir);text-decoration:none;
    font-family:Archivo,system-ui,sans-serif;font-weight:800;font-stretch:115%;
    font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;
    box-shadow:0 10px 26px rgba(0,0,0,.45);
    transition:transform var(--t-std) var(--ease),opacity var(--t-std) var(--ease);}
  .fab-book svg{width:13px;height:10px;fill:currentColor;}
  /* Out of the way while the panel is open — the panel carries its own Book. */
  body.navpanel-open .fab-book{transform:translateY(120%);opacity:0;}
}
@media(min-width:901px){
  .navburger,.navpanel,.navpanel__scrim,.fab-book{display:none;}
}

/* ============================================================
   CHOOSER MARKS — the artwork, with light moving across it
   First attempt masked these by their alpha and filled the shape with a
   gradient. That failed for a reason worth recording: the alpha is a SOLID
   shield silhouette and every bit of the figure is in the RGB, so masking by
   alpha produced a plain gold blob. The artwork has to stay.

   So the drawing is painted as-is and a band of light travels OVER it, clipped
   to the same alpha so the shine lands on the shield and nowhere else. WebP
   rather than PNG: 2107 KB -> 239 KB for the four, with alpha kept.
   ============================================================ */
.choice__mark{
  background-image:var(--mark);
  background-size:contain;background-position:center;background-repeat:no-repeat;
  /* Present, not a watermark. The old .22 was why it read as half-there. */
  opacity:.9;
  isolation:isolate;}

.choice__mark::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  /* Clipped to the mark's own silhouette, so the light cannot spill past the
     shield onto the photograph behind it. */
  -webkit-mask-image:var(--mark);        mask-image:var(--mark);
  -webkit-mask-size:contain;             mask-size:contain;
  -webkit-mask-repeat:no-repeat;         mask-repeat:no-repeat;
  -webkit-mask-position:center;          mask-position:center;
  background-image:linear-gradient(104deg,
    rgba(255,246,223,0)   38%,
    rgba(255,246,223,.16) 45%,
    rgba(255,246,223,.62) 50%,
    rgba(255,246,223,.16) 55%,
    rgba(255,246,223,0)   62%);
  background-size:260% 100%;background-repeat:no-repeat;
  background-position:170% 0;
  /* screen lifts the metal where the band crosses instead of washing a white
     film over it - the gold stays gold and simply catches the light. */
  mix-blend-mode:screen;
  animation:plaqueShine 4.6s var(--ease) .9s infinite;}

/* Hover shrinks the mark to a corner badge; it needs full opacity to survive. */
.choice:hover .choice__mark,.choice:focus-visible .choice__mark{opacity:1;}

/* The ladies' pages run jade. The artwork is gold, so it is rotated to the
   scope's own metal rather than shipping a second set of files: gold sits near
   43 degrees of hue and this scope's accent near 162, hence the rotation, with
   saturation pulled back because jade is the quieter colour of the two. */
[data-scope="jade"] .choice__mark{
  filter:hue-rotate(117deg) saturate(.62) brightness(1.04);}

/* The label sits over a brighter mark now and must still read first. */
.choice__title{text-shadow:0 2px 14px rgba(0,0,0,.75),0 0 3px rgba(0,0,0,.6);}

@media(prefers-reduced-motion:reduce){
  .choice__mark::after{animation:none;background-position:-70% 0;}
}

/* ============================================================
   CHOOSER — brighter on hover, a flash on the one you pick
   Two separate things. Hovering lifts the photograph out of the gloom it was
   sitting in. Choosing sets off a short bloom on that box alone, so the page
   acknowledges the tap before it navigates — which matters most on a phone,
   where there is no hover to say "this one" and the wait for the next page
   would otherwise be unexplained.
   ============================================================ */

/* Hover: the picture was settling at .66 brightness, barely above its resting
   .6, so arriving read as a slide rather than a reveal. */
.choice:hover .choice__media,
.choice:focus-visible .choice__media{
  filter:grayscale(0) brightness(.92);}
.choice:hover::after,.choice:focus-visible::after{
  background:linear-gradient(0deg,rgba(11,10,9,.62),rgba(11,10,9,.20));}

/* Chosen: a bloom that peaks and settles rather than a step change - a single
   filter jump reads as a glitch, a curve reads as a flash. */
@keyframes choiceFlash{
  0%   {filter:grayscale(0) brightness(.92);}
  34%  {filter:grayscale(0) brightness(1.85) contrast(1.04);}
  100% {filter:grayscale(0) brightness(1.28);}
}
.choice.is-chosen .choice__media{
  opacity:1;transform:translateX(0) scale(1.04);
  animation:choiceFlash .46s var(--ease) forwards;}
/* The scrim exists to keep the label legible over the photo; during the flash
   the photo IS the point, so it lifts almost entirely. */
.choice.is-chosen::after{
  background:linear-gradient(0deg,rgba(11,10,9,.30),rgba(11,10,9,.05));}
.choice.is-chosen{border-color:var(--accent);}
/* The mark and label ride the bloom rather than sitting flat against it. */
.choice.is-chosen .choice__mark{opacity:1;}
.choice.is-chosen .choice__title{transform:scale(1.03);
  transition:transform .46s var(--ease);}

@media(prefers-reduced-motion:reduce){
  .choice.is-chosen .choice__media{animation:none;filter:grayscale(0) brightness(1.1);}
  .choice.is-chosen .choice__title{transform:none;}
}

/* ============================================================
   BOOKING DIALOG — the whole person, and copy that sits on something
   The photo was background-size:cover in a 296x343 box. Both assessment shots
   are portrait at 0.79 against a 0.86 box, so cover was cropping the coach's
   head off the top for an 8% difference in proportion. contain shows all of
   them and costs two thin bands, which the panel colour absorbs.
   ============================================================ */
.modal__media{
  background-size:contain;
  background-repeat:no-repeat;
  background-position:center;
  background-color:#0E0D0C;}
@media(max-width:659px){
  /* Stacked, the media is a full-width band. A portrait photo contained in a
     180px strip is a stamp, so the band grows to give the figure room. */
  .modal__media{height:clamp(210px,36vh,320px);}
}

/* The copy now reads as a panel of its own rather than text floating on the
   same flat black as the picture beside it. */
.modal__body{
  background:linear-gradient(180deg,rgba(26,24,22,.92),rgba(14,13,12,.96));}
.modal__title,.modal__lede{text-shadow:0 1px 10px rgba(0,0,0,.6);}

/* ---------- gold that moves across the primary actions ----------
   The same travelling sweep the membership figures use, on the buttons that
   matter. Applied to the label surface itself, so the gold runs THROUGH the
   type rather than a highlight sliding over the top of it. */
.btn--solid,.fab-book,.navpanel__cta{
  position:relative;overflow:hidden;isolation:isolate;}
.btn--solid::after,.fab-book::after,.navpanel__cta::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background-image:linear-gradient(104deg,
    rgba(255,255,255,0)    40%,
    rgba(255,255,255,.14)  46%,
    rgba(255,255,255,.55)  50%,
    rgba(255,255,255,.14)  54%,
    rgba(255,255,255,0)    60%);
  background-size:260% 100%;background-repeat:no-repeat;
  background-position:170% 0;
  mix-blend-mode:overlay;
  animation:plaqueShine 4.6s var(--ease) 1.2s infinite;}

/* ---------- the choose flash, dialled back ----------
   1.85 blew the photograph out and took its detail with it. The point was
   acknowledgement, not glare: this lifts the picture clearly and stops there. */
@keyframes choiceFlash{
  0%   {filter:grayscale(0) brightness(.92);}
  36%  {filter:grayscale(0) brightness(1.16);}
  100% {filter:grayscale(0) brightness(1.06);}
}

/* ---------- first tap reveals, second tap goes ----------
   On a touch screen there is no hover, so the photograph and the mark were
   fighting for the same moment. The first tap clears the furniture - mark and
   scrim - and hands the box to the picture. The second tap navigates. */
.choice.is-peek .choice__media{
  opacity:1;transform:translateX(0) scale(1);
  filter:grayscale(0) brightness(1);}
.choice.is-peek::after{
  background:linear-gradient(0deg,rgba(11,10,9,.42),rgba(11,10,9,.10));}
.choice.is-peek .choice__mark{opacity:0;transform:translate(-50%,-56%) scale(.9);}
.choice.is-peek .choice__title{opacity:0;transform:translateY(6px);}
.choice__title{transition:opacity var(--t-std) var(--ease),transform var(--t-std) var(--ease);}

@media(prefers-reduced-motion:reduce){
  .btn--solid::after,.fab-book::after,.navpanel__cta::after{
    animation:none;background-position:-70% 0;}
}

/* ============================================================
   BOOKING DIALOG ON PHONES — the photograph IS the panel
   Stacked, the picture was a 320px band with the copy in black below it, so
   the coach arrived as a cropped torso. Here the media and the body share one
   grid cell: the photo takes the full height of the dialog (portrait 0.794 in
   a ~0.54 panel, so `cover` crops the SIDES and keeps the figure head to toe)
   and the copy sits on top of it. The body's gradient stays clear over the
   figure and goes solid from the price rule down, so the money and the button
   keep the flat black they have always had.
   ============================================================ */
/* Grouping wrapper. display:contents everywhere except phones, so the body's
   flex layout and gap are exactly what they were before. */
.modal__intro{display:contents;}

@media(max-width:659px){
  #bookModal .modal__panel{
    grid-template-rows:minmax(0,1fr);
    min-height:min(620px,calc(100dvh - 2rem));}
  #bookModal .modal__media{
    grid-area:1/1;height:auto;align-self:stretch;
    background-size:cover;background-position:center 18%;}
  #bookModal .modal__body{
    grid-area:1/1;position:relative;z-index:1;
    background:linear-gradient(180deg,
      rgba(11,10,9,0)    0%,
      rgba(11,10,9,.10) 26%,
      rgba(11,10,9,.46) 44%,
      rgba(11,10,9,.82) 58%,
      rgba(11,10,9,.95) 70%,
      rgba(11,10,9,.99) 100%);}
  /* margin-top:auto rather than justify-content:flex-end — the body scrolls,
     and flex-end clips the top of overflowing content where auto margins
     simply collapse. */
  #bookModal .modal__intro{
    display:flex;flex-direction:column;gap:.5rem;
    margin-top:auto;
    padding:clamp(.8rem,3.2vw,1.1rem) clamp(.85rem,3.4vw,1.15rem);
    background:rgba(11,10,9,.58);
    -webkit-backdrop-filter:blur(8px) saturate(1.05);
    backdrop-filter:blur(8px) saturate(1.05);
    border:1px solid rgba(232,230,227,.10);
    /* the one coloured edge; --accent is jade on the ladies' pages */
    border-left:2px solid var(--accent);}
}
