/* ==========================================================================
   TRITAC MARTIAL ARTS — shared layer (tma-design-port)
   Lifted from the Claude Design canvas (858 inline styles, 0 media queries)
   into a real class vocabulary. Mechanical extraction, not a redesign:
   the rendered result at 1440px must match the canvas.

   Page-specific rules do NOT live here. Each page agent writes
   css/<page>.css scoped under its body class (.p-home .p-hub .p-hiw
   .p-pricing .p-coaches) and that file is appended to this one later.

   Token drift corrected: the canvas cyan #00f0ff -> brand cyan #00E5FF
   (rgba(0,240,255,a) -> rgba(0,229,255,a)) everywhere.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root{
  /* ground */
  --bg:#0a0a12;
  --bg-deep:#06060e;
  /* The alternating band ground. #06060e against a #0a0a12 body is a 4-point
     luminance step — invisible on screen, so consecutive sections read as one
     undifferentiated run. This is the step that is actually perceptible.
     --bg-deep stays as-is: it is the ground *behind* hero photography and the
     footer, where it must sit darker than the page. */
  --band-deep:#12121c;
  --surface:rgba(20,20,31,.72);
  --surface-flat:rgba(20,20,31,.5);
  --surface-glass:rgba(31,31,37,.5);
  --surface-glass-up:rgba(31,31,37,.6);
  --surface-bar:rgba(10,10,18,.6);

  /* type colour ramp */
  --fg-0:#ffffff;
  --fg-1:#e4e1e9;
  --fg-1b:#d4dcdd;
  --fg-2:#b9cacb;
  --fg-2b:#8a9697;
  --fg-3:#849495;
  /* Lifted from #5d6a6b, which measured 3.31-3.60:1 on the dark grounds and
     failed the 4.5:1 body floor on all 6 of its uses - the Google-review
     attributions and the small mono labels. #758283 clears it everywhere
     (4.67 card / 4.95 page / 5.07 deep) and is still a visible step below
     --fg-3 #849495 at 5.89-6.39, so the palette keeps its quietest tone. */
  --fg-4:#758283;
  --fg-5:#3f4a4b;

  /* brand + accents */
  --brand-red:#C8102E;
  /* Small red TYPE only. #C8102E measures 3.16-3.43:1 on the three dark
     grounds, under the 4.5:1 body-text floor, and the port sets these
     kickers at 9.5-10.5px where the previous build used 13px. #EE3B52 is
     the closest tint to the brand red that clears 4.5 everywhere
     (4.77 card / 5.05 page / 5.18 deep). --brand-red is unchanged and still
     owns buttons, rules, dots and fills, which carry white text or are not
     type at all. */
  --brand-red-lt:#EE3B52;
  --cyan:#00E5FF;
  --cyan-soft:#7ff5ff;
  --violet:#571BC1;
  --violet-lt:#a78bfa;
  --gold:#ffd700;
  --green:#65f2b5;
  --olive:#9aa33a;

  /* lines */
  --border-subtle:rgba(255,255,255,.08);
  --border-hair:rgba(255,255,255,.06);
  --border-mid:rgba(255,255,255,.10);
  --border-strong:rgba(255,255,255,.14);
  --line-cyan:rgba(0,229,255,.28);
  --line-cyan-soft:rgba(0,229,255,.22);
  --line-red:rgba(200,16,46,.45);

  /* glow */
  --glow-red:0 0 34px rgba(200,16,46,.45);
  --glow-red-sm:0 0 24px rgba(200,16,46,.40);
  --glow-cyan:0 0 34px rgba(0,229,255,.45);
  --shadow-plate:0 30px 80px rgba(0,0,0,.6);
  --shadow-plate-sm:0 24px 70px rgba(0,0,0,.55);

  /* type */
  --font-headline:'Space Grotesk',sans-serif;
  --font-body:'Manrope',sans-serif;
  --font-mono:'Space Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --font-mark:'Pirulen','Space Grotesk',sans-serif;

  /* motion + metrics */
  --ease:cubic-bezier(.16,1,.3,1);
  --shell:1440px;
  --shell-narrow:1180px;
  --pad-x:42px;
  --nav-h:64px;
  --anchor-offset:96px;
}

/* Pirulen — the wordmark face. Space Grotesk carries the fallback so the
   mark never reflows into a serif. */
@font-face{
  font-family:'Pirulen';
  src:url('assets/fonts/pirulen-rg.otf') format('opentype');
  font-weight:400;
  font-style:normal;
  font-display:swap;
}

/* --------------------------------------------------------------------------
   2. RESET / BASE
   -------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{
  scroll-behavior:smooth;
  /* clip, not hidden: `hidden` on an ancestor kills position:sticky */
  overflow-x:clip;
  -webkit-text-size-adjust:100%;
}
body{
  margin:0;
  padding:0;
  max-width:100%;
  overflow-x:clip;
  background:var(--bg);
  color:var(--fg-1b);
  font-family:var(--font-body),system-ui,sans-serif;
  font-size:16px;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4,h5,h6,p,figure,blockquote{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
img,video,svg,canvas{display:block;max-width:100%}
img{height:auto}
a{color:var(--cyan);text-decoration:none}
a:hover{color:var(--cyan-soft)}
button{font:inherit}
::selection{background:var(--brand-red);color:#fff}
:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}

/* Anchors clear the sticky nav. */
section[id],[id].anchor{scroll-margin-top:var(--anchor-offset)}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* Material Symbols — SELF-HOSTED, SUBSET TO THE EIGHT GLYPHS THIS SITE USES.
   (account_tree, arrow_forward, assignment_turned_in, bolt, check,
    content_cut, settings_input_antenna, workspace_premium)

   Do not replace this with the fonts.googleapis.com stylesheet. That link
   pulled the whole family: 1,127,988 bytes over a third-party origin, for
   eight glyphs — the single heaviest asset on the site by a factor of five.
   This file is 4,104 bytes and same-origin. Regenerate it with
     https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined\
       :wght,FILL@100..700,0..1&icon_names=<comma,separated,names>
   and save the woff2 it points at. It keeps both variable axes (FILL 0..1,
   wght 100..700), so .fill still works.

   The markup writes each icon as a NUMERIC CODEPOINT ENTITY (&#xe5ca;), never
   as the ligature name. With the ligature name, a font that fails to load
   paints the literal English word into the copy — "check A customized training
   plan", twelve times down the pricing page. A codepoint can only ever fall
   back to one tofu box. Keep it that way. */
@font-face{
  font-family:'Material Symbols Outlined';
  src:url('assets/fonts/material-symbols-subset.woff2') format('woff2');
  font-weight:100 700;
  font-style:normal;
  font-display:block;
}
.material-symbols-outlined{
  font-family:'Material Symbols Outlined';
  font-weight:normal;
  font-style:normal;
  line-height:1;
  flex:none;
  vertical-align:middle;
  letter-spacing:normal;
  text-transform:none;
  white-space:nowrap;
  word-wrap:normal;
  direction:ltr;
  -webkit-font-smoothing:antialiased;
}
.material-symbols-outlined.fill{font-variation-settings:'FILL' 1;flex:0 0 auto;min-width:auto}
.ic-14{font-size:14px}.ic-15{font-size:15px}.ic-16{font-size:16px}
.ic-17{font-size:17px}.ic-18{font-size:18px}.ic-20{font-size:20px}
.ic-24{font-size:24px}.ic-26{font-size:26px}

/* --------------------------------------------------------------------------
   3. KEYFRAMES (ported from the canvas <helmet> style block)
   -------------------------------------------------------------------------- */
@keyframes tk{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@keyframes orbit{from{transform:translate(-50%,-50%) rotate(0deg)}to{transform:translate(-50%,-50%) rotate(360deg)}}
@keyframes orbitR{from{transform:translate(-50%,-50%) rotate(360deg)}to{transform:translate(-50%,-50%) rotate(0deg)}}
@keyframes pulseDot{0%,100%{opacity:.35}50%{opacity:1}}
@keyframes gline{0%,100%{opacity:.25}50%{opacity:.7}}

/* --------------------------------------------------------------------------
   4. LAYOUT — shell, sections, bands, grids
   -------------------------------------------------------------------------- */
.shell{position:relative;width:100%;max-width:var(--shell);margin:0 auto;padding-inline:var(--pad-x)}
.shell--narrow{max-width:var(--shell-narrow)}

.sec{position:relative;max-width:var(--shell);margin:0 auto;padding:88px var(--pad-x)}
.sec--lg{padding:96px var(--pad-x)}
.sec--md{padding:72px var(--pad-x)}
.sec--sm{padding:56px var(--pad-x)}
.sec--xs{padding:34px var(--pad-x)}
.sec--narrow{max-width:var(--shell-narrow)}
.sec--flush-t{padding-top:0}
.sec--flush-b{padding-bottom:0}

/* Full-width colour/graphic band. Always clips so decorative blobs inside
   can never widen the page. */
.band{position:relative;overflow:hidden}
.band--deep{background:var(--band-deep)}

/* Escape the shell so one row runs edge to edge. Used to break a run of
   identically-shaped sections — the row stops being another 1200px box.
   html/body carry overflow-x:clip, so the 100vw can never scroll the page. */
.bleed-row{
  width:100vw;max-width:100vw;
  margin-inline:calc(50% - 50vw);
  --gap:0;
}
.band--hair-t{border-top:1px solid var(--border-hair)}
.band--hair-b{border-bottom:1px solid var(--border-hair)}
.band--edge-t{border-top:1px solid var(--border-subtle)}
.band--edge-b{border-bottom:1px solid var(--border-subtle)}

/* The canvas's one grid idiom: repeat(auto-fit,minmax(min(100%,N),1fr)).
   Set --min and --gap with a modifier class, or inline as the escape hatch. */
.autofit{
  display:grid;
  gap:var(--gap,3px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--min,260px)),1fr));
}
.min-160{--min:160px}.min-170{--min:170px}.min-180{--min:180px}
.min-190{--min:190px}.min-200{--min:200px}.min-220{--min:220px}
.min-230{--min:230px}.min-260{--min:260px}.min-300{--min:300px}
.min-320{--min:320px}.min-340{--min:340px}.min-360{--min:360px}
.min-380{--min:380px}.min-400{--min:400px}.min-420{--min:420px}

/* AUTO-FIT ORPHANS — the tablet band.
   auto-fit reflows on available width, never on item count, so through roughly
   600-900px a three-item grid drops to 2+1 and a four-item grid to 3+1: the
   last card sits alone against an empty half-row of ground. That empty
   rectangle is the "dead zone", and it survived three review rounds because
   only 1440 and 390 were ever measured. Eight grids across five pages were
   doing it at 768 (iPad portrait).
   The item count is what should decide the break, so let it: three items hold
   three tracks through the band, four items break 2x2 rather than 3+1. Same
   idiom and the same pinning already used for #paths at § HOME/4 (which forces
   three tracks from 640px up) — this generalises it instead of repeating it per
   page. Grids of 2, 5 and 8 are untouched, and browsers without :has() simply
   keep today's reflow. */
@media (min-width:601px) and (max-width:900px){
  .autofit:has(> :nth-child(3)):not(:has(> :nth-child(4))){
    grid-template-columns:repeat(3,minmax(0,1fr));
  }
  .autofit:has(> :nth-child(4)):not(:has(> :nth-child(5))){
    grid-template-columns:repeat(2,minmax(0,1fr));
  }
}
/* Below the band, the same orphan reappears from the other side: two grids with
   a small --min (hub's three lit frames at 190, the for-coaches step cards at
   230) still fit two tracks at 480-600 and strand the third. Every other
   three-item grid has already stacked by here, so this only extends the phone
   layout those two already use at 390 another hundred pixels up — it does not
   introduce a shape the page does not already have. */
@media (max-width:600px){
  .autofit:has(> :nth-child(3)):not(:has(> :nth-child(4))){
    grid-template-columns:1fr;
  }
}

.gap-hair{--gap:3px}.gap-xs{--gap:12px}.gap-sm{--gap:22px}
.gap-md{--gap:32px}.gap-lg{--gap:48px}.gap-xl{--gap:56px}.gap-2xl{--gap:64px}

/* Named preset: the two-column split used on nearly every section. */
.split{
  display:grid;
  gap:var(--gap,56px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--min,400px)),1fr));
}
/* Swap the two halves at desktop only. Source order stays prose-first so a
   phone (where the grid collapses to one column) still reads copy before the
   capture. Used to break a run of identically-handed splits. */
@media (min-width:901px){
  .split--flip>*:first-child{order:2}
}
.a-start{align-items:start}
.a-center{align-items:center}
.a-end{align-items:end}
.a-stretch{align-items:stretch}

.row{display:flex;flex-wrap:wrap;gap:var(--gap,18px);align-items:center}
.row--tight{--gap:12px}
.row--between{justify-content:space-between}
.row--end{justify-content:flex-end}
.col{display:flex;flex-direction:column;gap:var(--gap,14px)}
/* No bare `.fill` flex utility. The name is already taken by the icon font's
   FILL axis (`.material-symbols-outlined.fill`, above), and a `.fill{flex:1}`
   utility later in the cascade beat `.material-symbols-outlined{flex:none}` at
   equal specificity — every bolt icon in a red CTA became flex-grow:1 and blew
   the button apart at 390px. Nothing used the utility. If a flex-grow helper is
   needed, name it `.grow`, never `.fill`. */

/* Wide content (tickers, tables, chip rails) scrolls inside itself so the
   page body never scrolls sideways on a phone. */
.scroll-x{
  overflow-x:auto;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:thin;
  overscroll-behavior-x:contain;
}
.scroll-x::-webkit-scrollbar{height:6px}
.scroll-x::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:3px}

/* measure */
.measure{max-width:620px}
.measure--xs{max-width:520px}
.measure--sm{max-width:560px}
.measure--md{max-width:720px}
.measure--lg{max-width:840px}
.measure--xl{max-width:900px}

/* spacing scale */
.mt-1{margin-top:12px}.mt-2{margin-top:18px}.mt-3{margin-top:24px}
.mt-4{margin-top:32px}.mt-5{margin-top:44px}.mt-6{margin-top:56px}
.mb-1{margin-bottom:10px}.mb-2{margin-bottom:14px}.mb-3{margin-bottom:20px}
.mb-4{margin-bottom:34px}.mb-5{margin-bottom:44px}
.push{margin-top:auto}

/* --------------------------------------------------------------------------
   5. TYPE
   -------------------------------------------------------------------------- */

/* Mono kicker — the small tracked line above a headline. */
.kicker{
  display:block;
  font-family:var(--font-mono);
  font-size:11px;
  letter-spacing:.3em;
  text-transform:uppercase;
  color:var(--cyan);
  margin-bottom:14px;
}
.kicker--lg{font-size:11.5px;letter-spacing:.32em;margin-bottom:18px}
.kicker--red{color:var(--brand-red-lt)}
.kicker--gold{color:var(--gold)}
/* --violet (#571BC1) is a BORDER/GLOW token: as 10px uppercase text on the
   page ground it measures 2.07:1, under even the 3:1 non-text floor. Every
   other violet text in this build already uses --violet-lt. */
.kicker--violet{color:var(--violet-lt)}
.kicker--green{color:var(--green)}
.kicker--olive{color:var(--olive)}
.kicker--dim{color:var(--fg-2b)}

/* Headline-font eyebrow (coaches + pricing use this instead of the mono one). */
.eyebrow{
  display:block;
  font-family:var(--font-headline);
  font-weight:900;
  font-size:11px;
  letter-spacing:.24em;
  text-transform:uppercase;
  color:var(--cyan);
  margin-bottom:16px;
}
.eyebrow--sm{font-size:10.5px}
.eyebrow--red{color:var(--brand-red-lt)}
.eyebrow--dim{color:var(--fg-4)}
.eyebrow--fg{color:var(--fg-0)}

/* Small mono caption / stamp. */
.meta{
  font-family:var(--font-mono);
  font-size:10px;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--fg-4);
}
.meta--xs{font-size:9.5px;letter-spacing:.18em}
.meta--sm{font-size:10.5px;letter-spacing:.24em}
.meta--md{font-size:10px;letter-spacing:.2em}
.meta--lg{font-size:10.5px;letter-spacing:.18em}
.meta--fg{color:var(--fg-2)}
.meta--dim{color:var(--fg-2b)}
/* A caption sitting ON a photograph, not on the page ground.
   --fg-4 (#5D6A6B) is a page-ground colour: over the lit mat region of a hero
   photo it measures 1.26:1 and the caption dissolves. These captions are the
   whole reason the photos read as real frames from the gym, so they have to
   survive the brightest pixel under them. No background colour can reach 4.5:1
   against a lit mat — even pure white tops out near 3.3:1 — so the halo is
   load-bearing, not decoration. It is the same treatment the two How It Works
   stamps already use, turned up. */
.meta--onphoto{
  color:rgba(255,255,255,.9);
  font-size:10px;
  text-shadow:
    0 1px 3px rgba(0,0,0,.95),
    0 0 12px rgba(0,0,0,.9),
    0 0 26px rgba(0,0,0,.65);
}
.meta--cyan{color:var(--cyan)}
.meta--red{color:var(--brand-red-lt)}
.meta--green{color:var(--green)}
.meta--gold{color:var(--gold)}
.meta--violet{color:var(--violet-lt)}

/* Display headlines — 900 italic, uppercase, tight, clamp-sized. */
.d1,.d2,.d3,.d4,.d-cta{
  font-family:var(--font-headline);
  font-weight:900;
  font-style:italic;
  text-transform:uppercase;
  color:var(--fg-0);
  text-wrap:balance;
}
.d1{font-size:clamp(44px,6vw,92px);line-height:.90;letter-spacing:-.03em}
.d1--xl{font-size:clamp(46px,6.4vw,98px);line-height:.88}
.d1--md{font-size:clamp(40px,5.4vw,80px)}
.d1--sm{font-size:clamp(38px,5vw,72px);line-height:.92}

.d2{font-size:clamp(28px,3.2vw,46px);line-height:1;letter-spacing:-.02em}
.d2--lg{font-size:clamp(30px,3.4vw,50px);line-height:.98}
.d2--xl{font-size:clamp(32px,3.8vw,58px);line-height:.96;letter-spacing:-.025em}
.d2--sm{font-size:clamp(26px,3vw,42px)}
.d2--xs{font-size:clamp(24px,2.8vw,38px);line-height:1.02}
.d2--mini{font-size:clamp(20px,2.2vw,28px);line-height:1.1;letter-spacing:0}

.d-cta{font-size:clamp(32px,4.2vw,62px);line-height:.95;letter-spacing:-.025em}
.d-cta--lg{font-size:clamp(34px,4.4vw,66px)}

.d3{font-size:26px;line-height:1;letter-spacing:.02em}
.d4{font-size:22px;line-height:1;letter-spacing:.12em}
.d5{font-size:16px;line-height:1.1;letter-spacing:.14em}
.d6{font-size:12px;line-height:1.2;letter-spacing:.2em}

/* Accent spans inside a display headline. */
.accent{color:var(--cyan);text-shadow:0 0 34px rgba(0,229,255,.45)}
.accent--sm{text-shadow:0 0 30px rgba(0,229,255,.45)}
.accent--red{color:var(--brand-red);text-shadow:0 0 30px rgba(200,16,46,.5)}

/* Body copy. */
.p{font-size:16px;line-height:1.7;color:var(--fg-2)}
.p+.p{margin-top:14px}
.p--lead{font-size:18px;line-height:1.6;color:var(--fg-1b)}
.p--hero{font-size:18px;line-height:1.6;color:var(--fg-0);font-weight:700}
.p--sub{font-size:16.5px;line-height:1.65;color:var(--fg-2)}
.p--sm{font-size:15px;line-height:1.7;color:var(--fg-2b)}
.p--fine{font-size:14.5px;line-height:1.7;color:var(--fg-2b)}
.p--bright{color:var(--fg-1b)}
.p strong,.p b{color:var(--fg-0);font-weight:800}
.p a{color:var(--cyan);font-weight:700}
.num{font-variant-numeric:tabular-nums}
.nowrap{white-space:nowrap}

/* --------------------------------------------------------------------------
   6. BUTTONS
   -------------------------------------------------------------------------- */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  cursor:pointer;
  border:0;
  border-radius:2px;
  background:none;
  color:inherit;
  font-family:var(--font-headline);
  font-weight:900;
  font-size:13px;
  letter-spacing:.2em;
  text-transform:uppercase;
  text-align:center;
  text-decoration:none;
  padding:18px 30px;
  transition:transform 200ms var(--ease),box-shadow 200ms var(--ease),
             background-color 200ms var(--ease),border-color 200ms var(--ease),
             color 200ms var(--ease);
}
.btn:hover{transform:translateY(-2px)}

.btn--red{background:var(--brand-red);color:#fff;box-shadow:var(--glow-red)}
.btn--red:hover{color:#fff;box-shadow:0 0 44px rgba(200,16,46,.6)}

.btn--ghost{border:1px solid rgba(0,229,255,.5);color:var(--cyan);letter-spacing:.24em}
.btn--ghost:hover{background:rgba(0,229,255,.08);color:var(--cyan);box-shadow:0 0 26px rgba(0,229,255,.2)}

.btn--outline-red{border:1px solid rgba(200,16,46,.6);color:var(--fg-0);letter-spacing:.24em}
.btn--outline-red:hover{background:rgba(200,16,46,.14);color:var(--fg-0)}

.btn--outline{border:1px solid var(--border-strong);color:var(--fg-2)}
.btn--outline:hover{border-color:var(--cyan);color:var(--cyan)}

/* sizes */
.btn--sm{padding:11px 18px;font-size:10.5px;box-shadow:var(--glow-red-sm)}
.btn--md{padding:15px 24px;font-size:11.5px}
.btn--lg{padding:17px 26px;font-size:11.5px;letter-spacing:.24em}
.btn--block{display:flex;width:100%}

.cta-row{display:flex;flex-wrap:wrap;gap:20px;align-items:center;margin-top:30px}
.cta-row--tight{gap:18px;margin-top:32px}
.cta-note{
  font-family:var(--font-mono);
  font-size:10px;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--fg-2b);
}
.cta-note--lg{font-size:10.5px}

/* --------------------------------------------------------------------------
   7. SURFACES — cards, boxes, rails
   -------------------------------------------------------------------------- */
.card{
  position:relative;
  border:1px solid var(--border-subtle);
  background:var(--surface-flat);
}
.card--glass{
  border-color:var(--border-mid);
  background:var(--surface-glass);
  backdrop-filter:blur(20px);
  -webkit-backdrop-filter:blur(20px);
}
.card--red{
  border-color:rgba(200,16,46,.5);
  background:var(--surface-glass-up);
  backdrop-filter:blur(20px);
  -webkit-backdrop-filter:blur(20px);
  box-shadow:0 8px 32px rgba(0,0,0,.37),0 0 40px rgba(200,16,46,.14),inset 0 1px 0 rgba(255,255,255,.03);
}
.card--red-soft{border-color:rgba(200,16,46,.4);background:rgba(31,31,37,.55);backdrop-filter:blur(20px)}
.card--red-tint{border-color:var(--line-red);background:rgba(200,16,46,.05)}
.card--cyan{border-color:var(--line-cyan-soft);background:rgba(0,229,255,.05)}
.card--flat{background:var(--bg)}
.card--plain{background:none}
.card--col{display:flex;flex-direction:column}
.card__topline{position:absolute;left:0;right:0;top:0;height:2px;background:var(--brand-red);box-shadow:0 0 18px rgba(200,16,46,.7)}
.card__body{padding:24px}
.card__body--md{padding:26px}
.card__body--lg{padding:30px}
.card__body--xl{padding:34px}
.card__body--fill{display:flex;flex-direction:column;flex:1}

/* Rule / pull blocks. */
.pull{
  padding:22px 26px;
  border-left:2px solid var(--brand-red);
  background:rgba(200,16,46,.06);
}
.pull p{margin:0;font-size:17px;line-height:1.65;color:var(--fg-1)}
.rule-box{
  padding:18px 22px;
  border-left:2px solid var(--brand-red);
  background:rgba(6,6,14,.6);
}
.rule-box strong{
  font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:20px;letter-spacing:.02em;text-transform:uppercase;color:var(--fg-0);
}
.note-box{
  padding:18px 20px;
  border:1px solid rgba(101,242,181,.28);
  background:rgba(101,242,181,.05);
  display:flex;flex-direction:column;gap:8px;
}
.note-box p{margin:0;font-size:14.5px;line-height:1.6;color:var(--fg-1b)}

/* Divider row: label + fading hairline. */
.rulerow{display:flex;align-items:center;gap:14px}
.rulerow__line{flex:1;height:1px;background:linear-gradient(90deg,var(--border-strong),transparent)}
.rulerow--cyan .rulerow__line{background:linear-gradient(90deg,rgba(0,229,255,.4),transparent)}

/* Chips / discipline pills. */
.chips{display:flex;flex-wrap:wrap;gap:6px}
.chip{
  display:inline-block;
  padding:7px 12px;
  border:1px solid var(--border-mid);
  font-family:var(--font-headline);
  font-weight:900;
  font-size:9.5px;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--fg-2);
}

/* Bullet list (square red tick). Write plain <li>text</li>. */
.blist{display:flex;flex-direction:column;gap:10px}
.blist li{
  display:flex;gap:12px;align-items:flex-start;
  font-size:15px;line-height:1.6;color:var(--fg-2);
}
.blist li::before{
  content:"";width:6px;height:6px;margin-top:8px;flex:none;background:var(--brand-red);
}

/* Check list. Shape: <li><span class="material-symbols-outlined ic-17">check</span><span>text</span></li> */
.checks{display:flex;flex-direction:column;gap:11px}
.checks li{
  display:flex;gap:12px;align-items:flex-start;
  font-size:15px;line-height:1.55;color:var(--fg-1b);
}
.checks li>.material-symbols-outlined{font-size:17px;color:var(--cyan);flex:none;margin-top:1px}
.checks--red li>.material-symbols-outlined{color:var(--brand-red)}
.checks--grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));
  gap:11px 24px;
}
.checks strong{color:var(--fg-0);font-weight:800}

/* --------------------------------------------------------------------------
   8. STAT RAILS
   -------------------------------------------------------------------------- */
.stats{display:grid;gap:28px}
.stats--6{grid-template-columns:repeat(6,minmax(0,1fr))}
.stats--4{grid-template-columns:repeat(auto-fit,minmax(min(100%,160px),1fr));gap:36px}
.stat{display:flex;flex-direction:column;gap:9px;min-width:0}
.stat b{
  font-family:var(--font-headline);
  font-weight:900;font-style:italic;
  font-size:clamp(26px,2.4vw,40px);
  line-height:.9;color:var(--fg-0);
  font-variant-numeric:tabular-nums;
}
.stat span{
  font-family:var(--font-headline);
  font-weight:700;font-size:9px;line-height:1.45;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fg-2b);
  text-wrap:pretty;
}
.stat--lg b{font-size:clamp(30px,2.6vw,40px)}
.stat--lg span{font-size:9.5px;letter-spacing:.22em;margin-top:8px}
.stat b.cy{color:var(--cyan)}
.stat b.rd{color:var(--brand-red)}

/* Two-up boxed figure pair (hub coaching "30 / 1 QTR").
   The boxes are flex:1 siblings, so they stretch to a shared height and share a
   3px seam — which means their two eyebrow labels read as one horizontal line
   and any difference in value height throws that line out of true. Pinning the
   label to the bottom (margin-top:auto) makes the alignment hold no matter how
   tall the value runs, instead of depending on both values being one line. */
.figpair{display:flex;gap:3px}
.figbox{flex:1;padding:16px;border:1px solid var(--border-subtle);display:flex;flex-direction:column}
.figbox--cyan{border-color:rgba(0,229,255,.2);background:rgba(0,229,255,.05)}
.figbox b{
  display:block;font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:30px;color:var(--fg-0);font-variant-numeric:tabular-nums;
  margin-bottom:4px; /* the label's old margin-top, moved onto the value so the
                        label box itself stays flush and margin-top:auto is free
                        to do the bottom-alignment. Renders identically. */
}
.figbox--cyan b{color:var(--cyan)}
/* Non-numeric value. The 30px slot above is a FIGURE slot — italic display weight
   with tabular-nums, sized for "30" or "1 / QTR". A phrase dropped into it wraps
   and reads as a broken headline rather than a figure, so text values step down
   to prose size and normal line-height and keep the box a label/value pair. */
.figbox--text b{
  font-size:19px;line-height:1.3;letter-spacing:-.01em;font-variant-numeric:normal;
}
.figbox span{
  display:block;font-family:var(--font-headline);font-weight:900;font-size:9.5px;
  letter-spacing:.22em;text-transform:uppercase;color:var(--fg-2b);
  margin-top:auto;
}

/* Price block. */
.price{display:flex;align-items:baseline;gap:12px}
.price b{
  font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:64px;line-height:.85;color:var(--fg-0);font-variant-numeric:tabular-nums;
}
.price--sm b{font-size:44px;line-height:.9}
.price span{
  font-family:var(--font-mono);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--fg-2b);
}

/* --------------------------------------------------------------------------
   9. HERO + FULL-BLEED BANDS
   -------------------------------------------------------------------------- */
.hero{
  position:relative;
  display:flex;
  align-items:center;
  overflow:hidden;
  background:var(--bg-deep);
  min-height:var(--hero-h,560px);
}
.hero--bottom{align-items:flex-end}
.hero--tall{--hero-h:680px}
.hero--mid{--hero-h:660px}
.hero--short{--hero-h:520px}
.hero--cta{--hero-h:440px}
.hero--cta-sm{--hero-h:420px}

.hero__media{position:absolute;inset:0}
.hero__media img,.hero__media video{width:100%;height:100%;object-fit:cover}
.hero__media--dim img{opacity:.5;filter:grayscale(.6) contrast(1.1)}
.hero__media--dim-55 img{opacity:.55;filter:grayscale(.5) contrast(1.1)}
.hero__media--soft img{filter:grayscale(.85) contrast(1.08)}
.hero__media--mono img{filter:grayscale(1)}

.hero__inner{
  position:relative;width:100%;max-width:var(--shell);margin:0 auto;
  padding:72px var(--pad-x);
}
.hero__inner--lg{padding:96px var(--pad-x)}
.hero__inner--split{padding:72px var(--pad-x)}
.hero__inner--narrow{max-width:var(--shell-narrow)}

/* Scrims — the exact gradients the canvas paints over hero photography. */
.scrim{position:absolute;inset:0;pointer-events:none}
.scrim--l100{background:linear-gradient(100deg,rgba(6,6,14,.97) 0%,rgba(6,6,14,.86) 46%,rgba(6,6,14,.30) 100%)}
.scrim--l100-35{background:linear-gradient(100deg,rgba(6,6,14,.97) 0%,rgba(6,6,14,.86) 46%,rgba(6,6,14,.35) 100%)}
.scrim--l85{background:linear-gradient(85deg,rgba(6,6,14,.97) 0%,rgba(6,6,14,.84) 46%,rgba(6,6,14,.20) 100%)}
.scrim--l80{background:linear-gradient(80deg,rgba(6,6,14,.97) 0%,rgba(6,6,14,.80) 45%,rgba(6,6,14,.15) 100%)}
.scrim--x{background:linear-gradient(90deg,rgba(6,6,14,.96),rgba(6,6,14,.72) 55%,rgba(6,6,14,.35))}
.scrim--x-hard{background:linear-gradient(90deg,rgba(6,6,14,.97) 0%,rgba(6,6,14,.86) 42%,rgba(6,6,14,.25) 100%)}
.scrim--x-soft{background:linear-gradient(90deg,rgba(6,6,14,.96),rgba(6,6,14,.70) 55%,rgba(6,6,14,.30))}
.scrim--x-wide{background:linear-gradient(90deg,rgba(6,6,14,.95),rgba(6,6,14,.50) 60%,transparent)}
.scrim--btm{background:linear-gradient(180deg,transparent 55%,rgba(6,6,14,.90))}
.scrim--btm-deep{background:linear-gradient(180deg,transparent 55%,rgba(6,6,14,.94))}
.scrim--btm-hard{background:linear-gradient(180deg,transparent 45%,rgba(6,6,14,.92) 100%)}
.scrim--btm-hard-deep{background:linear-gradient(180deg,transparent 45%,rgba(6,6,14,.94))}
.scrim--btm-early{background:linear-gradient(180deg,transparent 40%,rgba(6,6,14,.90))}
.scrim--btm-late{background:linear-gradient(180deg,transparent 60%,rgba(6,6,14,.90))}
/* deeper + earlier than --btm so an 11px caption keeps its ground */
.scrim--btm-card{background:linear-gradient(180deg,transparent 40%,rgba(6,6,14,.96))}
.scrim--vfade{background:linear-gradient(180deg,rgba(10,10,18,.35) 0%,rgba(10,10,18,.9) 70%,var(--bg) 100%)}
.scrim--wash{background:linear-gradient(180deg,rgba(6,6,14,.4),rgba(6,6,14,.35) 40%,rgba(6,6,14,.95))}

/* Decorative blurred blobs. Parent must be .hero/.band (overflow:hidden). */
.blob{position:absolute;border-radius:999px;pointer-events:none;filter:blur(150px)}
.blob--red{background:rgba(200,16,46,.24)}
.blob--red-soft{background:rgba(200,16,46,.16)}
.blob--cyan{background:rgba(0,229,255,.10)}
.blob--tl{left:-120px;top:20px;width:520px;height:520px}
.blob--tl-hi{left:-140px;top:-120px;width:520px;height:520px}
.blob--bl{left:-100px;bottom:-60px;width:460px;height:460px}
.blob--br{right:-80px;bottom:-80px;width:420px;height:420px;filter:blur(140px)}
.blob--br-lo{right:-120px;bottom:-160px;width:460px;height:460px}

/* CRT scanline overlay. */
.scanlines{
  position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(180deg,transparent 0 2px,rgba(0,229,255,.015) 2px 3px);
}
.scanlines--faint{background:repeating-linear-gradient(180deg,transparent 0 2px,rgba(0,229,255,.014) 2px 3px)}

/* Full-bleed photographic strip with content pinned to the bottom.
   min-height (not height) so content can grow it on small screens. */
.coverband{
  position:relative;display:flex;align-items:flex-end;overflow:hidden;
  min-height:var(--h,320px);
}
.coverband--center{align-items:center}
.coverband__media{position:absolute;inset:0}
.coverband__media img{width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.1);transition:filter 500ms var(--ease)}
.coverband:hover .coverband__media img{filter:grayscale(0) contrast(1.05)}
.coverband__media--plain img{filter:grayscale(1)}
.coverband__inner{
  position:relative;width:100%;max-width:var(--shell);margin:0 auto;
  padding:0 var(--pad-x) 26px;
}
.coverband__inner--center{padding:0 var(--pad-x)}
/* Same over-photo caption treatment as .meta--onphoto and .shot__cap: this one
   sits on top of a photograph with no scrim behind it, and the light half of
   the frame (a white gi/t-shirt) ate the dim grey it used to use. */
.coverband__stamp{
  position:absolute;right:var(--pad-x);bottom:12px;
  font-family:var(--font-mono);font-size:9px;letter-spacing:.2em;
  text-transform:uppercase;color:rgba(255,255,255,.9);
  text-shadow:0 1px 3px rgba(0,0,0,.95),0 0 12px rgba(0,0,0,.9),0 0 26px rgba(0,0,0,.65);
}

/* --------------------------------------------------------------------------
   10. IMAGE PLATES (photography)
   Shape: <figure class="shot h-340"><img …><span class="scrim scrim--btm"></span>
          <figcaption class="shot__cap">…</figcaption></figure>
   -------------------------------------------------------------------------- */
.shot{position:relative;overflow:hidden;border:1px solid var(--border-subtle)}
.shot--bare{border:0}
.shot--cyan{border-color:rgba(0,229,255,.3)}
.shot--red{border-color:rgba(200,16,46,.35)}
.shot>img{
  width:100%;
  height:var(--h,auto);
  object-fit:cover;
  filter:grayscale(1);
  transition:filter 600ms var(--ease),transform 700ms var(--ease);
}
.shot--mono-soft>img{filter:grayscale(.2)}
.shot--mono-light>img{filter:grayscale(.15)}
.shot--colour>img{filter:none}
.shot--dimmed>img{filter:grayscale(1) brightness(.4);transition:filter 400ms var(--ease)}
.shot:hover>img{filter:grayscale(0)}
.shot--dimmed:hover>img{filter:grayscale(0) brightness(1)}
.shot--zoom:hover>img{transform:scale(1.03)}
.shot--still:hover>img{filter:grayscale(1)}

/* A portrait-orientation file dropped into a short letterbox keeps only its
   middle third under object-fit:cover — which is the midsection, not the face.
   This pulls the frame up to the head. Same idea as .hiw-crop-high / -face,
   promoted to the shared layer because five figures across three pages need it. */
.shot--face>img{object-position:50% 20%}

/* fixed photo heights, matching the canvas 1:1 */
.h-150{--h:150px}.h-190{--h:190px}.h-200{--h:200px}.h-210{--h:210px}
.h-230{--h:230px}.h-280{--h:280px}.h-300{--h:300px}.h-320{--h:320px}
.h-340{--h:340px}.h-400{--h:400px}.h-420{--h:420px}.h-500{--h:500px}
.h-520{--h:520px}

/* caption pinned into the scrim.
   The caption is the only thing that gives a photograph a specific argument,
   so it has to be readable at 1:1 — 8.5px mono was texture, not text. The
   tracking comes down as the size goes up so the line still fits on one row. */
.shot__cap{
  position:absolute;left:12px;bottom:10px;right:12px;
  font-family:var(--font-mono);font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg-1);
  text-shadow:0 1px 8px rgba(0,0,0,.9);
}
.shot__cap--md{left:16px;bottom:12px;font-size:12px;letter-spacing:.14em}
.shot__cap--lg{
  left:16px;bottom:14px;
  font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:12px;letter-spacing:.2em;color:var(--fg-0);text-shadow:0 1px 6px #000;
}
/* stacked label + sub (Solo / Bag / BOB tiles, flow cards) */
.shot__label{position:absolute;left:16px;bottom:14px;right:16px;pointer-events:none}
.shot__label--sm{left:12px;bottom:10px;right:12px}
.shot__label b{
  display:block;font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:22px;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-0);
}
.shot__label--flat b{font-style:normal;font-size:12px;letter-spacing:.24em;color:var(--cyan)}
.shot__label--cyan b{color:var(--cyan);text-shadow:0 0 26px rgba(0,229,255,.4)}
.shot__label span{
  display:block;margin-top:5px;
  font-family:var(--font-mono);font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-2);
  text-shadow:0 1px 8px rgba(0,0,0,.9);
}
.shot__label--sm span{margin-top:4px;font-size:10px;letter-spacing:.08em}
.shot__tick{
  position:absolute;right:14px;top:12px;
  font-family:var(--font-mono);font-size:9px;letter-spacing:.2em;color:var(--fg-4);
}
.shot__tick--cyan{color:var(--cyan)}
/* the 2px cyan rail down the left edge of a flow card */
.shot--railed::after{
  content:"";position:absolute;left:0;top:0;bottom:0;width:2px;
  background:var(--cyan);box-shadow:0 0 14px var(--cyan);
}
/* overlay block sitting in the bottom scrim (the "earn your counter" card) */
.shot__overlay{position:absolute;left:0;right:0;bottom:0;padding:24px}

/* Film-strip: three frames, the middle one lit and kept. */
.strip{display:grid;gap:3px;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}
.strip__frame{position:relative;overflow:hidden}
.strip__frame--lit{outline:1px solid rgba(0,229,255,.55);outline-offset:-1px;box-shadow:0 0 26px rgba(0,229,255,.22)}
.strip__cap{
  position:absolute;left:8px;bottom:6px;right:8px;
  font-family:var(--font-mono);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--fg-2);
  text-shadow:0 1px 8px rgba(0,0,0,.95);
}
.strip__cap--lit{color:var(--cyan)}
/* The hub's three lit frames live inside one half of a .split, so no viewport
   media query describes their real container: at 1024 that column is 464px and
   --min:190 forced 2+1, orphaning "Between rounds" beside empty ground, while
   at 1440 the same grid is a clean 3. The tablet-band rule above cannot see it
   either — the split has already stacked by then and full width is fine. Drop
   the track floor only while the split is genuinely two columns; below that the
   grid is full-width and 190 is what keeps it from breaking 2+1 on a phone. */
@media (min-width:901px){
  body.p-hub .split .autofit.min-190{--min:140px}
}

/* --------------------------------------------------------------------------
   11. PRODUCT PLATES (hub captures in a browser-chrome frame)
   Shape: <div class="plate"><div class="plate__bar">…</div>
          <div class="plate__shot"><img …></div></div>
   -------------------------------------------------------------------------- */
.plate-wrap{position:relative}
.plate-glow{
  position:absolute;inset:-40px;pointer-events:none;filter:blur(50px);
  background:radial-gradient(circle at 60% 40%,rgba(0,229,255,.18),transparent 65%);
}
.plate-glow--sm{inset:-30px;background:radial-gradient(circle at 40% 30%,rgba(0,229,255,.14),transparent 65%)}

.plate{
  position:relative;
  border:1px solid var(--line-cyan);
  background:var(--surface);
  backdrop-filter:blur(20px);
  -webkit-backdrop-filter:blur(20px);
  box-shadow:var(--shadow-plate);
}
.plate--soft{border-color:var(--line-cyan-soft);box-shadow:var(--shadow-plate-sm)}
.plate--lit{box-shadow:var(--shadow-plate),0 0 40px rgba(0,229,255,.1)}
.plate--violet{border-color:rgba(87,27,193,.35);box-shadow:var(--shadow-plate-sm),0 0 30px rgba(87,27,193,.15)}
.plate--gold{border-color:rgba(255,215,0,.22);box-shadow:var(--shadow-plate-sm)}
.plate--green{border-color:rgba(101,242,181,.22);box-shadow:var(--shadow-plate-sm)}

.plate__bar{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 14px;
  border-bottom:1px solid var(--border-subtle);
  background:var(--surface-bar);
}
.plate__bar--tight{padding:9px 12px}
.plate__bar--left{justify-content:flex-start;gap:8px}
.plate__label{
  font-family:var(--font-mono);font-size:9px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--fg-3);min-width:0;
}
.plate__label--cyan{color:var(--cyan)}
.plate__label--green{color:var(--green)}

/* The capture itself. Never scaled past its natural width — see
   fragments/photo-allocation.md for the per-file cap. */
.plate__shot{position:relative;overflow:hidden;background:rgba(10,10,18,.55)}
.plate__shot picture{display:block}
.plate__shot img{width:auto;max-width:100%;height:auto;display:block;margin-inline:auto}
.plate__shot--pad{padding:14px;display:flex;justify-content:center}
.plate__shot--pad img{width:auto;max-width:100%}

/* One capture in the set is 1080x314 — 3.4:1. Squeezed to a phone or tablet
   column it lands at a third of its natural size and its own 12px UI type
   renders at ~4px, the "grey smear". That one scrolls inside its plate at a
   legible height instead of scaling down, and is marked .plate__shot--wide.

   Nothing else does. Forcing height:300px on every capture below 900px was
   calibrated for that strip, but every other capture in the set is between
   0.8:1 and 1.65:1, so a 300px height made them NARROWER than their own plate:
   five product shots floated at 0.35x-0.50x inside frames up to twice their
   width, with dead gutters inside the border. And it bought almost nothing —
   for a 1.28:1 capture in a 356px phone column, 300px of height is 385px wide
   against 356px fitted, an 8% difference in exchange for a scrollbar.

   So the rule is: a capture fits its column, and never renders past its own
   natural width (rule: never upscale). width:auto + max-width:100% on an <img>
   that carries true width/height attributes gives exactly that at every
   breakpoint, with no per-file numbers in the stylesheet. Where the plate is
   wider than the capture the capture centres rather than stretching.

   The right edge of the one scrolling capture fades: an overlay scrollbar on a
   phone is invisible until touched, and without the fade a cut-off frame reads
   as a broken image rather than as something to swipe. */
@media (max-width:900px){
  /* 300px is the floor that never upscales the 1080x314 strip. */
  .plate__shot--wide{
    overflow-x:auto;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain;
    scroll-snap-type:x proximity;
    scrollbar-width:thin;
    -webkit-mask-image:linear-gradient(90deg,#000 84%,rgba(0,0,0,.18));
    mask-image:linear-gradient(90deg,#000 84%,rgba(0,0,0,.18));
  }
  .plate__shot--wide img{width:auto;max-width:none;height:300px;scroll-snap-align:start}
  .plate__shot--wide::-webkit-scrollbar{height:6px}
  .plate__shot--wide::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:3px}
}

/* --swipe: the same scroller, for the two captures that HAVE no croppable pane.
   Four of the six product captures got a phone crop (see the <picture> blocks in
   index.html and hub.html). Two could not: every horizontal cut through the
   clip-studio card or the technique page's chip rows lands in the middle of a
   control, so a crop would have shipped a bisected UI. Fitted to a 356px column
   they render at 0.40 of source, which is the "grey smear" the note above
   describes, so they get the note's own remedy instead of the smear.

   --cap-w is the file's own natural width, the number already in the <img>
   width attribute. .62 is the render scale: above the 0.6 legibility floor in
   fragments/photo-allocation.md, and low enough that the overflow is one short
   swipe rather than three. Replace this whole treatment the day a real
   phone-viewport capture of either screen exists — that is the actual fix. */
@media (max-width:600px){
  .plate__shot--swipe{
    overflow-x:auto;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain;
    scroll-snap-type:x proximity;
    scrollbar-width:thin;
    -webkit-mask-image:linear-gradient(90deg,#000 84%,rgba(0,0,0,.18));
    mask-image:linear-gradient(90deg,#000 84%,rgba(0,0,0,.18));
  }
  .plate__shot--swipe img{
    width:calc(var(--cap-w) * .62);
    max-width:none;
    margin-inline:0;
    scroll-snap-align:start;
  }
  .plate__shot--swipe::-webkit-scrollbar{height:6px}
  .plate__shot--swipe::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:3px}
}

/* Striped placeholder — only for a slot with no capture yet. */
.plate__shot--empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:12px;height:var(--ph,420px);padding:24px;text-align:center;
  background:repeating-linear-gradient(135deg,rgba(255,255,255,.022) 0 10px,transparent 10px 20px),rgba(10,10,18,.55);
}
.plate__shot--empty b{
  font-family:var(--font-headline);font-weight:900;font-size:12px;line-height:1.5;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fg-1);max-width:420px;
}
.plate__cap{
  display:flex;flex-wrap:wrap;gap:18px;margin-top:12px;
}
/* live dot */
.dot-live{
  width:7px;height:7px;border-radius:999px;flex:none;
  background:var(--cyan);box-shadow:0 0 8px var(--cyan);
  animation:pulseDot 3s ease-in-out infinite;
}
/* floating badge clipped to a plate corner */
.plate__badge{
  position:absolute;right:-14px;bottom:-18px;
  display:flex;align-items:center;gap:10px;
  padding:12px 16px;
  background:rgba(6,6,14,.95);
  border:1px solid rgba(0,229,255,.4);
  box-shadow:0 0 26px rgba(0,229,255,.25);
}
.plate__badge b{
  font-family:var(--font-headline);font-weight:900;font-size:9.5px;
  letter-spacing:.22em;text-transform:uppercase;color:var(--fg-2b);
}
.plate__badge i{
  display:inline-flex;align-items:center;gap:6px;font-style:normal;
  font-family:var(--font-headline);font-weight:900;font-size:11px;
  letter-spacing:.18em;text-transform:uppercase;color:var(--cyan);
}

/* --------------------------------------------------------------------------
   12. PERSON TILE (coach grid)
   -------------------------------------------------------------------------- */
.person{border:1px solid var(--border-subtle);background:var(--surface-flat)}
.person__img{position:relative;overflow:hidden;aspect-ratio:1/1}
.person__img img{width:100%;height:100%;object-fit:cover;filter:grayscale(1);transition:filter 500ms var(--ease)}
.person:hover .person__img img,
.person:focus-within .person__img img{filter:grayscale(0)}
.person__body{padding:14px}
.person__name{
  font-family:var(--font-headline);font-weight:900;font-size:13px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--fg-0);
}
.person__role{font-family:var(--font-body);font-size:12px;line-height:1.45;color:var(--fg-2b);margin-top:4px}

/* --------------------------------------------------------------------------
   13. ACCORDION
   Shape:
   <div class="acc">
     <div class="acc__item">
       <button class="acc__btn" aria-expanded="false" aria-controls="a1">
         <span>Question</span><span class="acc__icon" aria-hidden="true">+</span>
       </button>
       <div class="acc__panel" id="a1"><div class="acc__inner"><p class="p">…</p></div></div>
     </div>
   </div>
   With JS off html has no .js class, every panel stays open.
   -------------------------------------------------------------------------- */
.acc{display:flex;flex-direction:column;gap:3px}
.acc__item{border:1px solid var(--border-subtle);background:var(--surface-flat)}
.acc__item:hover,.acc__item.is-open{border-color:var(--line-cyan)}
.acc__btn{
  display:flex;width:100%;align-items:center;justify-content:space-between;gap:16px;
  padding:20px 24px;cursor:pointer;border:0;background:none;text-align:left;
  font-family:var(--font-headline);font-weight:900;font-size:12.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fg-0);
}
.acc__icon{
  flex:none;font-family:var(--font-mono);font-size:16px;line-height:1;color:var(--brand-red);
  transition:transform 200ms var(--ease);
}
.acc__panel{display:grid;grid-template-rows:1fr;transition:grid-template-rows 320ms var(--ease)}
.acc__inner{overflow:hidden;padding:0 24px 22px}
/* Gated on .js-acc, which ONLY nav.js sets — not on .js, which the inline head
   script sets before nav.js has run. If nav.js ever 404s or throws, every panel
   stays open and readable instead of being permanently collapsed by CSS with no
   script left to open it. */
html.js-acc .acc__item:not(.is-open) .acc__panel{grid-template-rows:0fr}
/* grid-template-rows:0fr zeroes the panel's content box, but the inner's own
   padding-bottom is not clipped by its overflow:hidden — a collapsed row was
   carrying 22px of dead space. */
html.js-acc .acc__item:not(.is-open) .acc__inner{visibility:hidden;padding-bottom:0}
html.js-acc .acc__item.is-open .acc__icon{transform:rotate(45deg)}

/* --------------------------------------------------------------------------
   14. TICKER
   Shape: <div class="ticker"><div class="ticker__run">…items… …same items again…</div></div>
   The run must contain the item set TWICE — the -50% translate depends on it.
   -------------------------------------------------------------------------- */
.ticker{position:relative;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
}
.ticker__run{display:flex;width:max-content;gap:var(--gap,28px);animation:tk var(--tk,44s) linear infinite}
.ticker:hover .ticker__run{animation-play-state:paused}
.ticker__item{
  display:inline-flex;align-items:center;gap:10px;flex:none;
  font-family:var(--font-mono);font-size:10px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--fg-2b);white-space:nowrap;
}
.ticker__item b{color:var(--cyan);font-weight:400}

/* --------------------------------------------------------------------------
   15. CONSTELLATION / ORBIT GRAPHIC
   Shape:
   <div class="orbit">
     <span class="orbit__ring orbit__ring--a"></span> …b …c
     <svg class="orbit__svg" viewBox="0 0 100 100">…</svg>
     <div class="orbit__core">…</div>
     <div class="orbit__node" style="--x:50%;--y:8%">Striking</div> …
   </div>
   -------------------------------------------------------------------------- */
/* The outer ring sits at 96% and the nodes hang off the ring, so the graphic
   needs a little more slack than its column before it starts pressing the
   edge. margin-inline keeps it centred once the split stacks. */
.orbit{position:relative;width:100%;aspect-ratio:1/1;max-width:min(520px,84vw);margin-inline:auto}
.orbit__ring{
  position:absolute;left:50%;top:50%;
  width:var(--size,96%);height:var(--size,96%);
  transform:translate(-50%,-50%);
  border:1px dashed rgba(0,229,255,.16);
  border-radius:999px;
}
.orbit__ring--a{--size:96%;animation:orbit 90s linear infinite}
.orbit__ring--b{--size:66%;border-color:rgba(87,27,193,.3);animation:orbitR 64s linear infinite}
.orbit__ring--c{--size:34%;border-style:solid;border-color:rgba(0,229,255,.22);animation:orbit 40s linear infinite}
.orbit__svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.orbit__svg .glines{stroke:var(--cyan);stroke-width:.35;fill:none;opacity:.4}
.orbit__svg .glines>*{animation:gline 5s ease-in-out infinite}
.orbit__svg .glines>*+*{animation-duration:7s}
.orbit__core{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:16px 20px;background:rgba(6,6,14,.9);
  border:1px solid rgba(0,229,255,.4);box-shadow:0 0 34px rgba(0,229,255,.25);
}
.orbit__core span:last-child{
  font-family:var(--font-headline);font-weight:900;font-size:11px;
  letter-spacing:.26em;text-transform:uppercase;color:var(--fg-0);
}
.orbit__node{
  position:absolute;left:var(--x,50%);top:var(--y,50%);
  transform:translate(-50%,-50%);
  padding:8px 12px;background:rgba(6,6,14,.92);
  border:1px solid var(--border-strong);
  font-family:var(--font-headline);font-weight:900;font-size:9.5px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fg-1);white-space:nowrap;
}

/* --------------------------------------------------------------------------
   16. FORM FIELDS (for-coaches apply block)
   -------------------------------------------------------------------------- */
.form-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));gap:22px}
.field{display:flex;flex-direction:column;gap:9px}
.field--wide{grid-column:1/-1}
.field__label{
  font-family:var(--font-headline);font-weight:900;font-size:9.5px;
  letter-spacing:.24em;text-transform:uppercase;color:var(--fg-2b);
}
.input,.textarea{
  width:100%;padding:14px 16px;
  border:1px solid var(--border-mid);
  border-radius:0;
  background:rgba(10,10,18,.6);
  font-family:var(--font-body);font-size:14.5px;line-height:1.6;color:var(--fg-0);
  transition:border-color 200ms var(--ease);
}
.textarea{resize:vertical;min-height:110px}
.input::placeholder,.textarea::placeholder{color:var(--fg-4)}
/* border-colour alone is a 1px change — too quiet to be the only focus signal,
   and it was out-specifying the global :focus-visible ring on form fields. */
.input:focus,.textarea:focus{border-color:rgba(0,229,255,.5)}
.input:focus-visible,.textarea:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}

/* --------------------------------------------------------------------------
   17. NAV
   Progressive enhancement:
     no JS  -> under 1000px the links wrap onto their own row (always visible)
     JS on  -> html.js turns the wrap into a hamburger + panel
   -------------------------------------------------------------------------- */
.nav{
  position:sticky;top:0;z-index:200;
  background:rgba(10,10,18,.9);
  backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);
  border-bottom:1px solid var(--border-subtle);
}
.nav__in{
  display:flex;align-items:center;justify-content:space-between;gap:24px;
  max-width:var(--shell);margin:0 auto;padding:14px var(--pad-x);
}
.nav__brand{display:flex;align-items:center;gap:12px;flex:none}
.nav__brand:hover{color:inherit}
.nav__logo{height:34px;width:auto;object-fit:contain}
.nav__mark{
  font-family:var(--font-mark);font-size:13px;letter-spacing:.16em;
  color:#fff;white-space:nowrap;
}
.nav__mark b{color:var(--brand-red);font-weight:inherit}
.nav__links{display:flex;align-items:center;min-width:0}
.nav__links-inner{display:flex;align-items:center;gap:28px;flex-wrap:wrap;min-width:0}
.nav__link{
  font-family:var(--font-headline);font-weight:900;font-size:10.5px;
  letter-spacing:.22em;text-transform:uppercase;color:var(--fg-2);
  transition:color 200ms var(--ease);white-space:nowrap;
}
.nav__link:hover{color:var(--cyan)}
.nav__link[aria-current="page"]{color:var(--cyan)}
.nav__login{
  font-family:var(--font-mono);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--fg-3);white-space:nowrap;
}
.nav__login:hover{color:var(--cyan)}
.nav__cta{flex:none}
.nav__toggle{
  display:none;align-items:center;justify-content:center;
  width:44px;height:44px;min-width:44px;min-height:44px;flex:none;cursor:pointer;
  border:1px solid var(--border-mid);background:none;color:var(--fg-1);
  border-radius:2px;
}
.nav__toggle .bars,.nav__toggle .bars::before,.nav__toggle .bars::after{
  display:block;width:18px;height:1.5px;background:currentColor;transition:transform 200ms var(--ease),opacity 200ms var(--ease);
}
.nav__toggle .bars{position:relative}
.nav__toggle .bars::before{content:"";position:absolute;top:-6px}
.nav__toggle .bars::after{content:"";position:absolute;top:6px}
html.js .nav.is-open .nav__toggle .bars{background:transparent}
html.js .nav.is-open .nav__toggle .bars::before{transform:translateY(6px) rotate(45deg)}
html.js .nav.is-open .nav__toggle .bars::after{transform:translateY(-6px) rotate(-45deg)}

/* --------------------------------------------------------------------------
   18. FOOTER
   -------------------------------------------------------------------------- */
.foot{border-top:1px solid var(--border-subtle);background:var(--bg-deep)}
.foot__cols{
  display:grid;gap:40px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr));
  max-width:var(--shell);margin:0 auto;padding:64px var(--pad-x) 40px;
}
.foot__logo{height:44px;width:auto;object-fit:contain;margin-bottom:16px}
.foot__blurb{max-width:280px;font-size:13.5px;line-height:1.6;color:var(--fg-2b)}
.foot__h{
  font-family:var(--font-headline);font-weight:900;font-size:9.5px;
  letter-spacing:.26em;text-transform:uppercase;color:var(--fg-4);
  margin:0 0 14px;
}
.foot__links{display:flex;flex-direction:column;gap:9px}
.foot__links a{font-size:13px;color:var(--fg-2);transition:color 200ms var(--ease)}
.foot__links a:hover{color:var(--cyan)}
.foot__bar{border-top:1px solid var(--border-hair);padding:18px var(--pad-x)}
.foot__mark{font-family:var(--font-mark);font-size:10px;letter-spacing:.3em;color:var(--fg-5)}

/* --------------------------------------------------------------------------
   19. SCROLL REVEAL
   Contract: an element opts in with data-rv="N" (N = 0..6 stagger index).
   CSS never hides anything on its own. nav.js arms ONLY the elements that
   start below the fold, so:
     - JS off / JS failed  -> content is visible, full stop
     - before the observer -> content is visible, full stop
     - armed + off-screen  -> fades up when it scrolls into view
   -------------------------------------------------------------------------- */
[data-rv]{
  transition:opacity 620ms var(--ease) var(--rv-d,0ms),
             transform 620ms var(--ease) var(--rv-d,0ms);
}
[data-rv].rv-armed{opacity:0;transform:translateY(20px)}
[data-rv].rv-armed.rv-in{opacity:1;transform:none}
[data-rv="1"]{--rv-d:90ms}
[data-rv="2"]{--rv-d:180ms}
[data-rv="3"]{--rv-d:270ms}
[data-rv="4"]{--rv-d:360ms}
[data-rv="5"]{--rv-d:450ms}
[data-rv="6"]{--rv-d:540ms}

/* --------------------------------------------------------------------------
   20. RESPONSIVE — 1200 / 1024 / 1000(nav) / 768 / 480
   Nothing may scroll horizontally at 390px.
   -------------------------------------------------------------------------- */
@media (max-width:1200px){
  :root{--pad-x:32px}
  .sec{padding:80px var(--pad-x)}
  .sec--lg{padding:88px var(--pad-x)}
  .stats--6{grid-template-columns:repeat(3,minmax(0,1fr));gap:26px 24px}
  .nav__links-inner{gap:22px}
}

@media (max-width:1024px){
  :root{--pad-x:28px;--anchor-offset:150px}
  .sec{padding:72px var(--pad-x)}
  .sec--lg{padding:76px var(--pad-x)}
  .sec--md{padding:60px var(--pad-x)}
  .hero{--hero-h:auto}
  .hero__inner{padding:80px var(--pad-x) 56px}
  .hero__inner--lg{padding:88px var(--pad-x) 56px}
  .split{--gap:40px}
  .gap-xl,.gap-2xl{--gap:40px}
  .orbit{max-width:min(440px,72vw)}
  .price b{font-size:52px}
}

/* Nav collapse. The desktop row stops fitting at 1069px — between 1001 and
   1069 the links wrapped to a second line and orphaned "Log in", which is
   iPad-Pro-landscape territory. The hamburger now takes over above the wrap
   point rather than 69px below it. nav.js's matchMedia guard is 1070 to match.
   The no-JS branch (links wrap) is the default. */
@media (max-width:1069px){
  /* the header is taller from here down, so anchors need the bigger offset */
  :root{--anchor-offset:150px}
  /* --- no-JS branch: the links simply wrap onto their own row --- */
  .nav__in{flex-wrap:wrap;row-gap:12px}
  .nav__toggle{order:2}
  .nav__cta{order:3}
  .nav__links{
    order:4;width:100%;
    border-top:1px solid var(--border-hair);padding-top:12px;
  }
  .nav__links-inner{width:100%;gap:14px 20px}

  /* --- JS branch: hamburger + collapsible panel --- */
  html.js .nav__toggle{display:inline-flex}
  html.js .nav__links{
    display:grid;grid-template-rows:0fr;
    /* align-items:center from the desktop rule would let the panel escape
       the collapsed row and land on top of the page. Stretch pins it. */
    align-items:stretch;
    border-top:0;padding-top:0;
    transition:grid-template-rows 280ms var(--ease);
  }
  html.js .nav__links-inner{
    min-height:0;overflow:hidden;
    flex-direction:column;flex-wrap:nowrap;align-items:stretch;gap:0;
    border-top:1px solid var(--border-hair);
  }
  html.js .nav__links-inner>*{
    width:100%;padding:15px 2px;border-bottom:1px solid var(--border-hair);
  }
  html.js .nav__links-inner>*:last-child{border-bottom:0}
  html.js .nav.is-open .nav__links{grid-template-rows:1fr}
}

/* Phone header: brand left, hamburger and CTA right, all on one row.
   The CTA used to take a full-width row of its own, which made the sticky bar
   129px — 15% of a phone screen, pinned at every scroll position — and put a
   second identical red BUILD MY PLAN directly above the hero's own. */
@media (max-width:600px){
  .nav__cta{flex:0 0 auto;width:auto}
}

/* That was still 1px short of fitting, and only under a desktop user agent did
   it fit at all: measured under iOS Safari's font metrics the row came to 391px
   inside a 390px viewport, wrapped anyway, and the sticky bar stood at 128px —
   15.1% of the screen at 320, 360 and 390, which is most phones in use. Shaving
   type off the button to win single-digit pixels is not a fix. The wordmark is
   what actually costs the row: ~141px plus its 12px gap, on a bar where the
   bear logo already carries the brand and the full wordmark appears in the hero
   a few hundred pixels below. Dropping it leaves ~150px of slack, so the row
   holds under any font metrics. The brand link keeps its own aria-label, so
   nothing is lost to a screen reader. */
@media (max-width:480px){
  .nav__mark{display:none}
  .nav__brand{gap:0}
}

@media (max-width:768px){
  :root{--pad-x:20px}
  body{font-size:15.5px}
  .sec{padding:56px var(--pad-x)}
  .sec--lg{padding:60px var(--pad-x)}
  .sec--md{padding:48px var(--pad-x)}
  .sec--sm{padding:40px var(--pad-x)}
  .hero__inner{padding:64px var(--pad-x) 44px}
  .hero__inner--lg{padding:68px var(--pad-x) 44px}
  .split,.autofit{--gap:28px}
  .gap-hair{--gap:3px}
  .stats--6{grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 20px}
  /* 2x2, not auto-fit. The hub proof rail's four stats fell to 3+1 anywhere
     from ~480 to ~740 — measured 3/1 with 387px of empty ground at 601 and
     413px at 640 — because auto-fit fits as many 160px tracks as the width
     allows and 160*4 does not make it through that band. Same orphan shape,
     and same answer, as the four-item .autofit rule in § grid. */
  .stats--4{grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 20px}
  /* photo plates shrink rather than crop the layout */
  .shot>img{height:calc(var(--h) * .78)}
  .coverband{min-height:calc(var(--h,320px) * .8)}
  .plate__shot--empty{height:calc(var(--ph,420px) * .72)}
  .figpair{flex-direction:column}
  .orbit{max-width:min(400px,80vw)}
  .orbit__node{font-size:8.5px;letter-spacing:.16em;padding:6px 9px}
  .orbit__core{padding:12px 14px}
  .pull{padding:18px 20px}
  .pull p{font-size:16px}
  .price b{font-size:46px}
  .price--sm b{font-size:38px}
  /* decorative blobs contribute nothing on a phone and can only cause grief */
  .blob{display:none}
  .plate__badge{position:static;margin-top:3px;justify-content:center}
  .coverband__stamp{position:static;display:block;padding:0 var(--pad-x) 12px}
  .btn{padding:16px 24px;font-size:12px;letter-spacing:.18em}
  .btn--lg,.btn--md{padding:15px 22px;font-size:11px}
  .cta-row{gap:14px;margin-top:24px}
  .foot__cols{gap:32px;padding:48px var(--pad-x) 32px}
  /* wide rows must scroll inside themselves, never widen the page */
  .chips{flex-wrap:wrap}
  .ticker__run{--gap:20px}
}

@media (max-width:480px){
  :root{--pad-x:16px}
  .sec{padding:44px var(--pad-x)}
  .sec--lg{padding:48px var(--pad-x)}
  .sec--md{padding:40px var(--pad-x)}
  .hero__inner,.hero__inner--lg{padding:52px var(--pad-x) 36px}
  .shot>img{height:calc(var(--h) * .62)}
  .coverband{min-height:calc(var(--h,320px) * .68)}
  .plate__shot--empty{height:calc(var(--ph,420px) * .6)}
  .stats--6,.stats--4{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 16px}
  .stat b{font-size:28px}
  .d3{font-size:22px}
  .d4{font-size:19px}
  .card__body,.card__body--md,.card__body--lg,.card__body--xl{padding:20px}
  .acc__btn{padding:16px 18px;font-size:11.5px;letter-spacing:.14em}
  .acc__inner{padding:0 18px 18px}
  /* Stack, don't squeeze. At 390 the two mono labels butted together with no
     gap and the second wrapped mid-phrase, breaking the one-line browser-chrome
     illusion the plate depends on. */
  .plate__bar{padding:8px 10px;gap:3px;flex-direction:column;align-items:flex-start}
  .plate__bar--left{flex-direction:row;align-items:center;gap:8px}
  .plate__label{font-size:8px;letter-spacing:.18em}
  /* Content CTAs go full width; the nav button must not. */
  .cta-row>.btn,.card .btn,.btn--block{width:100%}
  .btn{padding:15px 18px}
  /* brand + hamburger + CTA have to survive on one row at 390, or the sticky
     bar grows a whole extra row and eats 15% of the screen */
  /* min-height, not padding: this is the primary conversion control on a phone
     and 12px/12px resolved to a 40px-tall target, under the 44px floor the
     hamburger (44x44) and the panel links (48px) already meet. Horizontal
     padding stays at 12 because the width budget on this row is spent — see
     the 390px note above. Growing it vertically costs the sticky bar 4px. */
  .nav__cta{
    width:auto;padding:12px 12px;font-size:9.5px;letter-spacing:.1em;
    min-height:44px;display:inline-flex;align-items:center;justify-content:center;
  }
  .cta-row .cta-note{width:100%}
  .price b{font-size:40px}
  .form-grid{gap:16px}
  .nav__in{padding:11px var(--pad-x);gap:10px}
  .nav__logo{height:26px}
  /* stays at the 44px tap-target floor — it was 38x34 */
  .nav__toggle{width:44px;height:44px}
  .foot__cols{grid-template-columns:1fr 1fr;gap:26px}
  /* captions wrap and strand orphan words at this width; less tracking, more
     room, one step smaller than the desktop floor but still readable */
  .shot__cap{font-size:10.5px;letter-spacing:.06em;left:10px;right:10px}
  .shot__cap--md{font-size:11px;letter-spacing:.08em}
  .shot__label span,.shot__label--sm span{font-size:10px;letter-spacing:.05em}
}

/* Footer rows were 21px tall against a 44px target. */
@media (max-width:640px){
  .foot__links{gap:0}
  .foot__links a{display:block;padding:11px 0}
}

/* --------------------------------------------------------------------------
   21. REDUCED MOTION
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    transition-delay:0ms !important;
  }
  [data-rv],[data-rv].rv-armed,[data-rv].rv-armed.rv-in{
    opacity:1 !important;
    transform:none !important;
  }
  .orbit__ring,.ticker__run,.dot-live,.orbit__svg .glines>*{animation:none !important}
  .btn:hover,.shot--zoom:hover>img{transform:none !important}
  .ticker{-webkit-mask-image:none;mask-image:none}
  .ticker__run{width:auto;overflow-x:auto}
}

/* --------------------------------------------------------------------------
   22. PRINT (cheap insurance — nothing here is meant to be printed pretty)
   -------------------------------------------------------------------------- */
@media print{
  .nav,.blob,.scanlines,.plate__badge{display:none}
  body{background:#fff;color:#000}
}


/* ==========================================================================
   PAGE LAYER — /  (homepage)   (merged from css/home.css, 2026-08-26)
   ========================================================================== */

/* ==========================================================================
   TRITAC MARTIAL ARTS — /  (homepage)
   Page-specific only. Everything else comes from style-v2.css.
   Every rule is scoped under body.p-home.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1 · HERO
   The canvas capped both hero paragraphs at 580px and spaced them 26 / 12.
   -------------------------------------------------------------------------- */
body.p-home .hero-copy .p--hero,
body.p-home .hero-copy .p--sub{max-width:580px}
body.p-home .hero-copy__lead{margin-top:26px}
body.p-home .hero-copy .p--sub{margin-top:12px}

/* The hub capture is a 1022px-wide crop of hub-home.png. It must never be
   stretched past that (upscaling) and must not be squeezed into a column so
   narrow the UI text turns to mush — see fragments/photo-allocation.md.
   Above 1200px the canvas 1fr/1fr split gives it ~650px (0.64x). Below that
   the hero stacks and the plate takes its own natural width, centred. */
body.p-home .plate-wrap{max-width:768px}

/* --------------------------------------------------------------------------
   2 · STAT RAIL
   -------------------------------------------------------------------------- */
body.p-home .stat-rail{padding-top:38px;padding-bottom:38px}

/* --------------------------------------------------------------------------
   4 · THREE STARTING PATHS
   -------------------------------------------------------------------------- */
body.p-home .path-tag{display:block;letter-spacing:.26em;margin-bottom:10px}
body.p-home .path-tag--olive{color:var(--olive)}
body.p-home .path-p{margin-top:12px;font-size:15px;line-height:1.6;color:var(--fg-2)}
body.p-home .spokes{margin-top:22px;font-size:13.5px;line-height:1.6;color:var(--fg-2b)}

/* The three cards are the homepage's router. They carried hover-zoom and
   hover-desaturate — motion under the cursor — with nothing to click. The
   whole tile is now one hit area, keyed off the card's own heading so the
   accessible name is the path name and no new words are invented. */
body.p-home .path-card{position:relative;transition:border-color 200ms var(--ease)}
body.p-home .path-card .d3{display:flex;align-items:center;gap:12px}
body.p-home .path-card__link{color:inherit}
body.p-home .path-card__link:hover{color:inherit}
body.p-home .path-card__link::after{content:"";position:absolute;inset:0;z-index:2}
body.p-home .path-card__go{
  flex:none;display:inline-flex;color:var(--path-accent,var(--cyan));
  transition:transform 220ms var(--ease);
}
body.p-home .path-card:hover .path-card__go{transform:translateX(5px)}
body.p-home .path-card:hover{border-color:var(--path-accent,var(--cyan))}
body.p-home .path-card:focus-within{border-color:var(--path-accent,var(--cyan))}
body.p-home .path-card--mma{--path-accent:var(--cyan)}
body.p-home .path-card--jj{--path-accent:var(--violet-lt)}
body.p-home .path-card--combatives{--path-accent:var(--olive)}
/* .card--plain has no border of its own to tint, so give the tile one. */
body.p-home .path-card{border:1px solid transparent}

/* Cards fall to 2 columns between 640 and 1023 and orphan COMBATIVES beside
   an empty half-row. Three tracks are forced through that band instead. */
@media (min-width:640px) and (max-width:1023px){
  body.p-home #paths .autofit{grid-template-columns:repeat(3,minmax(0,1fr));--gap:3px}
  body.p-home #paths .path-card .d3{font-size:22px}
  body.p-home #paths .h-280{--h:210px}
  /* a two-line caption on one card must not push its body off the shared top edge */
  body.p-home #paths .path-card{display:flex;flex-direction:column}
  body.p-home #paths .path-card .shot{flex:0 0 auto}
}

/* --------------------------------------------------------------------------
   5 · WHY TRUST IT
   -------------------------------------------------------------------------- */
body.p-home .creds-chips{margin-bottom:26px}
body.p-home .rule-label{letter-spacing:.28em;color:var(--fg-2b)}

/* --------------------------------------------------------------------------
   6 · PRICING TEASER
   -------------------------------------------------------------------------- */
body.p-home .price-cell{padding:26px;gap:16px}
body.p-home .price-cell__label{
  margin-top:8px;
  font-family:var(--font-headline);
  font-weight:900;
  font-size:9.5px;
  letter-spacing:.24em;
  text-transform:uppercase;
  color:var(--fg-2b);
}
body.p-home .price-cell .btn{padding:14px 20px;font-size:10.5px;letter-spacing:.24em}

/* --------------------------------------------------------------------------
   7 · THE WALL
   -------------------------------------------------------------------------- */
body.p-home .review{display:flex;flex-direction:column;gap:14px;padding:22px}
body.p-home .review__stars{font-size:13px;letter-spacing:.18em;color:var(--gold)}
body.p-home .review__q{font-size:14.5px;line-height:1.65;color:var(--fg-1b)}

/* --------------------------------------------------------------------------
   8 · CLOSING CTA
   -------------------------------------------------------------------------- */
body.p-home .cta-head{max-width:800px}

/* --------------------------------------------------------------------------
   RESPONSIVE
   The canvas has no media queries at all; these are the deliberate
   small-screen decisions for this page. Breakpoints follow the shared layer.
   -------------------------------------------------------------------------- */

/* Below the canvas width the two-up hero would squeeze the hub capture under
   ~0.5x of its source and the UI text would turn to mush. Stack instead and
   let the plate sit at its own natural width. */
@media (max-width:1200px){
  body.p-home .hero__inner{grid-template-columns:minmax(0,1fr)}
  body.p-home .plate-wrap{margin-inline:auto}
  body.p-home .hero-copy .p--hero,
  body.p-home .hero-copy .p--sub{max-width:640px}
}

@media (max-width:768px){
  body.p-home .stat-rail{padding-top:30px;padding-bottom:30px}
  body.p-home .creds-chips{margin-bottom:22px}
  body.p-home .price-cell{padding:22px}
  body.p-home .review{padding:20px}
}

/* Eight square coach tiles in one column is ~2,900px of scroll on a phone.
   Two up keeps the roster readable and the section inside a sane height. */
@media (max-width:600px){
  /* pinned, not derived: a 132px auto-fit floor resolved to 3 tracks between
     ~440 and ~560px and left the same 2-item orphan row the desktop grid had */
  body.p-home .coach-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}

/* auto-fit resolved the roster to 6 tracks at 1440 and 5 at 1200–1280, so the
   eight coaches ended in a 2-of-6 orphan row — roughly 894x314px of empty cells
   on the homepage, reading as unfinished. Eight divides by 4 and by 2 and by
   nothing else useful, so the track count is pinned rather than derived: 4 up
   from 601px (two clean rows, 336px portraits at 1440) and 2 up below it. */
@media (min-width:601px){
  body.p-home .coach-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}

@media (max-width:480px){
  body.p-home .hero-copy__lead{margin-top:20px}
  body.p-home .price-cell{padding:20px}
  body.p-home .spokes{font-size:13px}
}


/* ==========================================================================
   PAGE LAYER — /hub   (merged from css/hub.css, 2026-08-26)
   ========================================================================== */

/* ==========================================================================
   TRITAC MARTIAL ARTS — /hub
   Page-specific rules only. Everything structural, typographic and
   chromatic comes from style-v2.css; nothing below redefines a shared class
   or a :root token. Every selector is scoped to body.p-hub.
   ========================================================================== */

/* The two full-bleed photographic bands (proof rail, leaderboard rail) are
   drawn with a hairline above and below in the canvas. .coverband itself
   carries no border, so the rule is added here rather than shadowing it. */
body.p-hub .hub-band-edged{
  border-top:1px solid var(--border-subtle);
  border-bottom:1px solid var(--border-subtle);
}

/* Proof rail. .coverband__inner only pads the bottom, which is right while
   the four figures sit on one line. Once they wrap, they need air above. */
body.p-hub .hub-proof .coverband__inner{padding-top:30px}
/* At phone width the four stat rows stack into 2×2 and land across the roster's
   chests, so the photograph stopped being a photograph of these people and
   became texture behind numbers. The first fix pushed the frame up
   (object-position 50% 18%) — which pushed the roster OUT: at 390 the band is
   captioned "The roster, lined up on the mat" while the top ~55% of it was a
   bare wall and a light fixture, and the eleven coaches were squeezed into a
   ~60px sliver behind the stats with their faces sliced.

   The band was too SHORT for a group shot, not mis-positioned. So: keep the
   roster's eye line in frame (50% 42%) and give the band the room instead.
   min-height is set explicitly because the shared ≤480px rule multiplies --h by
   .68, which would eat most of what --h alone buys. 420px is 0.50 of an 844px
   phone viewport, inside the 0.6-viewport media budget. */
@media (max-width:600px){
  body.p-hub .hub-proof{--h:420px;min-height:420px}
  body.p-hub .hub-proof .coverband__media img{object-position:50% 42%}
  body.p-hub .hub-proof .meta--onphoto{margin-top:6px}
}
/* .stat labels are tuned for flat ground. On this band they sit on a
   photograph whose scrim is only 35% opaque where the four figures land, so a
   bright wall and a white t-shirt read straight through 9.5px of --fg-2b.
   Deepen the scrim here and give the labels the on-photo treatment the
   captions already use. Scoped to this band; .stat elsewhere is unchanged. */
body.p-hub .hub-proof .scrim--vfade{
  background:linear-gradient(180deg,rgba(10,10,18,.55) 0%,rgba(10,10,18,.8) 38%,rgba(10,10,18,.94) 72%,var(--bg) 100%);
}
body.p-hub .hub-proof .stat span{
  color:rgba(255,255,255,.88);
  text-shadow:0 1px 3px rgba(0,0,0,.95),0 0 12px rgba(0,0,0,.9);
}
body.p-hub .hub-proof .stat b{text-shadow:0 1px 4px rgba(0,0,0,.8)}

/* Leaderboard rail. The headline is centred in a 300px strip at desktop
   width; on a phone the strip has to grow around it, so it gets its own
   vertical padding instead of touching the band edges. */
body.p-hub .hub-netband .coverband__inner{padding-top:34px;padding-bottom:34px}
body.p-hub .hub-netband__head{max-width:640px}

/* This band's scrim is a left-to-right wash, and its stamp is pinned bottom
   RIGHT — the weakest corner of the wash, and exactly where the photograph's
   white gi/glove sits. The .meta--onphoto halo cannot rescue 9px white on a
   mid-grey ground (measured 3.2:1 falling to 2.7:1 at 1440), so the words
   "A FULL CLASS WORKING IN PAIRS" simply disappeared from ~769px up.
   The mitigation already existed — brightness on the image — but was scoped
   inside @media(max-width:768px), so only phones got it. Unscoped here at a
   lighter .45 so the frame still reads as a photograph at desktop; the ≤768px
   block below still overrides to .35, where the headline spans the full frame.
   The hover pair is included because the shared .coverband:hover rule drops
   the whole filter, brightness included. */
body.p-hub .hub-netband .coverband__media img,
body.p-hub .hub-netband:hover .coverband__media img{
  /* .45 still left the stamp at 4.37:1, under the 4.5:1 floor. .38 clears it
     and the frame still reads as a photograph rather than a flat panel. */
  filter:grayscale(1) contrast(1.1) brightness(.38);
}

/* The prose + plate that sit directly under that rail. */
body.p-hub .hub-netbody{padding-top:44px;padding-bottom:96px}

/* The canvas's 3px hairline gap, used vertically between the clip-studio
   plate and the photograph beneath it. */
body.p-hub .hub-hair-t{margin-top:3px}

/* The format rule-row label is tracked one step wider than .meta--md. */
body.p-hub .hub-fmt-lab{letter-spacing:.28em}

/* Plate-bar icon tints — the clip studio reads violet, the board reads gold,
   matching their plate borders. Tokens only; no new colours. */
body.p-hub .hub-ic-violet{color:var(--violet-lt)}
body.p-hub .hub-ic-gold{color:var(--gold)}

/* --------------------------------------------------------------------------
   BREAKING THE RUN
   Six consecutive heading + media + two-paragraph sections read as one
   undifferentiated 6,000px scroll. Two things break it, both inside the dark
   palette: the flow tiles run edge to edge (they are the strongest thing on
   the page and were boxed in the same 1200px shell as everything else), and
   .band--deep now steps to a ground you can actually see.
   -------------------------------------------------------------------------- */
/* Five format tiles. See the note in hub.html: the wrapping grid orphaned the
   fifth tile on its own row at phone width. Scroller instead.
   Breakpoint was 600px, which left the whole 601-900 band (iPad portrait, 768)
   still orphaning CLASS onto its own row beside ~548px of empty ground. The
   scroller is the right treatment at EVERY width where five tiles do not fit,
   not only on phones. */
@media (max-width:900px){
  body.p-hub .hub-fmt{
    display:flex;flex-wrap:nowrap;
    overflow-x:auto;-webkit-overflow-scrolling:touch;
    scroll-snap-type:x proximity;
    scrollbar-width:none;
  }
  body.p-hub .hub-fmt::-webkit-scrollbar{display:none}
  body.p-hub .hub-fmt>.shot{flex:0 0 62%;scroll-snap-align:start}
}
body.p-hub .hub-tiles{border-block:1px solid var(--border-subtle)}
body.p-hub .hub-tiles .shot{border:0}
/* At full width three h-400 tiles are 480px each; the sources are 1920 wide,
   so nothing upscales. They get taller to suit the wider frame. */
@media (min-width:1024px){
  body.p-hub .hub-tiles .h-400{--h:460px}
}

/* Each product zone ends in its own action. The label is the site's existing
   CTA text, never a new one. */
body.p-hub .hub-act{margin-top:30px}

/* The leaderboard section's text column is 150px against a 432px plate; the
   282px of empty column is what reads as "weird spacing". */
body.p-hub .hub-netbody .split{align-items:center}

@media(max-width:1024px){
  body.p-hub .hub-netbody{padding-bottom:80px}
}
@media(max-width:768px){
  body.p-hub .hub-netbody{padding-top:34px;padding-bottom:64px}
  body.p-hub .hub-netband .coverband__inner{padding-top:28px;padding-bottom:28px}
  /* One step darker than the unscoped .45 above: once the headline spans the
     whole frame there is more white type over more of the photograph. */
  body.p-hub .hub-netband .coverband__media img{filter:grayscale(1) contrast(1.1) brightness(.35)}
  body.p-hub .hub-netband:hover .coverband__media img{filter:grayscale(1) contrast(1.1) brightness(.35)}
}


/* ==========================================================================
   PAGE LAYER — /how-it-works   (merged from css/hiw.css, 2026-08-26)
   ========================================================================== */

/* ==========================================================================
   TRITAC MARTIAL ARTS — /how-it-works
   Page-specific rules only. Layout, type, colour and motion all come from
   style-v2.css; nothing below redefines a shared class or a :root token.
   Every selector is scoped to body.p-hiw.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1 · HERO
   The canvas hero is 560px and bottom-aligned, which is the .hero default
   height — but it is declared here so the intent is visible, and so the
   sub-line keeps the canvas's 600px measure (between .measure--sm and
   .measure, so it needs its own value).
   -------------------------------------------------------------------------- */
body.p-hiw .hiw-hero{--hero-h:560px}
body.p-hiw .hiw-hero__media img{object-position:70% 40%}
body.p-hiw .hiw-hero__sub{max-width:600px}

/* Both full-bleed stamps sit directly on photography rather than on a card.
   They were missed by the .meta--onphoto pass and kept the old grey treatment:
   --fg-2b at 9px with a single shadow measured ~3.0:1 falling to 1.7:1 over the
   lit regions of the hero frame, i.e. grey-on-grey. Folded into the fixed
   treatment — this is the identical declaration block as .meta--onphoto (§ type
   scale), not a new colour. */
body.p-hiw .hiw-hero__stamp,
body.p-hiw .hiw-cannot__stamp{
  color:rgba(255,255,255,.9);
  text-shadow:
    0 1px 3px rgba(0,0,0,.95),
    0 0 12px rgba(0,0,0,.9),
    0 0 26px rgba(0,0,0,.65);
}

/* --------------------------------------------------------------------------
   2 · THE PERSON, NOT A STYLE
   Three photographs stacked on the canvas's signature 3px hairline gap.
   -------------------------------------------------------------------------- */
body.p-hiw .hiw-stack{--gap:3px}

/* Two of the three are portrait files landing in a 200px letterbox. A
   centred crop lands on a midsection; these pull the frame up to the part
   of the photograph the caption is about. */
body.p-hiw .hiw-crop-high>img{object-position:50% 22%}
body.p-hiw .hiw-crop-face>img{object-position:50% 30%}

/* --------------------------------------------------------------------------
   3 · THE METHOD IS CONNECTION
   A single centred cyan bloom sits behind the constellation. .blob only
   offers corner positions, so this one decoration is drawn here. It lives
   inside .band (which clips) and, like .blob, it is dropped on a phone
   where it contributes nothing and only costs paint.
   -------------------------------------------------------------------------- */
body.p-hiw .hiw-bloom{
  position:absolute;
  left:50%;
  top:-10%;
  width:700px;
  height:700px;
  transform:translateX(-50%);
  border-radius:999px;
  pointer-events:none;
  background:radial-gradient(circle,rgba(0,229,255,.1),transparent 65%);
  filter:blur(80px);
}

/* The technique capture and the "earn your counter" photograph sit in one
   3px-gapped row. The capture is 880px square-ish at source and must never
   render past that width (upscaling) — see photo-allocation.md, P7 — so it
   is the taller of the two, and it decides the row height. The photograph
   beside it stretches to finish level instead of leaving a hole. */
/* Scoped to >=601 on purpose: below that the plate is .plate__shot--swipe and
   this rule, being page-specific, would out-specify it and clamp the capture
   back to the column width — the 0.40x smear it exists to prevent. */
@media (min-width:601px){
  body.p-hiw .hiw-technique .plate__shot img{max-width:min(100%,880px);margin-inline:auto}
}

/* At desktop width an even 1fr/1fr split would render the capture at 676px
   and stand a 690px block on the page. 560px is still 0.64x of source —
   comfortably above the 0.6 legibility floor — and 110px shorter. The
   photograph then stretches to finish level with it. */
@media (min-width:1025px){
  body.p-hiw .hiw-pair{grid-template-columns:minmax(0,1fr) minmax(0,560px)}
  body.p-hiw .hiw-earn>img{height:100%;min-height:var(--h)}
}

/* Below that, two columns would squeeze the capture to 0.55x of source and
   the UI text turns to mush — the exact failure photo-allocation.md warns
   about. Stack instead. The plate is then capped at 640px — 0.73x of source,
   still crisp, and it stops a nearly square capture from standing 850px tall
   on a tablet. */
@media (max-width:1024px){
  body.p-hiw .hiw-pair{grid-template-columns:minmax(0,1fr)}
  body.p-hiw .hiw-technique{width:100%;max-width:640px;margin-inline:auto}
}

/* --------------------------------------------------------------------------
   4 · WHAT ONLINE TRAINING LOOKS LIKE
   The section head is a headline with a tracked mono note sitting on its
   baseline, not centred against it.
   -------------------------------------------------------------------------- */
body.p-hiw .hiw-sechead{align-items:baseline}
body.p-hiw .hiw-sechead .kicker{margin-bottom:0}

/* SOLO / DRILLED / LIVE is a set of three and only reads as one: auto-fit
   dropped it to two tracks below 1024 and stranded LIVE beside ~383px of dead
   space. Three tracks are forced through that band, the same remedy the home
   page's three path cards already use. */
@media (min-width:620px) and (max-width:1024px){
  body.p-hiw #online>.autofit{grid-template-columns:repeat(3,minmax(0,1fr))}
  body.p-hiw #online>.autofit .h-320{--h:250px}
}

/* The log capture is a 920x1162 2.5x render (re-shot 2026-08-26). Capped at
   420px so the plate stays inside the ~0.6vh media budget — 420x530 rather
   than the 610x770 the column would otherwise give it. That is 0.46 of the
   file's natural width, which looks like it breaks the 0.6 floor in
   photo-allocation.md P8 but does not: the floor was written for 1x captures,
   and 0.46 of a 2.5x render is still 1.15x the source UI. Verified legible
   down to 342px. Never scaled ABOVE 920px. */
body.p-hiw .hiw-log .plate__shot--pad{min-height:240px;align-items:center}
/* min(), not a bare 420px: .plate__shot is overflow:hidden with no scroller, so
   a flat cap wider than the column silently CLIPS instead of shrinking. At a
   390px viewport the column is 356px and a bare 420px cap ate 46px of the
   panel's right edge. */
body.p-hiw .hiw-log .plate__shot--pad img{max-width:min(420px,100%)}

/* --------------------------------------------------------------------------
   5 · WHAT ONLINE TRAINING CANNOT DO
   Full-bleed, un-desaturated: the whole point of the section is that the
   contact in the photograph is real.
   -------------------------------------------------------------------------- */
body.p-hiw .hiw-cannot{border-top:1px solid var(--border-hair)}
body.p-hiw .hiw-cannot__media img{object-position:60% 50%}
body.p-hiw .hiw-cannot__stamp{margin-top:34px}

/* --------------------------------------------------------------------------
   6 · USE IT WITH YOUR GYM, OR TRAIN IN CROMWELL
   Both cards are photo-on-top, prose beneath (.card--col), and the two must
   finish level however unevenly the prose falls.
   -------------------------------------------------------------------------- */
body.p-hiw .hiw-door .card__body{flex:1}

/* The Cromwell card's whole argument is that the room is named. A centred
   crop of this portrait file cuts the wall banner off; this keeps it in. */
body.p-hiw .hiw-crop-banner>img{object-position:50% 18%}

/* --------------------------------------------------------------------------
   RESPONSIVE
   The canvas has no media queries. These are the deliberate decisions for
   this page; everything else steps with the shared layer.
   -------------------------------------------------------------------------- */

/* The constellation and the prose beside it both want room. Below 1024 the
   shared .split has already stacked them; the bloom is then sitting behind
   a column of text rather than behind the graphic, so pull it in. */
@media (max-width:1024px){
  body.p-hiw .hiw-bloom{width:520px;height:520px;top:-6%}
}

@media (max-width:768px){
  /* Same reasoning as .blob in the shared layer. */
  body.p-hiw .hiw-bloom{display:none}
  /* Stacked, the head reads better as two lines than as a squeezed row. */
  body.p-hiw .hiw-sechead{align-items:flex-start;gap:12px}
  body.p-hiw .hiw-cannot__stamp{margin-top:26px}
  body.p-hiw .hiw-log .plate__shot--pad{min-height:0}
}

@media (max-width:480px){
  body.p-hiw .hiw-cannot__stamp{margin-top:22px}
}


/* ==========================================================================
   PAGE LAYER — /pricing   (merged from css/pricing.css, 2026-08-26)
   ========================================================================== */

/* ==========================================================================
   TRITAC MARTIAL ARTS — /pricing
   Page-specific only. Everything else comes from style-v2.css.
   Every rule is scoped under body.p-pricing.

   The canvas pricing page carries no photography at all — gradient blobs,
   scanlines and type only. photo-allocation.md preserves that (0 slots), so
   there is nothing here about images.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1 · HERO
   Canvas: max-width 1180, padding 84px 42px 64px. .sec--narrow gives the
   1180 shell and --pad-x gives the 42; only the vertical rhythm differs.
   -------------------------------------------------------------------------- */
body.p-pricing .pricing-hero{padding-top:84px;padding-bottom:64px}
body.p-pricing .pricing-hero__kicker{margin-bottom:20px}
body.p-pricing .pricing-hero__sub{max-width:600px;margin-top:24px}

/* --------------------------------------------------------------------------
   2 · THE TWO PLAN CARDS
   The price block is the loudest thing on each card by design: .price paints
   $0 / $49 at 900-italic 64px directly under the plan label, above every
   line of body copy. Nothing below it competes for size.
   -------------------------------------------------------------------------- */

/* The canvas card is itself the flex column, so its 34px padding and the
   column live on one box. Here .card--col is the box and .card__body--xl
   carries the 34; --fill makes the body the column and lets it fill a
   stretched card when the two end up at different natural heights. */

/* Plan label. .eyebrow ships cyan at 16px bottom margin; the canvas paints
   the free card's label --fg-2b and the Kickstart's white (.eyebrow--fg),
   both at 18px. */
body.p-pricing .plan__label{color:var(--fg-2b);margin-bottom:18px}
body.p-pricing .plan__label.eyebrow--fg{color:var(--fg-0)}

/* Lede under the price. */
body.p-pricing .plan__lede{margin-top:22px;line-height:1.65}

/* "Includes" divider label. */
body.p-pricing .plan__includes{margin:28px 0 14px}

/* The free card's exclusion line. */
body.p-pricing .plan__fine{
  margin-top:26px;
  font-size:14px;
  line-height:1.6;
  color:var(--fg-2b);
}

/* Guarantee box + its second, dimmer line. */
body.p-pricing .plan__note{margin-top:28px}
body.p-pricing .plan__note .plan__note-dim{color:var(--fg-2)}

/* Card CTAs. Canvas spacing: 28px under the free card's fine print,
   24px under the Kickstart guarantee box. */
/* The grid stretches both cards but the free card's content is shorter, so it
   used to bottom out 145px above its neighbour. margin-top:auto pushes the
   button to the floor.

   The canvas gap belongs to the elements ABOVE the button, not inside it. It
   used to be padding-top on .plan__cta, which draws inside the button's own
   border and fill: the red "Start Kickstart · $49" button ended up welded to
   the guarantee box with a literal 0px gap at every width (and 24px taller
   than designed), and at ≤600px the free card's ghost-button border landed
   flush under the last line of the fine print. Both are the money moment.
   Same spacing, moved onto the preceding elements so margin-top:auto keeps
   doing the flex push.

   Do NOT re-add padding-top here, not even 0: .btn's own padding is the
   button's internal breathing room (17px 26px), and any padding-top on
   .plan__cta overrides it — 0 collapses the label onto the top border and
   loses 17px of button height. The gap above the button is margin on the
   element above it, full stop. */
body.p-pricing .plan__cta{margin-top:auto}
body.p-pricing .plan__fine{margin-bottom:28px}
body.p-pricing .plan__note{margin-bottom:24px}

/* The one link out of the buy card. Quiet — it sits under the button, not
   beside it — but present at the point of decision instead of only in the
   footer. margin-top:0 keeps .plan__cta's auto push doing the work. */
body.p-pricing .plan__terms{
  margin:12px 0 0;text-align:center;
  font-family:var(--font-mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;
}
body.p-pricing .plan__terms a{color:var(--fg-2);text-decoration:underline;text-underline-offset:3px}
body.p-pricing .plan__terms a:hover{color:#fff}

/* --------------------------------------------------------------------------
   THE QUESTIONS
   Eight answers already existed on this page — inside the FAQPage JSON-LD,
   where Google can read them and a visitor cannot. Two of them (the refund and
   the age rule) are the exact things a buyer comes here to check. Same words,
   moved from an invisible position to a visible one, on the accordion the
   shared layer already ships. #guarantee is the anchor the refund answer needs.
   -------------------------------------------------------------------------- */
/* 820px keeps a question on one line and an answer at a readable measure, but
   left-aligned inside a 1180px section under 1096px-wide plan cards it left a
   276px column of nothing running the full height of the block. Centred, the
   narrower measure reads as deliberate. */
body.p-pricing .faq{max-width:820px;margin-inline:auto}
body.p-pricing .faq .acc__btn{text-transform:none;letter-spacing:.02em;font-size:15px}
body.p-pricing .faq .acc__inner .p{font-size:15px}
body.p-pricing .faq-head{margin-bottom:26px}

/* The page where the money decision happens carried no proof at all. */
body.p-pricing .pricing-proof .review{display:flex;flex-direction:column;gap:14px;padding:22px}
body.p-pricing .pricing-proof .review__stars{font-size:13px;letter-spacing:.18em;color:var(--gold)}
body.p-pricing .pricing-proof .review__q{font-size:14.5px;line-height:1.65;color:var(--fg-1b)}

/* --------------------------------------------------------------------------
   3 · COACHING / CAMPS / SCHOOLS POINTER
   -------------------------------------------------------------------------- */
body.p-pricing .pricing-cta{padding:32px 34px}

/* The fit line sits under the plan grid, not inside a card: it is a quiet
   answer to "will this suit me", and boxing it would make it a third claim
   competing with two prices. */
body.p-pricing .plan-fit{margin:26px auto 0;text-align:center;color:var(--fg-2)}
body.p-pricing .pricing-cta__p{margin-top:16px;font-size:15.5px}

/* Canvas button: 16px 26px, 11px, .24em, never wrapping. */
body.p-pricing .pricing-cta__btn{
  padding:16px 26px;
  font-size:11px;
  white-space:nowrap;
}

/* Below the auto-fit break the two halves stack, and a right-aligned button
   under left-aligned copy reads as a mistake — so it returns to the left.
   The break is derived, not guessed: the grid needs 2x300 + a 28px gap
   (--gap drops to 28 at <=1024) = 628px of card interior; the card eats
   2x34 of padding and the shell eats 2x20 of --pad-x at <=768, so the two
   columns survive down to a 728px viewport and stack at 727. */
@media (max-width:727px){
  body.p-pricing .pricing-cta__act{justify-content:flex-start}
}

@media (max-width:600px){
  body.p-pricing .pricing-cta{padding:24px 22px}
}

@media (max-width:480px){
  body.p-pricing .pricing-cta{padding:20px 18px}
  /* .card .btn goes full width at this breakpoint; let it. */
  body.p-pricing .pricing-cta__btn{justify-content:center}
}

/* --------------------------------------------------------------------------
   4 · THE GYM LINE
   Canvas: padding 26px 42px 88px.
   -------------------------------------------------------------------------- */
body.p-pricing .pricing-gym{padding-top:26px}

/* --------------------------------------------------------------------------
   5 · SMALL SCREENS
   -------------------------------------------------------------------------- */
@media (max-width:1024px){
  body.p-pricing .pricing-hero{padding-top:72px;padding-bottom:52px}
}

@media (max-width:768px){
  body.p-pricing .pricing-hero{padding-top:60px;padding-bottom:44px}
  body.p-pricing .pricing-gym{padding-top:22px}
}

@media (max-width:480px){
  body.p-pricing .pricing-hero{padding-top:48px;padding-bottom:36px}
  body.p-pricing .plan__includes{margin:24px 0 12px}
  body.p-pricing .plan__note{margin-top:24px}
}


/* ==========================================================================
   PAGE LAYER — /for-coaches   (merged from css/coaches.css, 2026-08-26)
   ========================================================================== */

/* ==========================================================================
   /for-coaches — page-scoped rules only.
   Everything here is under body.p-coaches. Nothing in the shared layer is
   redefined, no :root tokens are declared, no new colours are introduced.
   ========================================================================== */

/* --- 1 · HERO ------------------------------------------------------------ */

/* The canvas hero is 96px of top padding and only 44px at the bottom, with the
   block bottom-aligned against the photograph. */
body.p-coaches .co-hero .hero__inner{ padding-top: 96px; padding-bottom: 44px; }

/* The class-demo frame is composed right-of-centre; the canvas pulls it left
   so the standing group sits clear of the headline column. */
body.p-coaches .co-hero .hero__media img{ object-position: 65% 40%; }

/* Canvas hero paragraph is 17px, one step down from the shared 18px lead. */
body.p-coaches .co-hero .p--lead{ font-size: 17px; }

/* The stamp is left-aligned at EVERY width, not only on a phone.
   `.row--end` parked it in the 0.20-opacity tail of .scrim--l85, directly over
   the bright mat of a grayscale(.85) contrast(1.08) frame: 2.17:1 measured, the
   worst contrast on the site and under the 3:1 large-text floor — the caption
   was unreadable from "TRAINING" rightward. The left edge of the same scrim is
   rgba(6,6,14,.97) and carries it cleanly, which is why the phone rule already
   read flex-start; it was scoped one breakpoint too narrow. Every other
   .meta--onphoto on the site measures 5.2-11.5:1. */
body.p-coaches .co-hero .co-stamp{ justify-content: flex-start; }

@media (max-width: 768px){
  body.p-coaches .co-hero .hero__inner{ padding-top: 64px; padding-bottom: 34px; }
}

/* --- 2 · THE TWO CONVERSATION CARDS -------------------------------------- */

/* Canvas h2 measure on this section is 780px — between .measure--md and --lg. */
body.p-coaches .co-w780{ max-width: 780px; }

/* The overlay word sitting in the bottom scrim of each card photo.
   16px here, not the 22px of .shot__label — this is a card tag, not a tile
   label, so it gets its own name rather than shadowing a shared class. */
body.p-coaches .co-tag{
  position: absolute;
  left: 18px;
  bottom: 14px;
  right: 18px;
  font-family: var(--font-headline);
  font-weight: 900;
  font-style: italic;
  font-size: 16px;
  line-height: 1.1;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-0);
  text-shadow: 0 1px 6px #000;
  pointer-events: none;
}
body.p-coaches .co-tag--cyan{ color: var(--cyan); }

/* School Partner card carries the canvas's lifted plate shadow on top of
   the shared red-soft surface. */
body.p-coaches .co-card-partner{
  box-shadow: 0 8px 32px rgba(0, 0, 0, .37), 0 0 40px rgba(200, 16, 46, .1);
}

@media (max-width: 480px){
  body.p-coaches .co-tag{ left: 14px; right: 14px; font-size: 14px; }
}

/* --- 3 · THE THREE STEPS ------------------------------------------------- */

/* Canvas step copy is 15/1.65; the shared .p colour (--fg-2) is already right. */
body.p-coaches .co-step .p{ font-size: 15px; line-height: 1.65; }

/* --- 4 · WHO YOU WOULD BE WORKING WITH ----------------------------------- */

body.p-coaches .co-matt{ margin-top: 72px; }

@media (max-width: 768px){
  body.p-coaches .co-matt{ margin-top: 48px; }
}

/* --- 5 · APPLY ----------------------------------------------------------- */

/* Canvas closes the page on 72px / 96px rather than the shared 88px pair. */
body.p-coaches .co-apply{ padding-top: 72px; padding-bottom: 96px; }

/* The form is a grid; .card__body--xl would double the padding, so the
   padding lives on the form itself. */
body.p-coaches .co-form{ padding: 34px; }

body.p-coaches .co-form .co-submit-row{
  grid-column: 1 / -1;
  margin-top: 0;
}

@media (max-width: 600px){
  body.p-coaches .co-form{ padding: 24px; }
}
@media (max-width: 480px){
  /* .cta-row already blocks its buttons at this width; the submit button
     lives in a .cta-row so it inherits that. Nothing extra needed. */
  body.p-coaches .co-apply{ padding-bottom: 72px; }
}


/* ==========================================================================
   PAGE LAYER — EDITORIAL PAGES
   /about /contact /privacy /terms and the three SEO spokes.

   These eight pages existed in the previous staged build and are linked 43
   times from the nav and footer of the five design-port pages, so they are
   carried forward here. Their copy is Matt's, unchanged and moved verbatim;
   only the class vocabulary is re-expressed in this build's system. Nothing
   below introduces a colour or a token — it is the shared layer, arranged.
   ========================================================================== */

/* Running prose: the plain-English legal pages and the SEO article bodies. */
.prose{max-width:70ch}
.prose p{font-size:16px;line-height:1.75;color:var(--fg-2)}
.prose p+p{margin-top:18px}
.prose strong{color:var(--fg-0);font-weight:800}
.prose a{color:var(--cyan);font-weight:700}
.prose h3{
  font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:clamp(20px,2.2vw,26px);line-height:1.05;letter-spacing:-.01em;
  text-transform:uppercase;color:var(--fg-0);
  margin:40px 0 14px;
}
.prose h3:first-child{margin-top:0}

/* A short mono "→" tail link. The words are always existing page copy. */
.golink{
  display:inline-flex;align-items:center;gap:8px;margin-top:16px;
  font-family:var(--font-headline);font-weight:900;font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--cyan);
}
.golink:hover{color:var(--cyan-soft)}
.golink .material-symbols-outlined{transition:transform 200ms var(--ease)}
.golink:hover .material-symbols-outlined{transform:translateX(4px)}

/* Google-review quote block (SEO spokes). Same shape as the homepage wall. */
.rq{display:flex;flex-direction:column;gap:14px;padding:22px}
.rq__stars{font-size:13px;letter-spacing:.18em;color:var(--gold)}
.rq p{font-size:15px;line-height:1.7;color:var(--fg-1b)}
.rq__who{
  font-family:var(--font-mono);font-size:9.5px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--fg-4);margin-top:auto;
}

/* Dated log rows (the About timeline). */
.tline{display:flex;flex-direction:column;gap:0}
.tline__row{
  display:flex;gap:24px;align-items:baseline;
  padding:16px 0;border-bottom:1px solid var(--border-hair);
}
.tline__row:last-child{border-bottom:0}
.tline__d{
  flex:none;min-width:74px;
  font-family:var(--font-headline);font-weight:900;font-style:italic;
  font-size:18px;letter-spacing:.04em;color:var(--brand-red);
  font-variant-numeric:tabular-nums;
}
.tline__row:last-child .tline__d{color:var(--cyan)}
.tline__row p{font-size:15.5px;line-height:1.6;color:var(--fg-2)}

/* The TRITAC acronym line on /about — headline face, but set as a readable
   sentence rather than a display headline. */
.namesake{
  font-family:var(--font-headline);font-weight:700;
  font-size:clamp(15px,2.1vw,21px);letter-spacing:.03em;line-height:1.55;
  color:var(--fg-1);
}

@media (max-width:768px){
  .prose h3{margin:32px 0 12px}
  .tline__row{gap:16px}
  .tline__d{min-width:58px;font-size:16px}
}

/* ── /invite hero headline ───────────────────────────────────────────────────
   d1--xl is clamp(46px,6.4vw,98px) — a coefficient calibrated on index and hub,
   whose heroes carry a shorter h1 above a shorter lede. /invite adds the
   build-log strip above the hero (~68px) and its headline is the longest of the
   three, and at 1280x720 the two compounded: 6.4vw = 81.9px against a 570px
   split column, so BOTH halves wrapped —

       Stop / watching. / Start / training.

   four lines instead of two, which put the hero CTA at top:713 in a 720px
   viewport (7px of the button visible, "Free path: no credit card…" entirely
   below the fold) while index sat at 589 and hub at 575. Scoped to p-invite so
   index and hub keep the type scale they were signed off on; the cap is set
   where the longest line ("Stop watching.") still fits the split column, so the
   headline holds its two authored lines and the CTA comes back above the fold.
   Below 901px the split collapses to one full-width column and the base scale
   is correct again, so the override stops there. Re-check by measuring
   .hero .btn--red bottom against innerHeight at 1280x720 and 1440x800. */
@media (min-width:901px){
  body.p-invite .hero h1.d1--xl{font-size:clamp(56px,5.2vw,72px)}
}
