/* =========================================================
   FushiFit — Ty | One-on-One Coaching
   Palette: near-black canvas, graphite surfaces, cream type,
            neon green accent used sparingly.

   Forked from the Andrew Perez build. The structure is the same;
   the accent moved from a dark maroon to a bright neon green,
   which flips one rule: green is far too light to carry cream
   text on top of it, so every accent-coloured FILL takes
   --accent-ink (near-black) instead of --text. Grep for
   --accent-ink before adding a new filled element.
   ========================================================= */

:root{
  /* --- canvas --- */
  --bg:         #0b0b0c;   /* page */
  --bg-alt:     #121214;   /* alternating sections */
  --surface:    #17171a;   /* cards */
  --surface-2:  #1e1e22;   /* raised cards / inputs */
  --line:       rgba(245,240,232,.10);
  --line-2:     rgba(245,240,232,.18);

  /* --- type --- */
  --text:       #f5f0e8;   /* cream white — headings + body */
  --muted:      #a8a29a;   /* body copy, gray */
  --muted-2:    #78726a;   /* meta, labels */

  /* Green, sampled from Ty's own footage rather than guessed. Sampling the
     green-ish pixels across the gym scenes on his YouTube channel put the
     dominant hue at 132deg. The first two attempts here were at ~105deg,
     which is why they read as lime: his grade is a cooler forest green, and
     the gym itself is grey steel wearing that grade.

     Kept dark on purpose. It's still bright enough to need dark text on top
     of it, cream on this green is 2.7:1, which is why --accent-ink exists.

     Every translucent accent in this file goes through the two -rgb tokens,
     so a retheme is this block and nothing else. Keep each one in sync with
     its hex twin below. */
  --accent-rgb:    63,162,82;
  --accent-hi-rgb: 90,191,110;

  --accent:        #3fa252;  /* headings, rules, icons   (6.1:1 on bg) */
  --accent-hi:     #5abf6e;  /* hover, small labels      (8.3:1 on bg) */
  --accent-btn:    #3fa252;  /* button fill              (5.9:1 w/ ink) */
  --accent-btn-hi: #48b25d;
  --accent-ink:    #07160a;  /* type + icons sitting ON an accent fill */
  --accent-deep:   #1c4a25;
  --accent-dim:    rgba(var(--accent-rgb),.10);
  --accent-line:   rgba(var(--accent-rgb),.30);

  /* Shine stops. The band that travels through the accent gradients.
     Both stops are lighter than --accent, never darker, so the contrast
     floor on small accent text holds through the whole animation. */
  --accent-mid:    #9bd4a7;
  --accent-peak:   #e6f5ea;

  /* Validation red. The accent can't do this job on this build: a form
     error rendered in bright green reads as a tick, not a problem. */
  --warn:          #ff6b6b;  /* form errors             (7.1:1 on bg) */

  /* --- fonts --- */
  --display: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --sans:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  --nav-h: 79px;

  --wrap: 1180px;
  --r:    12px;

  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.35);
  --ease: cubic-bezier(.22,.61,.36,1);
}

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

html{
  scroll-behavior:smooth;
  scroll-padding-top:96px;
  -webkit-text-size-adjust:100%;
  background:var(--bg);
}

body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:var(--sans);
  font-size:17px;
  line-height:1.7;
  font-weight:350;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}

img{ max-width:100%; height:auto; display:block; }

h1,h2,h3,h4{
  font-family:var(--display);
  font-weight:700;
  line-height:1.05;
  letter-spacing:-.02em;
  margin:0;
  color:var(--text);
  font-variation-settings:"wdth" 112;
}

p{ margin:0 0 1.15em; }
p:last-child{ margin-bottom:0; }

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

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

.wrap{ width:100%; max-width:var(--wrap); margin:0 auto; padding:0 28px; }

.accent{ color:var(--accent); }

.skip-link{
  position:absolute; left:-9999px; top:0; z-index:200;
  background:var(--accent-btn); color:var(--accent-ink); padding:12px 20px; font-weight:600;
  border-radius:0 0 8px 0;
}
.skip-link:focus{ left:0; }

/* =============== SHARED BITS =============== */

.eyebrow{
  font-family:var(--sans);
  font-size:12px;
  font-weight:600;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--accent);
  margin:0 0 18px;
  display:flex;
  align-items:center;
  gap:12px;
}
.eyebrow::before{
  content:"";
  width:28px; height:1px;
  background:var(--accent-line);
  flex:none;
}
.eyebrow--center{ justify-content:center; }
.eyebrow--center::after{
  content:"";
  width:28px; height:1px;
  background:var(--accent-line);
  flex:none;
}

.btn{
  display:inline-flex;
  align-items:center;
  gap:10px;
  font-family:var(--sans);
  font-size:15px;
  font-weight:600;
  letter-spacing:.01em;
  padding:15px 28px;
  border-radius:8px;
  border:1px solid transparent;
  cursor:pointer;
  transition:background .25s var(--ease), border-color .25s var(--ease),
             transform .25s var(--ease), color .25s var(--ease);
  text-align:center;
  line-height:1.2;
}
.btn:focus-visible{ outline:2px solid var(--accent-hi); outline-offset:3px; }

.btn--primary{
  background:var(--accent-btn);
  color:var(--accent-ink);
}
.btn--primary:hover{ background:var(--accent-btn-hi); transform:translateY(-1px); }

.btn--ghost{
  background:transparent;
  color:var(--text);
  border-color:var(--line-2);
}
.btn--ghost:hover{ border-color:var(--accent); color:var(--accent-hi); }

.btn--lg{ padding:18px 34px; font-size:16px; }
.btn--block{ width:100%; justify-content:center; }
.btn[disabled]{ opacity:.4; cursor:not-allowed; transform:none; }

.section{ padding:clamp(72px,10vw,128px) 0; }
.section--alt{ background:var(--bg-alt); }

.section__head{ max-width:760px; margin:0 0 56px; }
.section__head--center{ margin-left:auto; margin-right:auto; text-align:center; }
.section__title{ font-size:clamp(32px,4.6vw,52px); text-transform:uppercase; }
.section__lede{
  color:var(--muted);
  font-size:clamp(17px,1.7vw,19px);
  margin-top:20px;
  max-width:62ch;
}
.section__head--center .section__lede{ margin-left:auto; margin-right:auto; }

/* reveal-on-scroll */
.reveal{ opacity:0; transform:translateY(22px); transition:opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.is-in{ opacity:1; transform:none; }
@media (prefers-reduced-motion:reduce){
  .reveal{ opacity:1; transform:none; transition:none; }
  html{ scroll-behavior:auto; }
}

/* =============== INTRO =============== */
/* Self-terminating: the CSS animation hides the overlay on its own at 3.15s,
   so a blocked or broken script can never leave a visitor staring at it. */

.intro{
  position:fixed; inset:0; z-index:999;
  display:grid; place-items:center;
  padding:24px;
  overflow:hidden;
  background:
    radial-gradient(70% 55% at 50% 46%, rgba(var(--accent-rgb),.13), transparent 62%),
    var(--bg);
  animation:introAuto 3.15s linear forwards;
}
.intro.gone{ display:none; }
@keyframes introAuto{
  0%,80%{ opacity:1; }
  100%{ opacity:0; visibility:hidden; pointer-events:none; }
}

.intro__inner{ text-align:center; }

.intro__name{
  font-family:var(--display);
  font-weight:800;
  text-transform:uppercase;
  letter-spacing:-.025em;
  line-height:1;
  font-size:clamp(36px,8.6vw,104px);
  white-space:nowrap;
  font-variation-settings:"wdth" 108;
}
.intro__l{
  display:inline-block;
  opacity:0;
  will-change:transform,opacity;
  transform:translateX(var(--dx));
  animation:slideAcross .85s cubic-bezier(.16,.84,.34,1) var(--d) forwards;
}
.intro__sp{ display:inline-block; width:.3em; }
.intro__l--b{ color:var(--accent); }
@keyframes slideAcross{ to{ opacity:1; transform:translateX(0); } }

.intro__rule{
  display:block;
  height:3px;
  margin:22px auto 0;
  border-radius:2px;
  background:var(--accent);
  transform:scaleX(0);
  animation:drawRule .65s cubic-bezier(.16,.84,.34,1) 1s forwards;
}
@keyframes drawRule{ to{ transform:scaleX(1); } }

.intro__role{
  margin:18px 0 0;
  font-family:var(--sans);
  font-size:clamp(10px,1.3vw,13px);
  font-weight:600;
  letter-spacing:.34em;
  text-transform:uppercase;
  color:var(--muted);
  opacity:0;
  animation:riseIn .7s var(--ease) 1.35s forwards;
}
@keyframes riseIn{
  from{ opacity:0; transform:translateY(10px); }
  to{ opacity:1; transform:none; }
}

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

/* =============== NAV =============== */

.nav{
  position:fixed; inset:0 0 auto 0; z-index:100;
  background:transparent;
  transition:background .3s var(--ease), border-color .3s var(--ease), backdrop-filter .3s var(--ease);
  border-bottom:1px solid transparent;
}
.nav.is-stuck{
  background:rgba(11,11,12,.88);
  backdrop-filter:saturate(140%) blur(14px);
  -webkit-backdrop-filter:saturate(140%) blur(14px);
  border-bottom-color:var(--line);
}
.nav__inner{
  display:flex; align-items:center; justify-content:space-between;
  gap:24px; height:var(--nav-h);
}
.brand{
  font-family:var(--display);
  font-weight:700;
  font-size:17.5px;
  letter-spacing:.16em;
  text-transform:uppercase;
  font-variation-settings:"wdth" 100;
  display:flex; align-items:baseline; gap:8px;
}
.brand em{ font-style:normal; color:var(--accent); }

.nav__links{ display:flex; align-items:center; gap:34px; }
.nav__links a{
  font-size:14px; font-weight:500; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted);
  transition:color .2s var(--ease);
}
.nav__links a:hover{ color:var(--text); }
.nav .btn{ padding:12px 22px; font-size:14px; letter-spacing:.06em; }
/* `.nav__links a` is (0,1,1) and beats `.btn--primary` (0,1,0), so the nav's
   muted link colour was winning and painting the primary CTA's label gray on
   its own fill. That measured 1.8:1 against the accent. Re-assert the ink at
   matching specificity. */
.nav__links a.btn--primary{ color:var(--accent-ink); }

.nav__toggle{
  display:none; background:none; border:0; color:var(--text);
  padding:8px; cursor:pointer;
}

@media (max-width:900px){
  .nav__links{
    position:fixed; inset:72px 0 auto 0;
    flex-direction:column; align-items:stretch; gap:0;
    background:rgba(11,11,12,.98);
    backdrop-filter:blur(14px);
    border-bottom:1px solid var(--line);
    padding:12px 28px 26px;
    transform:translateY(-12px);
    opacity:0; pointer-events:none;
    transition:opacity .25s var(--ease), transform .25s var(--ease);
  }
  .nav__links.is-open{ opacity:1; transform:none; pointer-events:auto; }
  .nav__links a{ padding:15px 0; border-bottom:1px solid var(--line); font-size:14px; }
  .nav__links .btn{ margin-top:18px; justify-content:center; }
  .nav__toggle{ display:block; }
}

/* =============== SECTION RAIL ===============
   A spine running the full height of the viewport with a dot per section. The
   fill tracks scroll position and the active dot branches out to name the
   section.

   Shown at every width, including phones. What changes below 1440px is the
   label: above that there is gutter to park it in, so it simply stays visible
   for the active section. Below it there is no gutter at all, the copy starts
   28px from the edge, so a permanent label would sit on top of the text.
   There it flashes for a moment when the section changes and then fades back
   out, leaving just the dots. .is-flash is driven from main.js.

   Dots are spread with space-between across the padded height rather than
   sitting in a fixed-gap cluster, so the rail reads as a scale for the whole
   page. --rail-top clears the fixed nav; the track is inset by both paddings
   plus half a dot so the line starts and ends on a dot centre, not in space. */

.rail{
  --rail-top: calc(var(--nav-h) + 18px);
  --rail-bottom: 34px;
  --dot: 11px;

  position:fixed;
  left:clamp(10px, 1.1vw, 14px);
  top:0;
  bottom:0;
  z-index:90;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  padding:var(--rail-top) 0 var(--rail-bottom);
  pointer-events:none;
}

.rail__track{
  position:absolute;
  left:calc(var(--dot) / 2);
  top:calc(var(--rail-top) + var(--dot) / 2);
  bottom:calc(var(--rail-bottom) + var(--dot) / 2);
  width:1px;
  background:var(--line-2);
}
.rail__fill{
  position:absolute;
  left:0; top:0;
  width:1px;
  height:0;
  background:var(--accent);
  box-shadow:0 0 8px rgba(var(--accent-rgb),.5);
}

.rail__item{
  position:relative;
  display:flex;
  align-items:center;
  height:var(--dot);
  cursor:pointer;
  pointer-events:auto;
  width:max-content;
}
.rail__dot{
  flex:none;
  width:var(--dot); height:var(--dot);
  border-radius:50%;
  border:1px solid var(--line-2);
  background:var(--bg);
  position:relative;
  z-index:1;
  transition:border-color .3s var(--ease), background .3s var(--ease),
             box-shadow .3s var(--ease), transform .3s var(--ease);
}

.rail__label{
  font-family:var(--sans);
  font-size:10px;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--muted-2);
  white-space:nowrap;
  opacity:0;
  transform:translateX(-4px);
  /* Lifts the label off whatever it lands on. Below 1440 it can cross the
     copy, and the page is dark everywhere, so a dark halo is enough. */
  text-shadow:0 0 6px rgba(11,11,12,.95), 0 0 14px rgba(11,11,12,.85);
  transition:opacity .32s var(--ease), transform .32s var(--ease), color .32s var(--ease);
}
/* The branch. Grows out of the dot before the text rather than the label just
   fading in beside it, so the dot reads as the thing doing the pointing. */
.rail__label::before{
  content:"";
  display:inline-block;
  vertical-align:middle;
  width:0;
  height:1px;
  margin-right:0;
  background:var(--accent);
  transition:width .32s var(--ease), margin-right .32s var(--ease);
}

.rail__item:hover .rail__dot{ border-color:var(--accent); transform:scale(1.15); }
.rail__item:hover .rail__label{ opacity:1; transform:none; color:var(--muted); }
.rail__item:hover .rail__label::before{ width:12px; margin-right:8px; }

.rail__item.is-on .rail__dot{
  border-color:var(--accent);
  background:var(--accent);
  box-shadow:0 0 0 4px rgba(var(--accent-rgb),.14), 0 0 12px rgba(var(--accent-rgb),.5);
}
.rail__item.is-on .rail__label{ opacity:1; transform:none; color:var(--text); }
.rail__item.is-on .rail__label::before{ width:14px; margin-right:9px; }

.rail__item:focus-visible{ outline:2px solid var(--accent-hi); outline-offset:6px; border-radius:2px; }

/* No gutter to live in: the active label is a flash, not a fixture. */
@media (max-width:1439px){
  .rail__item.is-on .rail__label{ opacity:0; transform:translateX(-4px); }
  .rail.is-flash .rail__item.is-on .rail__label{ opacity:1; transform:none; }
  .rail__item:hover .rail__label{ opacity:1; transform:none; }
}

@media (max-width:720px){
  .rail{ --dot:9px; --rail-bottom:26px; }
  .rail__label{ font-size:9.5px; letter-spacing:.1em; }
  .rail__item.is-on .rail__label::before{ width:11px; margin-right:7px; }
}

@media (prefers-reduced-motion:reduce){
  .rail__dot,
  .rail__label,
  .rail__label::before{ transition:none; }
}

/* =============== HERO ===============
   Copy left, Ty's shot bled off the right edge. The photo is NOT in a frame:
   it's absolutely positioned, masked to nothing on its left side, and faded
   top and bottom, so it dissolves into the page and the headline can run over
   the top of it. Three things keep the type legible on it, and all three are
   load bearing:

     1. the mask, which kills the image well before the copy column ends
     2. .hero__scrim, a left-to-right darkening across the whole section
     3. .hero__copy::before, a pool of darkness under the text itself

   The source photo has bright smoke on its left third. Drop that mask and
   cream type lands on it at about 2:1. */

.hero{
  position:relative;
  /* Copy sits at the BOTTOM of the hero, not centred against the video. The
     two used to sit side by side like columns; now they're layered, with the
     clip forward and full height and the words tucked low and behind it. */
  min-height:min(92vh, 940px);
  display:flex;
  align-items:flex-end;
  padding:calc(var(--nav-h) + 24px) 0 clamp(52px,7vh,96px);
  overflow:hidden;
  isolation:isolate;
}

.hero__media{
  position:absolute; inset:0; z-index:0;
  background:
    radial-gradient(110% 88% at 76% 26%, rgba(var(--accent-rgb),.10), transparent 58%),
    linear-gradient(180deg, #141416 0%, #0b0b0c 74%);
}

/* --- the shot --- */
.hero__figure{
  position:absolute;
  top:0; right:0; bottom:0;
  width:min(66%, 960px);
  margin:0;
  /* ABOVE .hero .wrap (z-index 3), so the clip is genuinely in front and the
     headline runs behind Ty rather than beside him. pointer-events:none keeps
     the buttons underneath clickable. Because it's above the scrim too, the
     footage keeps its own contrast instead of being darkened. */
  z-index:4;
  pointer-events:none;
  /* Poster as a background rather than the video's poster attribute, so it
     still shows if the video is held as a still or never gets to play. */
  background:url("/assets/video/hero-poster.jpg?v=6") 16% 26% / cover no-repeat;

  /* The mask belongs HERE, not on the video. The figure paints the poster as
     its own background, so masking only the video left that poster showing as
     a hard-edged rectangle straight down the middle of the headline. Masking
     the figure fades the poster, the video and the ::after gradient together.

     Now that the clip sits over the copy these stops control occlusion, not
     just contrast: held at nothing until past where the text ends, then a long
     ramp so the words slide behind Ty instead of meeting an edge. Copy width
     and these stops are a pair. */
  -webkit-mask-image:linear-gradient(100deg, transparent 4%, rgba(0,0,0,.13) 14%, rgba(0,0,0,.32) 30%, #000 55%);
          mask-image:linear-gradient(100deg, transparent 4%, rgba(0,0,0,.13) 14%, rgba(0,0,0,.32) 30%, #000 55%);
}
.hero__figure video{
  width:100%; height:100%;
  object-fit:cover;
  object-position:16% 26%;
  display:block;
  opacity:1;
  filter:contrast(1.03) saturate(.96);

  /* Ramps to full much sooner than the photo version did. The photo was a
     dark silhouette that could sit at 15% opacity and still read; Ty is lit
     here and the whole point is seeing him, so the fade has to be done with
     its work by the time it reaches him. It still has to be at nothing where
     the copy is: .hero__copy ends at 25% of this element's width, so the
     first stop stays left of that and the ramp happens between them.

     Measured across every frame of the loop, not one still. The brightest
     frame behind the hero sub composites to 5.6:1 against the muted body
     colour. Re-measure if the clip is replaced, and remember a still frame
     will tell you the wrong answer. */
}
/* Top and bottom fade. Kept off the mask so the two gradients don't have to
   be composited together, which is where the WebKit prefixes get fragile. */
.hero__figure::after{
  content:"";
  position:absolute; inset:0;
  background:linear-gradient(180deg,
    rgba(11,11,12,.78) 0%,
    rgba(11,11,12,.16) 8%,
    transparent 20%,
    transparent 74%,
    rgba(11,11,12,.45) 90%,
    var(--bg) 100%);
}

/* Steeper falloff than before. It still has to sit at nearly full strength
   over the copy column, but it now clears completely by 78% rather than
   trailing all the way to the right edge, so the part of the photo nobody
   reads over is left alone. */
/* --- drifting smoke ---
   The photo already has smoke on its left, so this extends it rather than
   inventing it. Three fractal-noise layers, screened so they only ever add
   light, drifting at different speeds and in different directions. The
   parallax between the layers is what sells it as volume rather than one
   texture sliding around.

   Two things had to be dialled in together. The first pass used fine-grained
   noise moving a few percent, and at that scale the drift was invisible: the
   grain is smaller than the movement, so it reads as static. Big soft blobs
   moving further is what makes it legible as smoke. baseFrequency and the
   keyframe amplitudes are a pair; shrink the blobs and you have to travel
   further to get the same read.

   Cheap by construction: feTurbulence is rasterised once per layer as a
   background image, and the only animated property is transform, which stays
   on the compositor. Do not animate baseFrequency, which is the obvious way
   to do this and repaints the filter every frame.

   Legibility is structural, not tuned. .hero__smoke lives inside
   .hero__figure, so it inherits that element's bounds and gets its own left
   feather on top; and .hero__scrim (z-index 2) paints over the whole thing,
   so the copy column sits under near-opaque black no matter what the smoke
   is doing underneath it. */

/* OFF while the hero is the gym clip. The smoke was built to extend the smoke
   in the old still photo; over real footage that already has its own motion it
   just reads as a dirty lens. Kept rather than deleted because it's tuned and
   the markup is one line: re-add <div class="hero__smoke"><i></i><i></i><i></i></div>
   inside .hero__figure to bring it back. */
.hero__smoke{
  position:absolute; inset:0;
  overflow:hidden;
  pointer-events:none;
  /* Held fully transparent past where the copy ends, not merely feathered.
     `screen` only ever ADDS light, so unlike the photo underneath it this
     layer can only hurt legibility, and no amount of scrim tuning makes that
     safe to eyeball. .hero__copy ends at 25% of this element's width at the
     widest layout; the first stop sits at 30%, so the smoke contributes
     exactly nothing behind the text by construction. Everything from there
     right is the subject and the existing smoke in the photo, which is where
     it was wanted anyway. Do not pull that first stop left. */
  -webkit-mask-image:linear-gradient(100deg, transparent 30%, rgba(0,0,0,.45) 55%, #000 84%);
          mask-image:linear-gradient(100deg, transparent 30%, rgba(0,0,0,.45) 55%, #000 84%);
}
.hero__smoke i{
  position:absolute;
  top:-55%; left:-55%; width:210%; height:210%;
  background-repeat:repeat;
  mix-blend-mode:screen;
  will-change:transform;
}
/* background-size in px, NOT a percentage. A percentage resolves against the
   layer, which is 210% of the figure, so `100% 100%` stretched an 800px
   texture across 2200px and made every blob larger than the visible area.
   The drift was running correctly and looked like nothing was happening.
   Fixed px keeps the blobs at a readable size and the three sizes below give
   the parallax. */
.hero__smoke i:nth-child(1){ background-size:700px 700px; }
.hero__smoke i:nth-child(2){ background-size:1040px 1040px; }
.hero__smoke i:nth-child(3){ background-size:520px 520px; }
.hero__smoke i:nth-child(1){
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27800%27%20height%3D%27800%27%3E%3Cfilter%20id%3D%27s%27%20x%3D%270%27%20y%3D%270%27%20width%3D%27100%25%27%20height%3D%27100%25%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.0035%200.0055%27%20numOctaves%3D%274%27%20seed%3D%277%27%20stitchTiles%3D%27stitch%27%2F%3E%3CfeColorMatrix%20type%3D%27saturate%27%20values%3D%270%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27800%27%20height%3D%27800%27%20filter%3D%27url%28%23s%29%27%2F%3E%3C%2Fsvg%3E");
  opacity:.38;
  filter:blur(10px);
  animation:smokeA 38s ease-in-out infinite alternate;
}
.hero__smoke i:nth-child(2){
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27800%27%20height%3D%27800%27%3E%3Cfilter%20id%3D%27s%27%20x%3D%270%27%20y%3D%270%27%20width%3D%27100%25%27%20height%3D%27100%25%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.0022%200.0034%27%20numOctaves%3D%273%27%20seed%3D%2723%27%20stitchTiles%3D%27stitch%27%2F%3E%3CfeColorMatrix%20type%3D%27saturate%27%20values%3D%270%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27800%27%20height%3D%27800%27%20filter%3D%27url%28%23s%29%27%2F%3E%3C%2Fsvg%3E");
  opacity:.26;
  filter:blur(20px);
  animation:smokeB 53s ease-in-out infinite alternate;
}
.hero__smoke i:nth-child(3){
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27800%27%20height%3D%27800%27%3E%3Cfilter%20id%3D%27s%27%20x%3D%270%27%20y%3D%270%27%20width%3D%27100%25%27%20height%3D%27100%25%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.0060%200.0085%27%20numOctaves%3D%274%27%20seed%3D%2741%27%20stitchTiles%3D%27stitch%27%2F%3E%3CfeColorMatrix%20type%3D%27saturate%27%20values%3D%270%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27800%27%20height%3D%27800%27%20filter%3D%27url%28%23s%29%27%2F%3E%3C%2Fsvg%3E");
  opacity:.16;
  filter:blur(13px);
  animation:smokeC 71s ease-in-out infinite alternate;
}

/* `alternate` rather than a seamless loop: the layers ease to a stop at each
   extreme and drift back, which reads as air moving. A linear loop needs the
   texture to tile perfectly in both axes and still snaps at the boundary. */
@keyframes smokeA{
  from{ transform:translate3d(-12%, 7%, 0) scale(1.05) rotate(-3deg); }
  to  { transform:translate3d(14%, -11%, 0) scale(1.32) rotate(5deg); }
}
@keyframes smokeB{
  from{ transform:translate3d(13%, -6%, 0) scale(1.28) rotate(4deg); }
  to  { transform:translate3d(-11%, 12%, 0) scale(1.02) rotate(-5deg); }
}
@keyframes smokeC{
  from{ transform:translate3d(-8%, -9%, 0) scale(1.3) rotate(2deg); }
  to  { transform:translate3d(10%, 10%, 0) scale(1.08) rotate(-4deg); }
}

@media (prefers-reduced-motion:reduce){
  /* Held as a still. The texture is doing half the work even frozen, so
     there's no reason to remove it, only to stop it moving. */
  .hero__smoke i{ animation:none; }
}
.hero__scrim{
  position:absolute; inset:0; z-index:2;
  background:
    linear-gradient(90deg, rgba(11,11,12,.96) 0%, rgba(11,11,12,.88) 38%, rgba(11,11,12,.3) 60%, transparent 78%),
    linear-gradient(180deg, rgba(11,11,12,.45) 0%, transparent 28%, rgba(11,11,12,.6) 100%);
  pointer-events:none;
}
.hero .wrap{ position:relative; z-index:3; }

.hero .wrap{ width:100%; }
.hero__grid{ display:block; }
.hero__copy{
  position:relative;
  /* Narrower than it was with the still photo. That photo was a dark
     silhouette and the copy could sit right across it; Ty is lit and moving
     here, and the copy and the subject were fighting for the same horizontal
     space. Pulling the column in is what lets the mask below finish its fade
     before it reaches him. Copy width and mask stops are a pair. */
  max-width:min(58%, 660px);
}
/* Pool of darkness under the copy. The mask and the scrim between them get
   the background most of the way there, but the headline runs furthest right
   and this is what guarantees it lands on near-black. */
.hero__copy::before{
  content:"";
  position:absolute; z-index:-1;
  left:-40px; right:-90px; top:-56px; bottom:-40px;
  background:radial-gradient(74% 78% at 30% 50%,
    rgba(11,11,12,.92) 0%,
    rgba(11,11,12,.74) 48%,
    rgba(11,11,12,.42) 72%,
    transparent 90%);
  pointer-events:none;
}

.hero__title{
  font-size:clamp(34px,4.2vw,54px);
  text-transform:uppercase;
  letter-spacing:-.025em;
  font-variation-settings:"wdth" 108;
}
.hero__title span{ display:block; color:var(--accent); }
/* Without this the accent clause breaks as "BUILT AROUND YOUR / WEEK." and
   drops one word onto its own line. Balance splits it evenly instead. The
   span is display:block, so it needs the property in its own right; setting
   it on the h1 alone does nothing for it. */
.hero__title,
.hero__title span{ text-wrap:balance; }

.hero__sub{
  color:var(--muted);
  font-size:clamp(17px,1.9vw,20px);
  /* Deliberately shorter than .hero__copy. The headline is meant to run into
     the clip's fading edge, but a veil over 17px body text costs more than it
     does over 54px display type, so this stays clear of it. */
  max-width:34ch;
  margin:26px 0 0;
  line-height:1.62;
}
/* Held well inside the copy column. These are flex rows, so without a cap
   they stretch to the full measure and run under the opaque part of the clip:
   measured at a 41% veil on the ghost button's edge and 35% on the meta row.
   The headline is the only element meant to pass behind Ty. Anything
   interactive, or set small, stays in the clear. */
.hero__actions{ display:flex; flex-wrap:wrap; gap:14px; margin-top:36px; width:fit-content; max-width:100%; }

.hero__meta{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px 22px;
  margin-top:40px;
  max-width:400px;
  font-size:12px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2); font-weight:500;
}
.hero__meta span{ display:flex; align-items:center; gap:9px; }
.hero__meta span::before{
  content:""; width:5px; height:5px; border-radius:50%;
  background:var(--accent); flex:none;
}

/* Narrow: the photo goes full width behind the top of the section and fades
   down into the copy, rather than trying to hold a column of its own. The
   copy sits on the faded half. */
@media (max-width:900px){
  .hero{ padding-top:calc(var(--nav-h) + clamp(150px,42vw,260px)); }
  .hero__figure{
    width:100%;
    bottom:auto;
    height:clamp(300px,64vw,440px);
  }
  .hero__figure video{ object-position:center 22%; }
  .hero__figure{
    -webkit-mask-image:linear-gradient(180deg, #000 46%, rgba(0,0,0,.42) 74%, transparent 97%);
            mask-image:linear-gradient(180deg, #000 46%, rgba(0,0,0,.42) 74%, transparent 97%);
  }
  .hero__figure::after{
    background:linear-gradient(180deg,
      rgba(11,11,12,.5) 0%,
      rgba(11,11,12,.1) 22%,
      rgba(11,11,12,.42) 70%,
      var(--bg) 97%);
  }
  /* Here the copy sits below the band rather than beside it, so the guard
     has to run the other way. Same rule: gone before it reaches any text. */
  .hero__smoke{
    -webkit-mask-image:linear-gradient(180deg, #000 52%, rgba(0,0,0,.4) 74%, transparent 90%);
            mask-image:linear-gradient(180deg, #000 52%, rgba(0,0,0,.4) 74%, transparent 90%);
  }
  /* Two layers instead of three, and less blur. Three big blurred layers
     under a screen blend is a lot of compositing for a phone. */
  .hero__smoke i:nth-child(3){ display:none; }
  .hero__smoke i:nth-child(1){ filter:blur(8px); }
  .hero__smoke i:nth-child(2){ filter:blur(16px); }
  .hero__scrim{
    background:linear-gradient(180deg, rgba(11,11,12,.38) 0%, transparent 24%, rgba(11,11,12,.45) 60%, rgba(11,11,12,.88) 100%);
  }
  .hero__copy{ max-width:none; }
  /* Ramps from nothing rather than starting at full strength. At -64px and
     an opaque first stop this drew a hard horizontal line straight across the
     photo where the pool began. The px stops put the ramp above the eyebrow
     and the full darkness underneath it, independent of how tall the copy
     ends up. */
  .hero__copy::before{
    left:-28px; right:-28px; top:-140px; bottom:-24px;
    background:linear-gradient(180deg,
      transparent 0,
      rgba(11,11,12,.5) 70px,
      rgba(11,11,12,.88) 140px,
      rgba(11,11,12,.88) 52%,
      transparent 94%);
  }
}

@media (max-width:720px){
  .hero .eyebrow::before{ display:none; }
  .hero .eyebrow{ font-size:11px; letter-spacing:.13em; }
  .hero__title{ font-size:34px; }
  .hero__actions .btn{ flex:1 1 100%; justify-content:center; }

  /* Tap targets. These sat around 24px tall, fine with a mouse and a coin
     toss with a thumb. The .code chip is handled down in the trust bar
     section instead, because its base rule is set later in this file and
     would win over an override placed here. */
  .footer__links a{ padding:9px 0; }
  .trust__logos a{ padding:8px 0; }
}

/* =============== FOLLOW =============== */

.follow{
  padding:clamp(30px,4vw,44px) 0;
  background:
    radial-gradient(58% 130% at 50% 50%, rgba(var(--accent-rgb),.09), transparent 70%),
    var(--bg);
}
.follow__inner{
  display:flex;
  align-items:center;
  justify-content:center;
  flex-wrap:wrap;
  gap:16px 32px;
}
.follow__label{
  margin:0;
  font-size:11px; font-weight:600; letter-spacing:.2em; text-transform:uppercase;
  color:var(--muted-2);
}
.follow__links{ display:flex; flex-wrap:wrap; gap:14px; }

.follow__btn{
  display:inline-flex;
  align-items:center;
  gap:12px;
  padding:13px 24px;
  border:1px solid var(--line-2);
  border-radius:999px;
  background:var(--surface);
  color:var(--text);
  font-size:15px;
  font-weight:600;
  letter-spacing:.01em;
  transition:border-color .22s var(--ease), background .22s var(--ease),
             color .22s var(--ease), transform .22s var(--ease);
}
.follow__btn:hover{
  border-color:var(--accent);
  background:linear-gradient(180deg, rgba(var(--accent-rgb),.14), var(--surface));
  transform:translateY(-2px);
}
.follow__btn:focus-visible{ outline:2px solid var(--accent-hi); outline-offset:3px; }
.follow__btn svg{ width:19px; height:19px; flex:none; color:var(--accent); }

.follow__net{
  font-size:11px; font-weight:600; letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2);
  padding-left:12px;
  border-left:1px solid var(--line);
}

@media (max-width:560px){
  .follow__links{ width:100%; flex-direction:column; }
  .follow__btn{ justify-content:center; padding:15px 22px; }
}

/* =============== TRUST BAR =============== */

.trust{
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
  background:var(--bg-alt);
  padding:30px 0;
}
.trust__inner{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:18px 48px;
}
.trust__label{
  font-size:11px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
}
.trust__logos{ display:flex; flex-wrap:wrap; align-items:center; gap:16px 40px; }
.trust__logos a{
  font-family:var(--display);
  font-weight:600; font-size:16px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--muted);
  transition:color .2s var(--ease);
  font-variation-settings:"wdth" 100;
}
.trust__logos a:hover{ color:var(--accent-hi); }

.trust__item{ display:inline-flex; align-items:center; gap:12px; }

.code{
  display:inline-flex; align-items:center; gap:8px;
  font-family:var(--display);
  font-size:13px; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--accent-hi);
  background:var(--accent-dim);
  border:1px dashed var(--accent-line);
  border-radius:999px;
  padding:6px 14px;
  cursor:pointer;
  transition:background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.code:hover{ background:rgba(var(--accent-rgb),.18); border-color:var(--accent); }
.code:focus-visible{ outline:2px solid var(--accent-hi); outline-offset:3px; }
.code__icon{ opacity:.75; }
.code.is-copied{
  color:var(--accent-ink);
  background:var(--accent-btn);
  border-style:solid;
  border-color:var(--accent-btn);
}

/* Must live after the base .code rule above, not up in the hero's mobile
   block, or the base padding wins and the chip stays a 28px thumb target. */
@media (max-width:720px){
  .code{ padding:11px 17px; }
}

/* =============== FIT (who this is / isn't for) =============== */

.fit__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
  gap:24px;
}
.fit__card{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r);
  padding:36px 32px;
}
.fit__card--yes{ border-color:var(--accent-line); background:linear-gradient(180deg, rgba(var(--accent-rgb),.06), var(--surface) 60%); }
.fit__card h3{
  font-size:13px; letter-spacing:.16em; text-transform:uppercase;
  margin:0 0 24px; color:var(--muted-2); font-weight:600;
  font-family:var(--sans);
}
.fit__card--yes h3{ color:var(--accent); }
.fit__list{ list-style:none; margin:0; padding:0; display:grid; gap:16px; }
.fit__list li{
  display:flex; gap:14px; align-items:flex-start;
  color:var(--muted); font-size:16px; line-height:1.55;
}
.fit__list li::before{
  content:""; flex:none; width:18px; height:18px; margin-top:4px;
  border-radius:50%;
  border:1.5px solid var(--line-2);
  background:no-repeat center/10px 10px;
}
.fit__card--yes .fit__list li::before{
  border-color:var(--accent);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.6 9 10 3.2' fill='none' stroke='%233fa252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.fit__card--no .fit__list li::before{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3.2 3.2 8.8 8.8M8.8 3.2 3.2 8.8' fill='none' stroke='%2378726a' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* =============== PILLARS =============== */

/* Explicit 3 columns, not auto-fit — the container's gray shows through the
   1px gaps, so a fourth empty auto-fit cell reads as a broken box. */
.pillars{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1px;
  background:var(--line);
  border:1px solid var(--line);
  border-radius:var(--r);
  overflow:hidden;
}
.pillar{
  background:var(--bg);
  padding:44px 34px;
  transition:background .3s var(--ease);
}
.pillar:hover{ background:var(--surface); }
.pillar__num{
  font-family:var(--display);
  font-size:13px; font-weight:700; letter-spacing:.14em;
  color:var(--accent);
  display:block; margin-bottom:22px;
}
.pillar h3{
  font-size:clamp(24px,2.6vw,30px);
  text-transform:uppercase;
  margin-bottom:16px;
}
.pillar p{ color:var(--muted); font-size:16px; margin:0; }

@media (max-width:880px){
  .pillars{ grid-template-columns:1fr; }
}

/* =============== PROOF / TESTIMONIALS =============== */

.proof__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
  gap:24px;
}
.proof__card{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r);
  overflow:hidden;
  display:flex; flex-direction:column;
  transition:border-color .3s var(--ease), transform .3s var(--ease);
}
.proof__card:hover{ border-color:var(--accent-line); transform:translateY(-3px); }

.proof__media{
  aspect-ratio:4/3;
  background:
    repeating-linear-gradient(45deg, rgba(245,240,232,.02) 0 12px, transparent 12px 24px),
    linear-gradient(160deg, #202024, #131315);
  display:flex; align-items:center; justify-content:center;
  border-bottom:1px solid var(--line);
  position:relative;
}
.proof__media img{ width:100%; height:100%; object-fit:cover; }
.proof__ph{
  font-size:11px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; text-align:center; padding:0 20px;
}
.proof__body{ padding:28px 26px 30px; display:flex; flex-direction:column; gap:18px; flex:1; }
.proof__stat{
  display:flex; flex-wrap:wrap; gap:8px 18px;
  font-family:var(--display);
  font-size:13px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent);
}
.proof__quote{ color:var(--muted); font-size:16px; line-height:1.6; margin:0; flex:1; }
.proof__who{
  font-size:12px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
  padding-top:16px; border-top:1px solid var(--line);
}

/* =============== TESTIMONIAL CAROUSEL ===============
   A real scroll container that also drifts on its own, NOT a CSS marquee.
   It started as a transform animation, which cannot be scrolled: the user has
   no way into it and pausing on hover was the only interaction available.
   Driving scrollLeft instead means trackpads, touch and a mouse drag all work,
   and the drift is just something added on top every frame.

   It deliberately does NOT pause on hover. Stopping on a card used to halt the
   strip, which reads as broken when you were only passing over it.

   Two identical .tm__set blocks make the wrap seamless: once scrollLeft passes
   (one set + one gap) the view is identical, so main.js subtracts that and
   nobody sees a jump. The second set is aria-hidden with tabindex="-1" cards,
   so assistive tech and tab order only ever see one copy. */

.tm{
  position:relative;
  margin-top:8px;
  overflow-x:auto;
  overflow-y:hidden;
  /* html has scroll-behavior:smooth, which would fight a scrollLeft written
     every frame. */
  scroll-behavior:auto;
  /* Absorbs the card's hover lift, which overflow-y:hidden would otherwise
     clip. */
  padding:5px 0;
  scrollbar-width:none;
  -ms-overflow-style:none;
  /* Cards dissolve at the edges instead of being cut off by the viewport. */
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
}
.tm::-webkit-scrollbar{ display:none; }
.tm.is-dragging{ cursor:grabbing; }

.tm__track{
  display:flex;
  gap:20px;
  width:max-content;
}
.tm__set{ display:flex; gap:20px; }

.tm__card{
  flex:none;
  width:clamp(232px, 25vw, 288px);
  display:flex;
  flex-direction:column;
  text-align:left;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r);
  overflow:hidden;
  padding:0;
  cursor:pointer;
  font:inherit;
  color:inherit;
  position:relative;
  transition:border-color .28s var(--ease), transform .28s var(--ease);
}
.tm__card:hover{ border-color:var(--accent-line); transform:translateY(-3px); }
.tm.is-dragging .tm__card{ cursor:grabbing; }
.tm__card:focus-visible{ outline:2px solid var(--accent-hi); outline-offset:3px; }

/* Says out loud that the content is invented. Delete with the sample data. */
.tm__flag{
  position:absolute; top:10px; right:10px; z-index:2;
  font-size:9.5px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted);
  background:rgba(11,11,12,.78);
  border:1px solid var(--line-2);
  border-radius:999px;
  padding:4px 9px;
}

.tm__media{
  display:flex; align-items:center; justify-content:center;
  aspect-ratio:4/3;
  border-bottom:1px solid var(--line);
  background:
    repeating-linear-gradient(45deg, rgba(245,240,232,.02) 0 12px, transparent 12px 24px),
    linear-gradient(160deg, #202024, #131315);
}
.tm__ph{
  font-size:10px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; text-align:center; padding:0 14px;
}

.tm__body{ display:flex; flex-direction:column; gap:12px; padding:20px 20px 22px; flex:1; }
.tm__stat{
  font-family:var(--display);
  font-size:12px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent);
}
.tm__quote{ color:var(--muted); font-size:14.5px; line-height:1.55; flex:1; }
.tm__who{
  font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
  padding-top:12px; border-top:1px solid var(--line);
}

.tm__hint{
  margin:22px 0 0;
  font-size:11px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
}

@media (prefers-reduced-motion:reduce){
  /* The drift is switched off in main.js; the strip stays scrollable, so both
     sets have to stay in place for the wrap to keep working by hand. */
  .tm__card:hover{ transform:none; }
}

/* --- single testimonial ---
   One client, so the strip doesn't scroll: it centres a wider card that shows
   the before and after side by side. The carousel rules above are untouched
   and still work; removing .tm--single and adding cards brings them back. */

.tm--single{
  overflow:visible;
  padding:0;
  -webkit-mask-image:none;
          mask-image:none;
}
.tm--single .tm__track{ width:100%; justify-content:center; }
.tm--single .tm__set{ width:100%; justify-content:center; }
.tm--single .tm__card{
  width:min(100%, 560px);
  cursor:pointer;
}
.tm--single .tm__card:hover{ transform:translateY(-2px); }

.tm__shots{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:1px;
  background:var(--line);
  border-bottom:1px solid var(--line);
}
.tm__shot{ position:relative; display:block; background:var(--bg); }
.tm__shot img{
  width:100%;
  /* Both files are exported at 3:4 with the subject framed to the same
     height, so cover has almost nothing to crop and the pair reads as a
     genuine comparison rather than two unrelated photos. */
  aspect-ratio:3/4;
  object-fit:cover;
  object-position:center;
  display:block;
}
.tm__shot em{
  position:absolute; left:10px; bottom:10px;
  font-style:normal;
  font-size:10px; font-weight:600; letter-spacing:.16em; text-transform:uppercase;
  color:var(--text);
  background:rgba(11,11,12,.72);
  border-radius:999px;
  padding:4px 10px;
}

.tmodal__shots figure img,
.tmodal__pair img{
  width:100%;
  display:block;
  border:1px solid var(--line);
  border-radius:8px;
}
.tmodal__shots figure img{ aspect-ratio:3/4; object-fit:cover; object-position:center; }
.tmodal__pair{ margin:22px 0 0; display:flex; flex-direction:column; gap:8px; }
.tmodal__pair img{ aspect-ratio:4/5; object-fit:cover; object-position:center 30%; }
.tmodal__pair figcaption{
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; text-align:center;
}

@media (max-width:560px){
  .tm--single .tm__card{ width:100%; }
}

/* =============== TESTIMONIAL POPUP =============== */

.tmodal{
  width:min(92vw, 520px);
  max-height:min(80vh, 680px);
  padding:0;
  border:1px solid var(--line-2);
  border-radius:var(--r);
  background:var(--surface);
  color:var(--text);
  overflow:hidden;
  box-shadow:var(--shadow);
}
.tmodal::backdrop{
  background:rgba(6,6,7,.74);
  -webkit-backdrop-filter:blur(4px);
          backdrop-filter:blur(4px);
}
.tmodal__inner{ display:flex; flex-direction:column; max-height:inherit; }

.tmodal__bar{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:16px 16px 16px 22px;
  border-bottom:1px solid var(--line);
  flex:none;
}
.tmodal__flag{
  margin:0;
  font-size:10px; font-weight:600; letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2);
}
.tmodal__x{
  flex:none;
  width:32px; height:32px;
  display:flex; align-items:center; justify-content:center;
  background:none; border:1px solid var(--line-2); border-radius:8px;
  color:var(--muted); cursor:pointer;
  transition:color .2s var(--ease), border-color .2s var(--ease);
}
.tmodal__x:hover{ color:var(--text); border-color:var(--accent); }
.tmodal__x:focus-visible{ outline:2px solid var(--accent-hi); outline-offset:2px; }

/* The scroll lives here, not on the dialog, so the bar stays put. */
.tmodal__body{ padding:24px 22px 28px; overflow-y:auto; }
.tmodal__body p{ color:var(--muted); font-size:15px; line-height:1.65; }
.tmodal__stat{
  margin:0 0 16px;
  font-family:var(--display);
  font-size:13px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent) !important;
}
.tmodal__shots{ display:grid; grid-template-columns:1fr 1fr; gap:10px; margin:0 0 20px; }
.tmodal__shots figure{
  margin:0;
  display:flex; flex-direction:column; gap:8px;
}
/* 4:5 rather than 3:4. Physique shots want portrait, but the taller ratio
   pushed the whole story below the fold of the popup before you'd read a
   word. The figcaption is the only label now; there used to be a second one
   inside the box saying the same thing. */
.tmodal__shots figure > span{
  display:flex; align-items:center; justify-content:center;
  aspect-ratio:4/5;
  border:1px solid var(--line);
  border-radius:8px;
  background:
    repeating-linear-gradient(45deg, rgba(245,240,232,.02) 0 12px, transparent 12px 24px),
    linear-gradient(160deg, #202024, #131315);
}
.tmodal__shots figcaption{
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; text-align:center;
}
.tmodal__quote{
  margin:0 0 18px;
  font-family:var(--display);
  font-size:17px; font-weight:600; line-height:1.4;
  color:var(--text) !important;
  letter-spacing:-.01em;
}
.tmodal__who{
  margin:20px 0 0 !important;
  padding-top:16px;
  border-top:1px solid var(--line);
  font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2) !important; font-weight:600;
}

@media (max-width:480px){
  .tmodal{ width:94vw; }
  .tmodal__body{ padding:20px 18px 24px; }
}

/* =============== ABOUT =============== */

.about__grid{
  display:grid;
  /* Wider media column than the Perez original. That build had one small
     portrait; this has a layered pair carrying the section, and at .5fr they
     were too small to be worth showing. */
  grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr);
  gap:clamp(28px,4vw,56px);
  align-items:center;
}
@media (max-width:860px){ .about__grid{ grid-template-columns:1fr; } }

/* Two shots, layered. The inset overlaps the main one and carries a gap in
   the page colour so it reads as sitting in front rather than butted up
   against it. Extra bottom padding reserves the room the inset hangs into,
   or it collides with whatever follows. */
.about__media{
  position:relative;
  max-width:420px;
  padding:0 0 clamp(52px,7vw,84px) clamp(34px,5vw,60px);
}
.about__shot{
  margin:0;
  border-radius:var(--r);
  border:1px solid var(--line);
  overflow:hidden;
  background:linear-gradient(160deg, #202024, #131315);
  position:relative;
}
.about__shot img{ width:100%; aspect-ratio:4/5; object-fit:cover; display:block; }
.about__shot::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, transparent 58%, rgba(11,11,12,.5));
  pointer-events:none;
}
.about__shot--inset{
  position:absolute;
  left:0;
  bottom:0;
  width:56%;
  /* The ring is page colour, not a border, so it works over the section
     background without needing to match a border colour. */
  box-shadow:0 0 0 6px var(--bg-alt), var(--shadow);
}

@media (max-width:860px){
  .about__media{ max-width:300px; }
}
/* The shared .section__title carries no bottom margin, which is right in a
   .section__head but leaves the heading sitting on the first line of prose
   here. */
.about__body .section__title{ margin-bottom:24px; }
.about__body p{ color:var(--muted); font-size:17px; }
.about__pull{
  margin:28px 0 0;
  padding:22px 0 0;
  border-top:1px solid var(--line);
  font-family:var(--display);
  font-size:clamp(19px,2.2vw,24px);
  font-weight:600;
  line-height:1.3;
  color:var(--text);
  letter-spacing:-.01em;
}

/* =============== PROCESS ===============
   A rail with small numbered nodes rather than the big stacked numerals this
   started with. Those were fine on a wide screen and fell apart on a phone:
   the single-column fallback put a 34px numeral on its own line above every
   heading, so each step became three loose blocks and five of them read as a
   staggered list rather than a sequence. The rail keeps the same two-column
   shape at every width, which is what makes it hold together on mobile. */

.steps{ display:grid; gap:0; }

.step{
  position:relative;
  display:grid;
  grid-template-columns:34px 1fr;
  column-gap:clamp(16px,2.2vw,26px);
  padding-bottom:clamp(30px,3.6vw,42px);
  align-items:start;
}
.step:last-child{ padding-bottom:0; }

/* The connector, from the bottom of this node to the top of the next one.
   `bottom:0` lands on the padding edge, which is exactly where the next
   node starts, so the run stays flush without hard-coding a height. */
.step::before{
  content:"";
  position:absolute;
  left:16px;          /* (34px node / 2) minus half the 1px line */
  top:38px;
  bottom:0;
  width:1px;
  background:var(--line-2);
}
.step:last-child::before{ display:none; }

.step__num{
  width:34px; height:34px;
  border-radius:50%;
  border:1px solid var(--accent-line);
  background:var(--accent-dim);
  color:var(--accent);
  font-family:var(--display);
  font-size:12.5px; font-weight:700; letter-spacing:.04em;
  display:flex; align-items:center; justify-content:center;
  font-variation-settings:"wdth" 100;
  /* Above the connector, so the line never shows through the node. */
  position:relative; z-index:1;
}

/* Nudged down so the heading's cap height sits level with the node rather
   than its ascender line. */
.step h3{
  font-size:clamp(19px,2.1vw,23px);
  text-transform:uppercase;
  margin:5px 0 10px;
}
.step p{ color:var(--muted); font-size:16px; margin:0; max-width:62ch; }
.step__tag{
  display:inline-block; margin-top:14px;
  font-size:11px; letter-spacing:.16em; text-transform:uppercase; font-weight:600;
  color:var(--accent);
  background:var(--accent-dim);
  border:1px solid var(--accent-line);
  border-radius:999px;
  padding:5px 13px;
}

@media (max-width:560px){
  .step{ grid-template-columns:28px 1fr; column-gap:14px; }
  .step::before{ left:13px; top:32px; }
  .step__num{ width:28px; height:28px; font-size:11.5px; }
  .step h3{ margin-top:2px; }
}

/* =============== FINAL CTA =============== */

.cta{
  position:relative;
  padding:clamp(96px,13vw,168px) 0;
  background:
    radial-gradient(90% 120% at 50% 0%, rgba(var(--accent-rgb),.14), transparent 62%),
    var(--bg-alt);
  border-top:1px solid var(--line);
  text-align:center;
  overflow:hidden;
  isolation:isolate;
}

.cta .wrap{ position:relative; z-index:2; }

/* The Perez build runs a looping gym clip behind this block. There's no
   footage for Ty yet, so it's a flat gradient. If a clip does land, port
   .cta__video / .cta__scrim back over with it and re-measure the headline
   contrast against the brightest frame. */
.cta__title{
  font-size:clamp(34px,5.6vw,64px);
  text-transform:uppercase;
  max-width:16ch; margin:0 auto;
}
.cta__sub{ color:var(--muted); font-size:clamp(17px,1.9vw,19px); max-width:54ch; margin:24px auto 0; }
.cta__actions{ margin-top:38px; display:flex; justify-content:center; flex-wrap:wrap; gap:14px; }
.cta__note{ margin-top:22px; font-size:13px; color:var(--muted-2); }

/* =============== FOOTER =============== */

.footer{
  border-top:1px solid var(--line);
  padding:52px 0 44px;
  background:var(--bg);
}
.footer__inner{
  display:flex; flex-wrap:wrap; gap:24px 40px;
  align-items:center; justify-content:space-between;
}
.footer__links{ display:flex; flex-wrap:wrap; gap:14px 28px; }
.footer__links a{
  font-size:13px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted-2); transition:color .2s var(--ease);
}
.footer__links a:hover{ color:var(--accent-hi); }
.footer__fine{ font-size:12px; color:var(--muted-2); letter-spacing:.04em; }

/* =========================================================
   APPLICATION WIZARD  (apply.html)
   ========================================================= */

.apply-page{
  min-height:100vh;
  display:flex; flex-direction:column;
  background:
    radial-gradient(80% 60% at 50% -10%, rgba(var(--accent-rgb),.10), transparent 60%),
    var(--bg);
}

.apply__bar{
  position:sticky; top:0; z-index:20;
  background:rgba(11,11,12,.92);
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line);
}
.apply__bar-inner{
  display:flex; align-items:center; justify-content:space-between;
  gap:20px; height:68px;
}
.apply__count{
  font-size:12px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
}
.apply__progress{
  height:2px; background:var(--line); position:relative; overflow:hidden;
}
.apply__progress i{
  position:absolute; inset:0 auto 0 0;
  background:var(--accent);
  width:0%;
  transition:width .45s var(--ease);
}

.apply__main{
  flex:1;
  display:flex; align-items:center;
  padding:clamp(40px,8vh,88px) 0;
}
.apply__shell{ width:100%; max-width:720px; margin:0 auto; padding:0 28px; }

.q{ display:none; }
.q.is-active{ display:block; animation:qin .45s var(--ease); }
@keyframes qin{ from{ opacity:0; transform:translateY(14px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion:reduce){ .q.is-active{ animation:none; } }

.q__index{
  font-family:var(--display);
  font-size:12px; font-weight:700; letter-spacing:.18em; text-transform:uppercase;
  color:var(--accent); margin-bottom:18px; display:block;
}
.q__title{
  font-size:clamp(26px,3.8vw,40px);
  line-height:1.15;
  margin-bottom:14px;
}
.q__help{ color:var(--muted); font-size:16px; margin:0 0 30px; max-width:56ch; }

.field{
  width:100%;
  background:var(--surface-2);
  border:1px solid var(--line-2);
  border-radius:10px;
  color:var(--text);
  font-family:var(--sans);
  font-size:17px;
  line-height:1.6;
  padding:16px 18px;
  transition:border-color .2s var(--ease), background .2s var(--ease);
  -webkit-appearance:none;
  appearance:none;
}
.field::placeholder{ color:var(--muted-2); }
.field:focus{
  outline:none;
  border-color:var(--accent);
  background:var(--surface);
}
textarea.field{ min-height:150px; resize:vertical; }

/* Contact screen — several labelled fields on one step. */
.group{ display:grid; gap:18px; }
.group__row{ display:block; }
.group__label{
  display:block;
  font-size:11px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2);
  margin-bottom:9px;
}
.group__row:focus-within .group__label{ color:var(--accent); }

.choices{ display:grid; gap:12px; }
.choice{
  display:flex; align-items:flex-start; gap:16px;
  background:var(--surface-2);
  border:1px solid var(--line-2);
  border-radius:10px;
  padding:18px 20px;
  cursor:pointer;
  transition:border-color .2s var(--ease), background .2s var(--ease), transform .2s var(--ease);
}
.choice:hover{ border-color:var(--line-2); background:var(--surface); transform:translateY(-1px); }
.choice input{ position:absolute; opacity:0; pointer-events:none; }
.choice__dot{
  flex:none; width:20px; height:20px; margin-top:2px;
  border-radius:50%;
  border:1.5px solid var(--line-2);
  position:relative;
  transition:border-color .2s var(--ease);
}
.choice__dot::after{
  content:""; position:absolute; inset:4px;
  border-radius:50%; background:var(--accent);
  transform:scale(0); transition:transform .2s var(--ease);
}
.choice__text b{
  display:block;
  font-family:var(--display);
  font-size:17px; font-weight:600; letter-spacing:-.01em;
  margin-bottom:4px;
}
.choice__text small{ color:var(--muted); font-size:14px; line-height:1.5; display:block; }

/* Multi-select reads as a square with a tick, so nobody mistakes it for a
   pick-one and stops at the first option. */
.choice--check .choice__dot{ border-radius:6px; }
.choice--check .choice__dot::after{
  inset:0;
  border-radius:0;
  background:no-repeat center/11px 11px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.3 4.6 8.9 10 3.1' fill='none' stroke='%233fa252' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.choice:has(input:checked){
  border-color:var(--accent);
  background:linear-gradient(180deg, rgba(var(--accent-rgb),.09), var(--surface));
}
.choice:has(input:checked) .choice__dot{ border-color:var(--accent); }
.choice:has(input:checked) .choice__dot::after{ transform:scale(1); }
.choice:focus-within{ outline:2px solid var(--accent-hi); outline-offset:3px; }

.q__error{
  margin-top:14px;
  font-size:14px; color:var(--warn);
  display:none;
}
.q__error.is-on{ display:block; }

.q__nav{
  display:flex; align-items:center; gap:14px;
  margin-top:34px;
  padding-top:26px;
  border-top:1px solid var(--line);
}
.q__nav .spacer{ flex:1; }
.q__hint{ font-size:12px; color:var(--muted-2); letter-spacing:.04em; }
/* Phones: the primary button goes full width on its own row rather than
   fighting the back link for space and wrapping its own label. */
@media (max-width:560px){
  .q__hint{ display:none; }
  .q__nav{ flex-wrap:wrap; gap:12px; }
  .q__nav .spacer{ display:none; }
  .q__nav .btn{
    flex:1 1 100%;
    order:-1;
    justify-content:center;
  }
  .q__nav .back-link{ flex:0 0 auto; }
}

.back-link{
  background:none; border:0; cursor:pointer;
  color:var(--muted-2); font-family:var(--sans); font-size:14px;
  padding:8px 4px;
  transition:color .2s var(--ease);
}
.back-link:hover{ color:var(--text); }

/* --- confirmation --- */
.done{ display:none; text-align:center; }
.done.is-active{ display:block; animation:qin .5s var(--ease); }
.done__mark{
  width:64px; height:64px; margin:0 auto 28px;
  border-radius:50%;
  border:1.5px solid var(--accent);
  background:var(--accent-dim);
  display:flex; align-items:center; justify-content:center;
}
.done__title{ font-size:clamp(30px,4.4vw,46px); text-transform:uppercase; margin-bottom:18px; }
.done__body{ color:var(--muted); font-size:17px; max-width:52ch; margin:0 auto; }
.done__actions{ margin-top:34px; display:flex; justify-content:center; flex-wrap:wrap; gap:14px; }

/* Shown only when delivery failed. Not an error the applicant caused, so it
   reads as a handover, not a rejection. */
.done__fallback{
  margin:22px auto 0;
  max-width:52ch;
  padding:14px 18px;
  border:1px solid var(--line-2);
  border-radius:10px;
  background:var(--surface);
  color:var(--muted);
  font-size:14.5px;
  line-height:1.6;
}
.done__fallback a{ color:var(--accent); text-decoration:underline; }

.done__panel{
  margin-top:44px;
  text-align:left;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r);
  padding:28px 26px;
}
.done__panel h3{
  font-size:13px; letter-spacing:.16em; text-transform:uppercase;
  font-family:var(--sans); color:var(--muted-2); font-weight:600;
  margin-bottom:18px;
}
.done__panel ol{ margin:0; padding-left:20px; color:var(--muted); font-size:15px; display:grid; gap:10px; }

/* --- setter handoff preview (demo only, ?demo=1) --- */
.handoff{
  display:none;
  margin-top:44px; text-align:left;
  background:var(--surface);
  border:1px dashed var(--accent-line);
  border-radius:var(--r);
  padding:26px;
}
.handoff.is-on{ display:block; }
.handoff__tag{
  font-size:11px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--accent); font-weight:700; margin-bottom:16px;
}
.handoff__score{
  display:inline-flex; align-items:center; gap:10px;
  font-family:var(--display); font-weight:700;
  font-size:13px; letter-spacing:.12em; text-transform:uppercase;
  border-radius:999px; padding:7px 16px; margin-bottom:20px;
}
.handoff__score[data-tier="hot"]{ background:var(--accent-btn); color:var(--accent-ink); }
.handoff__score[data-tier="qualified"]{ background:var(--accent-dim); color:var(--accent-hi); border:1px solid var(--accent-line); }
.handoff__score[data-tier="nurture"]{ background:var(--surface-2); color:var(--muted); border:1px solid var(--line-2); }
.handoff__score[data-tier="declined"]{ background:var(--surface-2); color:var(--muted-2); border:1px solid var(--line); }
.handoff pre{
  margin:0; white-space:pre-wrap; word-break:break-word;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:13px; line-height:1.65; color:var(--muted);
  background:var(--bg); border:1px solid var(--line); border-radius:8px;
  padding:18px; max-height:340px; overflow:auto;
}
/* =========================================================
   SHINE
   Carried over from the Perez build and pulled back hard for
   neon green. Green reads far brighter than the maroon these
   effects were tuned against, so every alpha here is roughly
   half its original value, and the rim pulse is off the follow
   buttons entirely — four of them breathing in a row turned
   that strip into a light show.

   Four effects: a roaming metallic gradient on accent text, a
   sweeping highlight across pills, a breathing rim glow, and a
   bloom under the primary buttons.

   The sweeps animate transform only, so they stay on the
   compositor. The roam animates background-position, which does
   repaint, so it's kept to accent text rather than large areas.
   Everything stops for reduced-motion visitors at the bottom.
   ========================================================= */

@keyframes accentRoam{
  0%   { background-position:   0% 50%; }
  25%  { background-position:  65%  8%; }
  50%  { background-position: 100% 55%; }
  75%  { background-position:  35% 95%; }
  100% { background-position:   0% 50%; }
}
@keyframes pillSweep{
  0%   { transform:translateX(-170%); }
  100% { transform:translateX(330%); }
}
@keyframes accentPulse{
  0%,100% { box-shadow:0 0 12px rgba(var(--accent-rgb),.07), inset 0 0 10px rgba(var(--accent-rgb),.03); }
  50%     { box-shadow:0 0 22px rgba(var(--accent-hi-rgb),.17), inset 0 0 12px rgba(var(--accent-rgb),.07); }
}
@keyframes ctaGlow{
  0%,100% { box-shadow:0 0 0 0 rgba(var(--accent-hi-rgb),0); }
  50%     { box-shadow:0 0 28px 1px rgba(var(--accent-hi-rgb),.22); }
}

/* NO `filter` ON ANY OF THESE.
   WebKit drops the background-clip:text clip when the element also carries a
   filter, and paints the whole gradient as a solid rectangle behind the type.
   Reproduced in Safari at every eyebrow on the page. The Perez and Thar builds
   still carry the drop-shadow this was ported from, so they have the same box.
   The glow is not worth it; the intro keeps its halo on .intro__rule instead. */
@supports (-webkit-background-clip:text) or (background-clip:text){
  .eyebrow,
  .follow__label,
  .trust__label{
    background-image:linear-gradient(115deg,
      var(--accent) 0%, var(--accent) 34%,
      var(--accent-mid) 44%, var(--accent-peak) 50%, var(--accent-mid) 56%,
      var(--accent) 66%, var(--accent) 100%);
    background-size:300% 300%;
    -webkit-background-clip:text; background-clip:text;
    color:transparent;
    animation:accentRoam 4.6s ease-in-out infinite;
  }
  /* FIT in the intro gets a slower, heavier version. */
  .intro__l--b{
    background-image:linear-gradient(115deg,
      var(--accent) 0%, var(--accent) 32%,
      var(--accent-mid) 43%, var(--accent-peak) 50%, var(--accent-mid) 57%,
      var(--accent) 68%, var(--accent) 100%);
    background-size:300% 300%;
    -webkit-background-clip:text; background-clip:text;
    color:transparent;
    /* Both animations, not just the roam. These letters already carry the
       slide-in from .intro__l, and a bare animation here would replace it,
       so FIT would never travel in. */
    animation:
      slideAcross .85s cubic-bezier(.16,.84,.34,1) var(--d) forwards,
      accentRoam 3.4s ease-in-out infinite;
  }
  .brand em{
    background-image:linear-gradient(115deg,
      var(--accent) 0%, var(--accent) 36%,
      var(--accent-mid) 46%, var(--accent-peak) 50%, var(--accent-mid) 54%,
      var(--accent) 64%, var(--accent) 100%);
    background-size:300% 300%;
    -webkit-background-clip:text; background-clip:text;
    color:transparent;
    animation:accentRoam 5.2s ease-in-out infinite;
  }
}

/* Pills: a highlight sweeping across, staggered so they don't move in
   lockstep. The rim pulse is only on the two that appear once or twice
   per page. */
.code,
.follow__btn,
.step__tag{
  position:relative;
  overflow:hidden;
}
.code,
.step__tag{ animation:accentPulse 3.6s ease-in-out infinite; }

.code::after,
.follow__btn::after,
.step__tag::after{
  content:"";
  position:absolute; top:0; bottom:0; left:0;
  width:44%;
  background:linear-gradient(115deg, transparent, rgba(245,240,232,.13), transparent);
  transform:translateX(-170%);
  pointer-events:none;
  animation:pillSweep 4.6s linear infinite;
}
.follow__btn:nth-child(2)::after{ animation-delay:.7s; }
.follow__btn:nth-child(3)::after{ animation-delay:1.4s; }
.follow__btn:nth-child(4)::after{ animation-delay:2.1s; }
.trust__item:nth-child(2) .code,
.trust__item:nth-child(2) .code::after{ animation-delay:1.3s; }
.step__tag{ animation-delay:.5s; }

.code:hover,
.follow__btn:hover{
  animation-play-state:paused;
  box-shadow:0 0 22px rgba(var(--accent-hi-rgb),.2), inset 0 0 12px rgba(var(--accent-rgb),.08);
}

/* The money buttons. A bloom underneath pulls the eye without touching
   the fill, so the ink-on-green contrast is untouched. */
.btn--primary{ animation:ctaGlow 3.2s ease-in-out infinite; }
.btn--primary:hover{
  animation-play-state:paused;
  box-shadow:0 0 26px 1px rgba(var(--accent-hi-rgb),.28);
}

.intro__rule{ box-shadow:0 0 16px rgba(var(--accent-rgb),.3); }
.follow__btn{ box-shadow:0 10px 24px -18px rgba(var(--accent-rgb),.55); }

@media (prefers-reduced-motion:reduce){
  .eyebrow,
  .follow__label,
  .trust__label,
  .intro__l--b,
  .brand em,
  .code,
  .follow__btn,
  .step__tag,
  .btn--primary{
    animation:none;
    background-position:0 0;
  }
  .code::after,
  .follow__btn::after,
  .step__tag::after{ display:none; }
}
