/* ════════════════════════════════════════════════════════════════════
   JSTFitness.com — one stylesheet for the whole marketing site
   ════════════════════════════════════════════════════════════════════
   The colours below are NOT new. They are the app's Classic palette,
   copied from src/theme/palettes.js (CLASSIC_DARK_NEUTRAL, LIGHT_NEUTRAL
   and accentVars). Those values have already been through the WCAG
   contrast maths in src/theme/palettes.test.js — retyping approximations
   here would throw that away. If the app's Classic palette ever changes,
   change these with it.

   Dark is the default because the app opens on Classic dark; the light
   block honours a visitor whose OS asks for light, using the app's own
   measured light bag rather than a naive inversion.
   ════════════════════════════════════════════════════════════════════ */

/* ── Inter, self-hosted ──────────────────────────────────────────────
   The same five WOFF2 files the app ships in public/fonts (from the
   @fontsource/inter npm package, SIL OFL 1.1). NOT Google Fonts — see
   the comment in tools/build-site.mjs for why that matters here more
   than it does on most sites. font-display: swap so the headline paints
   immediately in the fallback face. */
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/inter-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("fonts/inter-latin-600-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap; src: url("fonts/inter-latin-700-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 800; font-display: swap; src: url("fonts/inter-latin-800-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 900; font-display: swap; src: url("fonts/inter-latin-900-normal.woff2") format("woff2"); }

:root {
  color-scheme: dark light;

  --bg:        #000000;
  --card:      #0A0A0A;
  --surface:   #111111;
  --border:    #1A1A1A;
  --text:      #FFFFFF;
  --text-mid:  #CCCCCC;
  --text-dim:  #888888;
  --text-faint:#555555;

  --accent:          #00D4D4;
  --accent-hover:    #5CE8E8;
  --accent-contrast: #0A0A0A;
  --accent-grad-top: #00D4D4;
  --accent-grad-bot: #00A8A8;
  --accent-glow:     rgba(0, 212, 212, 0.30);
  --accent-soft:     rgba(0, 212, 212, 0.15);

  --green: #00C853;
  --amber: #FFB300;
  --red:   #FF6B6B;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg:        #F5F5F5;
    --card:      #FFFFFF;
    --surface:   #EFEFEF;
    --border:    #E0E0E0;
    --text:      #111111;
    --text-mid:  #444444;
    --text-dim:  #6A6A6A;
    --text-faint:#8A8A8A;

    /* The app's Classic LIGHT accent. Darker than the dark-mode cyan
       because #00D4D4 as text on a white card measures ~1.7:1 — the
       light bag exists precisely so accent text stays readable. */
    --accent:          #007D7D;
    --accent-hover:    #005C5C;
    --accent-contrast: #FFFFFF;
    --accent-grad-top: #007D7D;
    --accent-grad-bot: #005E5E;
    --accent-glow:     rgba(0, 125, 125, 0.25);
    --accent-soft:     rgba(0, 125, 125, 0.12);

    --green: #007B33;
    --amber: #8A6100;
    --red:   #C62828;
  }
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* Focus must stay visible. The app's accessibility statement promises
   "focus is always visible", and a marketing site that breaks that
   promise on the way to the policy page is a poor advertisement. */
a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

h1, h2 { text-wrap: balance; margin: 0; }
p { text-wrap: pretty; margin: 0; }

.num { font-variant-numeric: tabular-nums; }

.eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

/* ── The holding page ────────────────────────────────────────────── */

.holding {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  min-height: 100svh;
  padding: 48px 24px 32px;
  gap: 48px;
}

.holding__spacer { flex: 0 0 1px; }

.holding__middle {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  max-width: 620px;
  text-align: center;
}

.mark {
  width: 76px;
  height: 76px;
  border-radius: 18px;
  display: block;
}

.wordmark {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.wordmark__type {
  font-size: clamp(30px, 8vw, 46px);
  font-weight: 900;
  letter-spacing: -0.035em;
  line-height: 1;
}

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

.wordmark__rule {
  width: 40px;
  height: 2px;
  background: var(--accent);
}

.lede {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.lede__line { font-size: 17px; color: var(--text-mid); }

.lede__status {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-dim);
}

/* ── Footer, shared ──────────────────────────────────────────────── */

.footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: 100%;
  max-width: 1000px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 24px;
  font-size: 14px;
}

/* Footer links are dim until hovered — they are wayfinding, not the
   point of the page. 14px, not smaller: these are the legal links and
   somebody looking for the deletion route should not have to squint. */
.footer__links a { color: var(--text-dim); }
.footer__links a:hover { color: var(--accent); }

.footer__copy { font-size: 13px; color: var(--text-faint); }

/* ── 404 ─────────────────────────────────────────────────────────── */

.notfound {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 20px;
  min-height: 100svh;
  padding: 48px 24px;
  text-align: center;
}

.notfound__code {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.notfound__title {
  font-size: clamp(26px, 6vw, 38px);
  font-weight: 900;
  letter-spacing: -0.03em;
  line-height: 1.1;
}

.notfound__body { font-size: 16px; color: var(--text-mid); max-width: 460px; }

/* ════════════════════════════════════════════════════════════════════
   MOTION
   ════════════════════════════════════════════════════════════════════
   The holding page gets ONE entrance and nothing else. It is a holding
   page: a visitor is here for eight seconds on their way to a policy
   document, and anything looping would be a page fidgeting at someone
   who is trying to leave.

   The full marketing site spends its motion budget differently — on the
   phone screens behaving like the running app — but that is a different
   page with a different job.

   prefers-reduced-motion does not slow this down, it turns it OFF at the
   final frame. Reduced motion must never mean less information, and it
   must never mean an element that stays invisible because its animation
   was the thing making it visible.
   ════════════════════════════════════════════════════════════════════ */

@keyframes jst-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}

@keyframes jst-sweep {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.rise {
  animation: jst-rise 0.8s cubic-bezier(0.22, 0.9, 0.3, 1) both;
  animation-delay: var(--d, 0s);
}

.wordmark__rule {
  transform-origin: center;
  animation: jst-sweep 0.7s cubic-bezier(0.22, 0.9, 0.3, 1) 0.55s both;
}

/* The CTA-less holding page has one interactive surface: the footer
   links. Give them a real transition rather than a hard colour swap. */
.footer__links a { transition: color 0.18s ease; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* ...and land the entrance on its finished frame, so nothing that
     animates its way into view stays invisible. */
  .rise { opacity: 1 !important; transform: none !important; }
  .wordmark__rule { transform: none !important; }
}

/* ════════════════════════════════════════════════════════════════════
   THE MARKETING PAGE
   ════════════════════════════════════════════════════════════════════
   Everything below is site/index.html only. The holding page above
   shares the tokens and the footer and nothing else.

   One responsive document, not a desktop file and a mobile file. The
   design canvas showed the two widths as separate artboards because a
   canvas cannot resize; the shipped page is a single layout that
   collapses at 900px.
   ════════════════════════════════════════════════════════════════════ */

.wrap { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 24px; }

/* ── Nav ─────────────────────────────────────────────────────────── */
.nav {
  display: flex; align-items: center; justify-content: space-between;
  height: 72px; border-bottom: 1px solid var(--border);
}
.lockup { display: flex; align-items: center; gap: 11px; }
.lockup img { width: 28px; height: 28px; border-radius: 8px; display: block; }
.lockup__type { font-size: 16px; font-weight: 900; letter-spacing: -0.02em; }
.nav__links { display: flex; gap: 28px; font-size: 14px; font-weight: 600; }
.nav__links a { color: var(--text-dim); }
.nav__links a:hover { color: var(--text); }

/* ── Hero ────────────────────────────────────────────────────────── */
.hero { position: relative; display: flex; align-items: center; gap: 72px; padding: 88px 0 96px; overflow: hidden; }
.hero__text { display: flex; flex-direction: column; gap: 26px; flex: 1 1 0; min-width: 0; }
.hero__glow {
  position: absolute; right: -60px; top: 20px; width: 620px; height: 620px;
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, var(--accent-glow) 0%, rgba(0,212,212,0.05) 42%, rgba(0,0,0,0) 68%);
}
.eyebrow--dot { display: flex; align-items: center; gap: 10px; }
.eyebrow__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.hero__h1 {
  font-size: clamp(44px, 7vw, 72px); font-weight: 900;
  letter-spacing: -0.038em; line-height: 0.98;
}
.hero__h1 span { display: block; }
.hero__h1 span:last-child { color: var(--accent); }
.hero__sub { font-size: clamp(16px, 2vw, 19px); color: var(--text-mid); max-width: 30rem; }

/* ── Waitlist ────────────────────────────────────────────────────── */
.waitlist { display: flex; flex-direction: column; gap: 12px; max-width: 30rem; }
.waitlist__row { display: flex; gap: 10px; }
.waitlist__field {
  flex: 1 1 auto; min-width: 0; height: 52px; padding: 0 18px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; color: var(--text); font: inherit; font-size: 15px;
}
.waitlist__field::placeholder { color: var(--text-faint); }
.waitlist__btn {
  height: 52px; padding: 0 22px; border: 0; border-radius: 10px;
  background: linear-gradient(180deg, var(--accent-grad-top) 0%, var(--accent-grad-bot) 100%);
  box-shadow: 0 2px 16px var(--accent-glow);
  color: var(--accent-contrast); font: inherit; font-size: 15px; font-weight: 700;
  white-space: nowrap; cursor: pointer;
  transition: box-shadow .2s ease, transform .2s ease;
}
.waitlist__btn:hover { box-shadow: 0 4px 24px var(--accent-glow); transform: translateY(-1px); }
.waitlist__note { font-size: 13px; color: var(--text-dim); }

/* ── The phone frames ────────────────────────────────────────────── */
.phone {
  position: relative; flex: 0 0 auto; width: 310px;
  border: 1px solid #222; border-radius: 40px; background: #000; padding: 10px;
  box-shadow: 0 50px 100px rgba(0,0,0,.8), 0 0 0 1px rgba(0,212,212,.08);
}
.phone__screen { border-radius: 31px; overflow: hidden; background: #000; display: flex; flex-direction: column; }
.phone--sm { width: 262px; border-radius: 36px; padding: 9px; }
.phone--sm .phone__screen { border-radius: 28px; }
/* The screens are drawn illustrations, always dark — they depict the
   app's Classic dark theme, which does not follow the visitor's OS. */
.phone, .phone__screen { color: #fff; }

/* ── Proof strip ─────────────────────────────────────────────────── */
.proof {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.proof__cell { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 40px 12px; }
.proof__cell + .proof__cell { border-left: 1px solid var(--border); }
.proof__num {
  font-size: clamp(30px, 4vw, 46px); font-weight: 900; letter-spacing: -0.04em;
  line-height: 1; font-variant-numeric: tabular-nums;
}
.proof__num--accent { color: var(--accent); }
.proof__label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--text-dim); text-align: center;
}

/* ── Feature blocks ──────────────────────────────────────────────── */
.feature { display: flex; align-items: center; gap: 72px; padding: 88px 0; }
.feature + .feature { border-top: 1px solid var(--border); }
.feature--reverse { flex-direction: row-reverse; }
.feature__text { display: flex; flex-direction: column; gap: 16px; flex: 1 1 0; min-width: 0; max-width: 32rem; }
.feature__h2 { font-size: clamp(28px, 4vw, 42px); font-weight: 900; letter-spacing: -0.035em; line-height: 1.08; }
.feature__body { font-size: clamp(15px, 2vw, 17px); color: var(--text-mid); }

/* ── Rank row ────────────────────────────────────────────────────── */
.ranks { display: flex; align-items: flex-end; justify-content: center; gap: 20px; flex: 0 0 auto; }
.rank { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.rank img { display: block; height: auto; }
.rank__name { font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; }

/* ── Full-width band ─────────────────────────────────────────────── */
.band {
  background: #050505; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
@media (prefers-color-scheme: light) { .band { background: var(--surface); } }
.band__inner { display: flex; flex-direction: column; align-items: center; gap: 26px; padding: 104px 0; text-align: center; }
.band__h2 { font-size: clamp(30px, 5vw, 54px); font-weight: 900; letter-spacing: -0.04em; line-height: 1.05; max-width: 20ch; }
.band__body { font-size: clamp(16px, 2vw, 18px); color: var(--text-mid); max-width: 42rem; line-height: 1.7; }
.band__link { font-size: 15px; font-weight: 700; }

/* ── Pricing ─────────────────────────────────────────────────────── */
.pricing { display: flex; flex-direction: column; align-items: center; gap: 36px; padding: 88px 0; }
.pricing__head { display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; }
.pricing__kicker { font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-dim); }
.pricing__h2 { font-size: clamp(26px, 4vw, 40px); font-weight: 900; letter-spacing: -0.035em; }
.plans { display: flex; gap: 20px; flex-wrap: wrap; justify-content: center; }
.plan {
  display: flex; flex-direction: column; gap: 12px; width: 320px; padding: 30px 28px;
  background: var(--card); border: 1px solid var(--border); border-radius: 16px;
}
.plan--featured { border-color: var(--accent); box-shadow: 0 0 40px var(--accent-soft); }
.plan__label { font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-dim); }
.plan--featured .plan__label { color: var(--accent); }
.plan__row { display: flex; align-items: center; justify-content: space-between; }
.plan__save { padding: 3px 9px; border-radius: 20px; background: var(--accent-soft); font-size: 10px; font-weight: 700; color: var(--accent); }
.plan__price { display: flex; align-items: baseline; gap: 6px; }
.plan__amount { font-size: 42px; font-weight: 900; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.plan__per { font-size: 15px; color: var(--text-dim); }
.plan__note { font-size: 14px; color: var(--text-dim); }
.pricing__fine { font-size: 14px; color: var(--text-faint); max-width: 38rem; text-align: center; line-height: 1.7; }

/* ── Closing CTA ─────────────────────────────────────────────────── */
.cta__inner { display: flex; flex-direction: column; align-items: center; gap: 24px; padding: 88px 0; text-align: center; }
.cta__h2 { font-size: clamp(26px, 4vw, 38px); font-weight: 900; letter-spacing: -0.035em; }

/* ── Site footer ─────────────────────────────────────────────────── */
.site-footer { border-top: 1px solid var(--border); padding: 48px 0 56px; display: flex; justify-content: space-between; gap: 48px; flex-wrap: wrap; }
.site-footer__cols { display: flex; gap: 56px; flex-wrap: wrap; }
.fcol { display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.fcol__head { font-size: 10px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-faint); }
.fcol a { color: var(--text-dim); }
.fcol a:hover { color: var(--accent); }

/* ── Scroll reveal ───────────────────────────────────────────────── */
/* Applied by a ~15-line IntersectionObserver in the page. The initial
   hidden state is set by script, never in CSS — a stylesheet that hides
   content would leave the whole page blank if the script never runs. */
.is-hidden { opacity: 0; transform: translateY(22px); }
.is-shown { opacity: 1; transform: none; transition: opacity .7s cubic-bezier(.22,.9,.3,1), transform .7s cubic-bezier(.22,.9,.3,1); }

/* ── Responsive ──────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .nav__links { display: none; }
  .hero { flex-direction: column; align-items: flex-start; gap: 44px; padding: 56px 0 64px; }
  .hero__glow { right: auto; left: -140px; top: 220px; width: 440px; height: 440px; }
  .phone { align-self: center; width: 268px; }
  .proof { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .proof__cell { border-top: 1px solid var(--border); }
  .proof__cell:nth-child(odd) { border-left: 0; }
  .proof__cell:nth-child(even) { border-left: 1px solid var(--border); }
  .feature, .feature--reverse { flex-direction: column; align-items: flex-start; gap: 32px; padding: 56px 0; }
  .feature__text { max-width: none; }
  .phone--sm { align-self: center; }
  .ranks { align-self: center; gap: 12px; }
  .band__inner { padding: 64px 0; }
  .plans { flex-direction: column; align-items: stretch; width: 100%; }
  .plan { width: auto; }
  .waitlist__row { flex-direction: column; }
  .waitlist__btn { width: 100%; }
}

@media (max-width: 560px) {
  .ranks img { max-width: 86px; }
}

@media (prefers-reduced-motion: reduce) {
  .is-hidden, .is-shown { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ── In-screen motion ────────────────────────────────────────────────
   The motion budget goes into the PRODUCT, not the page: the phone
   screens behave like the running app. Each loop draws once and then
   HOLDS for most of its cycle — a chart that redraws every two seconds
   is a nervous tic, not a flourish. */
@keyframes jstDraw   { 0% { stroke-dashoffset: var(--len); } 26%, 100% { stroke-dashoffset: 0; } }
@keyframes jstRing   { from { stroke-dashoffset: 339.3; } to { stroke-dashoffset: 69; } }
@keyframes jstFill   { from { width: 0; } }
@keyframes jstPop    { from { opacity: 0; transform: scale(.4); } 70% { transform: scale(1.15); } to { opacity: 1; transform: scale(1); } }
@keyframes jstBorder { 0%, 60%, 100% { border-color: #00D4D4; box-shadow: 0 0 0 rgba(0,212,212,0); } 30% { border-color: #7CE9E9; box-shadow: 0 0 16px rgba(0,212,212,.30); } }
@keyframes jstGlow   { 0%, 100% { opacity: .6; transform: scale(1); } 50% { opacity: 1; transform: scale(1.05); } }

.jst-draw { stroke-dasharray: var(--len); stroke-dashoffset: var(--len); animation: jstDraw 9s ease-out .5s infinite both; }
.jst-ring { animation: jstRing 2s cubic-bezier(.3,.9,.3,1) .6s both; }
.jst-bar  { animation: jstFill 1.5s cubic-bezier(.3,.9,.3,1) both; animation-delay: var(--d, .7s); }
.jst-tick { animation: jstPop .5s cubic-bezier(.3,1.4,.5,1) both; animation-delay: var(--d, 1s); }
.jst-live { animation: jstBorder 4.5s ease-in-out 1.6s infinite; }
.hero__glow { animation: jstGlow 7s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .jst-draw, .jst-ring, .jst-bar, .jst-tick, .jst-live, .hero__glow { animation: none !important; }
  .jst-draw { stroke-dashoffset: 0 !important; }
  .jst-ring { stroke-dashoffset: 69 !important; }
}

/* Screen-reader-only. The waitlist inputs carry a real <label> rather
   than leaning on the placeholder — a placeholder is not a label, and it
   vanishes the moment somebody starts typing. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Paired with the beforeprint handler in reveal.js. A scroll-reveal that
   hides content is fine on screen and unacceptable on paper. */
@media print {
  .is-hidden, .is-shown { opacity: 1 !important; transform: none !important; }
}
