// fc-reveal-lab.jsx — EXPERIMENT CANVAS for the post-loading moment.
// Strategy (research-backed): the loading screen ("Building your camp") pays off
// into a REVEAL = the aha moment — its own screen, glanceable, intelligence-
// forward, ending in ONE CTA. The PAYWALL is a SEPARATE screen right after,
// echoing the goal. The first-7-days card moves POST-purchase (activation).
//
// Every option below reads the SAME engine numbers (window.FC + helpers) so the
// directions differ in *framing*, not data. The point of the lab is to find the
// sharpest way to show that the app actually reasoned about THIS athlete.

// ── shared engine read ───────────────────────────────────────────────────────
function useReveal() {
  const FC = window.FC || {};
  const sport = FC.sport || 'MMA';
  const division = FC.division || null;
  const firstName = FC.firstName || '';
  const startW = FC.planStart != null ? FC.planStart : 78.4;
  const targetW = FC.goalWeight != null ? FC.goalWeight : 74.4;
  const cut = +(startW - targetW).toFixed(1);
  const weeks = 8;
  const planType = window.planTypeFor ? window.planTypeFor(sport, true) : 'camp';
  const water = planType !== 'walk';
  const fwWater = water ? +(cut * 0.28).toFixed(1) : 0;
  const campKg = +(cut - fwWater).toFixed(1);
  const ratePct = +((cut / weeks / startW) * 100).toFixed(2);
  const weekly = +(cut / weeks).toFixed(1);
  const S = (window.FC_SPORTS || {})[sport] || {};
  const REHYD = {
    'day-before': '≈ 24-hour rehydration window',
    'same-day': 'no rehydration window',
    'within-2h': 'almost no rehydration window',
    'same-or-day-before': 'a tight rehydration window',
  };
  const WEIGHIN_LABEL = {
    'day-before': 'day-before weigh-in',
    'same-day': 'same-day weigh-in',
    'within-2h': 'weigh-in minutes before you compete',
    'same-or-day-before': 'same / day-before weigh-in',
  };
  return {
    FC, sport, division, firstName, startW, targetW, cut, weeks, water, fwWater, campKg,
    ratePct, weekly, weighIn: S.weighIn || 'day-before', weighInTime: FC.weighInTime || '6:50 AM',
    rehyd: REHYD[S.weighIn] || REHYD['day-before'], weighInLabel: WEIGHIN_LABEL[S.weighIn] || WEIGHIN_LABEL['day-before'],
    coach: S.coach,
  };
}

// ── shared chrome ────────────────────────────────────────────────────────────
function RevealFrame({ label, children, footer }) {
  return (
    <Phone styleKey="balanced" label={label}>
      <StatusBar />
      <div className="scroll" style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {children}
      </div>
      {footer}
      <HomeIndicator />
    </Phone>
  );
}

function PrimaryNext({ label = 'See my full plan', sub }) {
  return (
    <div style={{ padding: '12px 20px 8px', borderTop: '1px solid var(--rule)', background: 'var(--paper-2)' }}>
      <button style={{ width: '100%', background: 'var(--ink)', color: 'var(--paper)', border: 'none', borderRadius: 'var(--radius-ctl)', minHeight: 54, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10 }}>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600 }}>{label}</span>
        <svg width="16" height="12" viewBox="0 0 16 12" fill="none"><path d="M1 6 H14 M9.5 1.5 L14.5 6 L9.5 10.5" stroke="var(--paper)" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
      </button>
      {sub && <div style={{ textAlign: 'center', marginTop: 9, fontFamily: 'var(--sans)', fontSize: 12, color: 'var(--ink-3)' }}>{sub}</div>}
    </div>
  );
}

// little "the app reasoned about you" eyebrow
function ReadChip({ children = 'Built from your answers' }) {
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, background: 'var(--accent-soft, rgba(163,42,24,0.09))', borderRadius: 100, padding: '5px 11px 5px 9px' }}>
      <svg width="13" height="13" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="6" stroke="var(--accent)" strokeWidth="1.3"/><path d="M4.3 7.1 L6.1 8.9 L9.7 4.9" stroke="var(--accent)" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.07em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--accent)' }}>{children}</span>
    </div>
  );
}

// safe-pace meter — shared by several options. 0 → 1%/wk, marker at your rate.
function PaceMeter({ ratePct, compact = false }) {
  const ceiling = 1.0;
  const pos = Math.min(100, (ratePct / ceiling) * 100);
  return (
    <div>
      <div style={{ position: 'relative', height: compact ? 10 : 13, borderRadius: 100, overflow: 'hidden', background: 'linear-gradient(90deg, var(--green) 0%, #6f8a3a 55%, var(--amber) 78%, var(--accent) 100%)', opacity: 0.92 }}>
        <div style={{ position: 'absolute', top: -3, bottom: -3, left: `calc(${pos}% - 2px)`, width: 4, background: 'var(--ink)', borderRadius: 2, boxShadow: '0 0 0 2.5px var(--paper)' }} />
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 7, fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.04em', color: 'var(--ink-3)', fontWeight: 600 }}>
        <span style={{ color: 'var(--green)' }}>SAFE</span>
        <span style={{ color: 'var(--accent)' }}>1%/wk LIMIT</span>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// PAYWALL 1 — "Goal echo + roadmap teaser" · the offer, its own screen
// Headline echoes the exact goal. The locked week-by-week roadmap shows what
// you're buying. Trial framing + proof + plans.
// ═══════════════════════════════════════════════════════════════════════════
function PaywallRoadmap() {
  const d = useReveal();
  const [plan, setPlan] = React.useState('annual');
  return (
    <Phone styleKey="balanced" label="Paywall · Roadmap">
      <StatusBar />
      <div className="scroll" style={{ flex: 1, padding: '12px 20px 20px', display: 'flex', flexDirection: 'column' }}>
        {/* goal echo */}
        <div style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>Your plan is ready</div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 26, fontWeight: 700, lineHeight: 1.15, letterSpacing: '-0.02em', color: 'var(--ink)', marginTop: 10, textWrap: 'balance' }}>
          Make {d.targetW.toFixed(1)} kg for {d.sport}{d.division ? ' ' + d.division : ''} — unlock the full {d.weeks} weeks.
        </div>
        {/* roadmap teaser */}
        <div style={{ marginTop: 20, background: 'var(--paper)', border: '1px solid var(--rule)', borderRadius: 'var(--radius)', padding: 18 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, marginBottom: 16 }}>
            <Eyebrow color="var(--accent)">Your week-by-week road</Eyebrow>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>Start → fight night</span>
          </div>
          {window.WeekRoadmap && <window.WeekRoadmap startW={d.startW} goal={d.targetW} weeks={d.weeks} water={d.water} fwWater={d.fwWater} weighInLabel={d.water ? 'water taper' : 'weigh-in'} teaser={true} free={2} width={283} />}
        </div>
        {/* unlock */}
        <div style={{ marginTop: 16 }}>
          <PaywallUnlock plan={plan} setPlan={setPlan} />
        </div>
        {window.ProofBand && <div style={{ marginTop: 16 }}><window.ProofBand sport={d.sport} quote /></div>}
      </div>
      <HomeIndicator />
    </Phone>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// PAYWALL 2 — "The daily verdict teaser" · sell the live product
// Shows the locked core feature — the morning verdict — blurred behind the
// gate. "Every morning, your call." Then plans + trial.
// ═══════════════════════════════════════════════════════════════════════════
function PaywallVerdict() {
  const d = useReveal();
  const [plan, setPlan] = React.useState('annual');
  return (
    <Phone styleKey="balanced" label="Paywall · Daily Verdict">
      <StatusBar />
      <div className="scroll" style={{ flex: 1, padding: '12px 20px 20px', display: 'flex', flexDirection: 'column' }}>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>Your plan is ready</div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 26, fontWeight: 700, lineHeight: 1.15, letterSpacing: '-0.02em', color: 'var(--ink)', marginTop: 10, textWrap: 'balance' }}>
          Every morning, one clear call — on track, too fast, or behind.
        </div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 14.5, color: 'var(--ink-2)', marginTop: 9, lineHeight: 1.5, textWrap: 'pretty' }}>
          Log your weight, the engine reads your trend against the {d.ratePct.toFixed(2)}%/wk plan and tells you exactly what today means.
        </div>
        {/* locked verdict mock */}
        <div style={{ marginTop: 20, position: 'relative', background: 'var(--paper)', border: '1px solid var(--rule)', borderRadius: 'var(--radius)', padding: 20, overflow: 'hidden' }}>
          <div style={{ filter: 'blur(5px)', opacity: 0.7, pointerEvents: 'none' }}>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
              <Eyebrow color="var(--ink-3)">This morning</Eyebrow>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>{d.weighInTime}</span>
            </div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 10 }}>
              <span style={{ fontFamily: 'var(--num)', fontWeight: 200, fontSize: 48, letterSpacing: '-0.03em', color: 'var(--ink)' }}>77.6</span>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--ink-3)', fontWeight: 600 }}>kg</span>
              <span style={{ marginLeft: 'auto', fontFamily: 'var(--display)', fontSize: 13, letterSpacing: '0.06em', fontWeight: 600, color: 'var(--green)' }}>ON TRACK</span>
            </div>
            <div style={{ height: 56, marginTop: 14, background: 'linear-gradient(180deg, var(--green-soft, rgba(58,107,46,0.12)), transparent)', borderRadius: 12 }} />
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, color: 'var(--ink-2)', marginTop: 12 }}>You’re 0.2 kg ahead of pace — hold steady today.</div>
          </div>
          <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <span style={{ display: 'flex', alignItems: 'center', gap: 8, background: 'var(--ink)', borderRadius: 100, padding: '9px 16px' }}>
              <svg width="12" height="14" viewBox="0 0 15 17" fill="none"><rect x="1.5" y="7" width="12" height="9" rx="2" stroke="var(--paper)" strokeWidth="1.5"/><path d="M4 7 V5 a3.5 3.5 0 0 1 7 0 V7" stroke="var(--paper)" strokeWidth="1.5"/></svg>
              <span style={{ fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600, color: 'var(--paper)' }}>Unlock the daily verdict</span>
            </span>
          </div>
        </div>
        <div style={{ marginTop: 16 }}>
          <PaywallUnlock plan={plan} setPlan={setPlan} />
        </div>
        {window.ProofBand && <div style={{ marginTop: 16 }}><window.ProofBand sport={d.sport} quote /></div>}
      </div>
      <HomeIndicator />
    </Phone>
  );
}

// shared unlock block (plans + trial), inverted ink card
function PaywallUnlock({ plan, setPlan }) {
  const Plans = (
    <div style={{ marginTop: 4, display: 'flex', flexDirection: 'column', gap: 9 }}>
      {[['annual', 'Annual', '£59.99/yr', '£5.00/mo', 'Save 50%'], ['monthly', 'Monthly', '£9.99/mo', null, null]].map(([key, label, price, per, badge]) => {
        const sel = plan === key;
        return (
          <button key={key} onClick={() => setPlan(key)} style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', textAlign: 'left', cursor: 'pointer', padding: '13px 15px', borderRadius: 13, background: sel ? 'var(--paper)' : 'transparent', border: '1.5px solid ' + (sel ? 'var(--paper)' : 'rgba(246,244,239,0.32)') }}>
            <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: '50%', border: '2px solid ' + (sel ? 'var(--accent)' : 'rgba(246,244,239,0.5)'), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{sel && <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--accent)' }} />}</span>
            <span style={{ flex: 1, minWidth: 0 }}>
              <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontFamily: 'var(--sans)', fontSize: 15, fontWeight: 600, color: sel ? 'var(--ink)' : 'var(--paper)' }}>{label}</span>
                {badge && <span style={{ fontFamily: 'var(--mono)', fontSize: 8.5, letterSpacing: '0.06em', textTransform: 'uppercase', fontWeight: 700, color: '#fff', background: 'var(--accent)', borderRadius: 100, padding: '2px 7px' }}>{badge}</span>}
              </span>
              {per && <span style={{ display: 'block', fontFamily: 'var(--sans)', fontSize: 12, color: sel ? 'var(--ink-3)' : 'rgba(246,244,239,0.6)', marginTop: 2 }}>Just {per}, billed yearly</span>}
            </span>
            <span style={{ flexShrink: 0, fontFamily: 'var(--sans)', fontSize: 14.5, fontWeight: 700, color: sel ? 'var(--ink)' : 'var(--paper)' }}>{price}</span>
          </button>
        );
      })}
    </div>
  );
  return (
    <Card pad={20} inverted>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'rgba(246,244,239,0.7)', lineHeight: 1.4 }}>A fight-camp nutritionist runs <span style={{ color: 'var(--paper)', fontWeight: 600 }}>£80–150</span> a session.</span>
        <span style={{ flexShrink: 0, fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--paper)', fontWeight: 600 }}>Yours from £5/mo</span>
      </div>
      <div style={{ marginTop: 14 }}>{Plans}</div>
      <button style={{ width: '100%', marginTop: 14, background: 'var(--paper)', color: 'var(--ink)', border: 'none', borderRadius: 14, minHeight: 50, fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600 }}>Start 14-day free trial</button>
      <div style={{ textAlign: 'center', marginTop: 11, fontFamily: 'var(--sans)', fontSize: 12, color: 'rgba(246,244,239,0.78)', lineHeight: 1.45 }}>{plan === 'annual' ? 'Then £59.99/yr (£5.00/mo)' : 'Then £9.99/mo'} · cancel anytime.<br />We’ll remind you 2 days before your trial ends.</div>
    </Card>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// POST-PAYWALL — "First 7 days" activation (where the first-week card belongs now)
// Research: after the paywall converts, run a brief premium onboarding that
// guides the user to their first premium action.
// ═══════════════════════════════════════════════════════════════════════════
function PostPaywallActivation() {
  const d = useReveal();
  return (
    <Phone styleKey="balanced" label="Post-paywall · Activation">
      <StatusBar />
      <div className="scroll" style={{ flex: 1, padding: '16px 22px 20px', display: 'flex', flexDirection: 'column' }}>
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <span style={{ width: 52, height: 52, borderRadius: '50%', background: 'var(--green)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <svg width="22" height="17" viewBox="0 0 22 17" fill="none"><path d="M2 9 L8 15 L20 2" stroke="#fff" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </span>
        </div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 24, fontWeight: 700, lineHeight: 1.15, letterSpacing: '-0.02em', color: 'var(--ink)', marginTop: 16, textAlign: 'center', textWrap: 'balance' }}>You’re in. Camp starts now.</div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 14.5, color: 'var(--ink-2)', marginTop: 8, textAlign: 'center', lineHeight: 1.5, textWrap: 'pretty' }}>Three things to set you up for week one.</div>
        {window.FirstWeekCard && <window.FirstWeekCard startW={d.startW} weekly={d.weekly} weighInTime={d.weighInTime} />}
        <div style={{ flex: 1, minHeight: 16 }} />
      </div>
      <div style={{ padding: '12px 20px 8px', borderTop: '1px solid var(--rule)', background: 'var(--paper-2)' }}>
        <button style={{ width: '100%', background: 'var(--ink)', color: 'var(--paper)', border: 'none', borderRadius: 'var(--radius-ctl)', minHeight: 54, fontFamily: 'var(--display)', fontSize: 14, letterSpacing: '0.13em', fontWeight: 600 }}>LOG MY STARTING WEIGHT</button>
      </div>
      <HomeIndicator />
    </Phone>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// REVEAL B+C — "The Starting Plan" · FRONT-RUNNER (user pick)
// B's glanceable numbers + safety read + C's projection chart, framed as a
// *first cut* that visibly sharpens once camp is set up. The refinement teaser
// doubles as an intelligence showcase (the levers we haven't pulled yet) AND a
// reason to push through the paywall into setup.
// ═══════════════════════════════════════════════════════════════════════════
function RevealRefine() {
  const d = useReveal();
  const pillars = [
    ['Real weight', d.campKg.toFixed(1), 'kg', 'across ' + d.weeks + ' wks', 'var(--ink)'],
    ['Fight-week water', d.fwWater.toFixed(1), 'kg', d.water ? 'final week' : 'none', d.water ? 'var(--accent)' : 'var(--ink-3)'],
    ['Pace', d.ratePct.toFixed(2), '%/wk', 'under 1% line', 'var(--green)'],
  ];
  return (
    <RevealFrame label="Reveal · Starting Plan (B+C)" footer={<PrimaryNext sub="Your starting plan — yours to keep." />}>
      <div style={{ padding: '16px 22px 26px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div style={{ display: 'flex', justifyContent: 'center' }}><ReadChip>Your starting plan</ReadChip></div>
        {/* hero (B) */}
        <div style={{ textAlign: 'center', marginTop: 22 }}>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 600, color: 'var(--ink-3)' }}>{d.startW.toFixed(1)} kg today → {d.targetW.toFixed(1)} kg make-weight</div>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 8, marginTop: 8 }}>
            <span style={{ fontFamily: 'var(--num)', fontWeight: 200, fontSize: 72, lineHeight: 1, letterSpacing: '-0.03em', color: 'var(--ink)' }}>−{d.cut.toFixed(1)}</span>
            <span style={{ fontFamily: 'var(--display)', fontSize: 16, letterSpacing: '0.08em', fontWeight: 600, color: 'var(--ink-3)' }}>KG</span>
          </div>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600, marginTop: 8 }}>in {d.weeks} weeks · {d.sport}{d.division ? ' ' + d.division : ''}</div>
        </div>
        {/* sport-specific coaching tip — the Coach Insight Card (sport × cut-rate tier) */}
        {(() => {
          const tier = window.paceTierFromRate ? window.paceTierFromRate(d.ratePct) : 'ideal';
          const tip = window.coachTip ? window.coachTip(d.sport, tier) : null;
          if (!tip) return null;
          return (
            <div style={{ marginTop: 22, paddingTop: 18, borderTop: '1px solid var(--rule)' }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 700, marginBottom: 9 }}>Coaching tip</div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 17, fontWeight: 700, lineHeight: 1.3, color: 'var(--ink)', textWrap: 'balance' }}>{tip.headline}</div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 8, textWrap: 'pretty' }}>{tip.body}</div>
            </div>
          );
        })()}
        {/* pillars (B) */}
        <div style={{ display: 'flex', marginTop: 24, border: '1px solid var(--rule)', borderRadius: 'var(--radius)', overflow: 'hidden', background: 'var(--paper)' }}>
          {pillars.map(([lb, v, u, sub, c], i) => (
            <div key={lb} style={{ flex: 1, padding: '15px 11px', borderLeft: i ? '1px solid var(--rule)' : 'none', textAlign: 'center' }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 8.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600, minHeight: 22 }}>{lb}</div>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 2, marginTop: 7 }}>
                <span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 24, letterSpacing: '-0.02em', color: c }}>{v}</span>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 8.5, color: 'var(--ink-3)', fontWeight: 600 }}>{u}</span>
              </div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 10.5, color: 'var(--ink-3)', marginTop: 5 }}>{sub}</div>
            </div>
          ))}
        </div>
        {/* safety meter (B) */}
        <div style={{ marginTop: 20 }}><PaceMeter ratePct={d.ratePct} /></div>
        {/* projection chart (C) */}
        <div style={{ marginTop: 22, background: 'var(--paper)', border: '1px solid var(--rule)', borderRadius: 'var(--radius)', padding: '16px 14px 8px' }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 2, padding: '0 4px' }}>
            <Eyebrow color="var(--ink-3)" style={{ fontSize: 10 }}>Projection to weigh-in</Eyebrow>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.04em', color: 'var(--ink-3)', fontWeight: 600 }}>{d.weeks} WKS</span>
          </div>
          {window.PlanGlide
            ? <window.PlanGlide startW={d.startW} targetW={d.targetW} campWeeks={d.weeks} todayWeek={0} water={d.water} width={309} />
            : <div style={{ height: 150 }} />}
        </div>
        {/* refinement teaser — the "rough starting point gets sharper" beat */}
        <div style={{ marginTop: 24 }}><RefineTeaser /></div>
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// ── refinement teaser — the levers that sharpen the plan in setup (Flow 2) ──
// Reused by the Starting Plan and Your Camp reveals. Doubles as an intelligence
// showcase (the inputs we haven't pulled yet) AND a reason to push into setup.
function RefineTeaser({ title = 'This sharpens in setup' }) {
  const levers = [
    {
      icon: <><rect x="2.5" y="5" width="15" height="10" rx="2" stroke="currentColor" strokeWidth="1.5"/><path d="M6 5 V3.5 M14 5 V3.5 M2.5 9 H17.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></>,
      t: 'Competition rules', s: 'Your gear allowance, exact rehydration window and any re-weigh cap — so the make-weight is to the gram.',
    },
    {
      icon: <><circle cx="10" cy="10" r="7" stroke="currentColor" strokeWidth="1.5"/><path d="M10 3 a7 7 0 0 1 0 14" stroke="currentColor" strokeWidth="1.5" fill="none"/><circle cx="10" cy="10" r="1.4" fill="currentColor"/></>,
      t: 'Your cycle', s: 'Cycle-aware targets, so a normal hormonal water swing never reads as off-track.', tag: 'if tracked',
    },
    {
      icon: <><path d="M4 15 L8 8 L12 12 L16 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/><path d="M16 4 H12.5 M16 4 V7.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/></>,
      t: 'Cut strategy', s: 'How hard the fight-week water cut runs, and how the refeed is staged.',
    },
    {
      icon: <><circle cx="10" cy="10" r="7" stroke="currentColor" strokeWidth="1.5"/><path d="M10 6 V10 L12.5 12" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></>,
      t: 'Weigh-in & reminders', s: 'Your daily fasted check, locked to your morning routine.',
    },
  ];
  return (
    <div style={{ background: 'var(--paper)', border: '1px solid var(--rule)', borderRadius: 'var(--radius)', padding: '18px 18px 8px' }}>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
        <Eyebrow color="var(--accent)">{title}</Eyebrow>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>4 more inputs</span>
      </div>
      <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, color: 'var(--ink-2)', lineHeight: 1.5, marginTop: 8, marginBottom: 6, textWrap: 'pretty' }}>
        This is your first cut from sport and timeline. Once camp’s set up, we factor in:
      </div>
      {levers.map((lv) => (
        <div key={lv.t} style={{ display: 'flex', gap: 13, padding: '13px 0', borderTop: '1px solid var(--rule)' }}>
          <span style={{ flexShrink: 0, width: 34, height: 34, borderRadius: 10, background: 'var(--paper-2)', border: '1px solid var(--rule)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--accent)' }}>
            <svg width="20" height="20" viewBox="0 0 20 20" fill="none">{lv.icon}</svg>
          </span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontFamily: 'var(--sans)', fontSize: 14.5, fontWeight: 600, color: 'var(--ink)' }}>{lv.t}</span>
              {lv.tag && <span style={{ fontFamily: 'var(--mono)', fontSize: 8, letterSpacing: '0.05em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--ink-3)', background: 'var(--paper-2)', border: '1px solid var(--rule)', borderRadius: 100, padding: '2px 7px' }}>{lv.tag}</span>}
            </div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.45, marginTop: 3, textWrap: 'pretty' }}>{lv.s}</div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// REVEAL ★ — "Your Camp preview" · FRONT-RUNNER
// Built from the REAL in-app "Your Camp" components (hero card, the cut card +
// descent chart, the CoachTip read) so the aha moment previews exactly what the
// athlete gets — then optimised for conversion: goal-echo header, a pace-aware
// Coach's Read, the "sharpens in setup" teaser, and one CTA to the paywall.
// ═══════════════════════════════════════════════════════════════════════════
// shared camp data for the Your Camp reveal variants
function useCampData() {
  const d = useReveal();
  const FC = window.FC || {};
  const S = (window.FC_SPORTS || {})[d.sport] || {};
  const equip = !!S.equipmentReq;
  const tier = window.paceTierFromRate ? window.paceTierFromRate(d.ratePct) : 'ideal';
  const tip = window.coachTip ? window.coachTip(d.sport, tier) : null;
  const GLYPH = { MMA: 'mma', Boxing: 'boxing', BJJ: 'bjj', 'BJJ (no-gi)': 'bjj', Judo: 'judo', 'Muay Thai': 'muaythai', Taekwondo: 'taekwondo', Wrestling: 'wrestling' };
  const glyph = GLYPH[d.sport];
  const weighPhrase = { 'day-before': 'the day before', 'same-day': 'the same day', 'within-2h': 'in the gi, just before you compete', 'same-or-day-before': 'same day / day before' }[d.weighIn] || 'the day before';
  const weighShort = { 'day-before': 'day before', 'same-day': 'same day', 'within-2h': 'in gi, pre-comp', 'same-or-day-before': 'same / day before' }[d.weighIn] || 'day before';
  const chipTier = tier === 'ideal' ? 'CAMP' : tier === 'fast' ? 'FAST' : 'STEEP';
  // What the engine already knows by this point — from sport, gender, timeline,
  // and the sport's standard competition rules: the recommended cut strategy and
  // the common gear / re-weigh caps are pre-set, not left for the athlete to find.
  const included = [
    { t: 'Sport & weigh-in rules', s: `${d.sport} · ${weighShort}` },
    { t: 'Class limit & body target', s: `${d.targetW.toFixed(1)} kg${equip ? ` · ${S.equipmentKg} kg gear` : ''}` },
    { t: 'Cut size & timeline', s: `${d.cut.toFixed(1)} kg over ${d.weeks} wks` },
    { t: 'Safe cut pace', s: `${d.ratePct.toFixed(2)}%/wk` },
    { t: 'Recommended cut strategy', s: d.water ? `water taper on a ${d.campKg.toFixed(1)} kg real-weight base` : 'walk-it-down — all real weight' },
    ...(equip ? [{ t: 'Typical gear & re-weigh cap', s: `${S.equipmentKg} kg gear · sport-standard re-weigh` }] : []),
  ];
  // What still genuinely needs the athlete in setup — the personal pieces only.
  const pending = [
    ...(equip ? [{ t: 'Confirm your event’s exact caps', s: 'gear allowance & re-weigh vary by promotion' }] : []),
    { t: 'Cycle-aware targets', s: 'a hormonal water swing never reads as off-track', tag: 'if tracked' },
    { t: 'Weigh-in time & reminders', s: 'your daily fasted check, locked to your morning' },
  ];
  return { d, FC, S, equip, tier, tip, glyph, weighPhrase, weighShort, chipTier, included, pending };
}

// a single checklist row, two states: done (accent tick) / pending (hollow ring)
function CheckRow({ done, t, s, tag, last }) {
  return (
    <div style={{ display: 'flex', gap: 12, padding: '11px 0', alignItems: 'flex-start', borderBottom: last ? 'none' : '1px solid var(--rule)' }}>
      <span style={{ flexShrink: 0, marginTop: 1, width: 20, height: 20, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', background: done ? 'var(--accent)' : 'transparent', border: done ? 'none' : '1.5px solid var(--rule-2)' }}>
        {done && <svg width="10" height="8" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>}
      </span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ fontFamily: 'var(--sans)', fontSize: 14.5, fontWeight: 600, color: done ? 'var(--ink)' : 'var(--ink-2)' }}>{t}</span>
          {tag && <span style={{ fontFamily: 'var(--mono)', fontSize: 8, letterSpacing: '0.05em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--ink-3)', background: 'var(--paper-2)', border: '1px solid var(--rule)', borderRadius: 100, padding: '2px 7px' }}>{tag}</span>}
        </div>
        {s && <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', marginTop: 2 }}>{s}</div>}
      </div>
    </div>
  );
}

// shared atoms reused across variants
function GroupLabel({ children, color = 'var(--ink-3)' }) {
  return <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.1em', textTransform: 'uppercase', color, fontWeight: 700 }}>{children}</div>;
}
// editorial bare number (lives outside any card) — A
function BareNum({ label, value, unit, sub, color = 'var(--ink)', pad }) {
  return (
    <div style={{ flex: 1, paddingLeft: pad ? 22 : 0 }}>
      <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{label}</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 9 }}>
        <span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 42, lineHeight: 1, letterSpacing: '-0.03em', color }}>{value}</span>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>{unit}</span>
      </div>
      {sub && <div style={{ fontFamily: 'var(--sans)', fontSize: 11.5, color: 'var(--ink-3)', marginTop: 6 }}>{sub}</div>}
    </div>
  );
}

// dotted-rule spec row — C dossier
function SpecRow({ k, v, accent, last }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12, padding: '12px 0', borderBottom: last ? 'none' : '1px dotted var(--rule-2)' }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{k}</span>
      <span style={{ fontFamily: 'var(--sans)', fontSize: 14.5, fontWeight: 700, color: accent ? 'var(--accent)' : 'var(--ink)', textAlign: 'right' }}>{v}</span>
    </div>
  );
}

// segmented progress — C dossier (one tick per plan input)
function Seg({ total, done, dark }) {
  return (
    <div style={{ display: 'flex', gap: 4 }}>
      {Array.from({ length: total }).map((_, i) => (
        <div key={i} style={{ flex: 1, height: 6, borderRadius: 1, background: i < done ? 'var(--accent)' : (dark ? 'rgba(250,247,241,0.18)' : 'var(--rule)') }} />
      ))}
    </div>
  );
}

// rounded progress bar — A & B (the one you liked)
function ProgressBar({ done, total, dark }) {
  const pct = Math.round((done / total) * 100);
  return (
    <div style={{ height: 7, borderRadius: 100, background: dark ? 'rgba(250,247,241,0.16)' : 'var(--rule)', overflow: 'hidden' }}>
      <div style={{ width: pct + '%', height: '100%', background: 'var(--accent)', borderRadius: 100 }} />
    </div>
  );
}

// shared "paced under the line" reassurance strip
function PacedLine({ ratePct, dark, refineNote }) {
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: '50%', background: 'var(--green)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><svg width="9" height="7" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: dark ? 'rgba(250,247,241,0.78)' : 'var(--ink-2)', lineHeight: 1.4 }}>Paced at <span style={{ fontWeight: 700, color: dark ? '#faf7f1' : 'var(--ink)' }}>{ratePct.toFixed(2)}%/wk</span> — inside the safe sub-1% line.</span>
      </div>
      {refineNote && <div style={{ marginTop: 7, marginLeft: 26, fontFamily: 'var(--sans)', fontSize: 11.5, fontStyle: 'italic', color: dark ? 'rgba(250,247,241,0.55)' : 'var(--ink-3)', lineHeight: 1.45 }}>A starting cut — the pace tightens once you finish setting up camp.</div>}
    </div>
  );
}

// descent chart with a heading + kg unit, y-axis weights, x-axis markers
function DescentChart({ c }) {
  const d = c.d;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 10 }}>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 700 }}>Your descent to fight day</span>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 8.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>Body weight · kg</span>
      </div>
      {window.PlanGlide && <window.PlanGlide startW={d.startW} targetW={d.targetW} campWeeks={d.weeks} todayWeek={0} water={d.water} width={341} axis />}
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// REVEAL ★ — "Your Camp" · NEW ORDER (Coach's read → details → cut → checklist)
// Three treatments of the same content + order. The checklist is two-state:
// everything the engine already locked is ticked; the goal-setting levers are
// unticked, so the athlete sees exactly what's done and what sharpens in setup.
// ═══════════════════════════════════════════════════════════════════════════

// ── condensed-A shared atoms ────────────────────────────────────────────────
// compact matchup + key numbers band (merges "About this camp" + cut stats)
function CampBand({ c }) {
  const d = c.d;
  const stats = [
    { lb: 'Class limit', v: (c.equip ? (c.FC.maxWithGi || d.targetW) : d.targetW).toFixed(1), u: 'kg' },
    { lb: 'Body target', v: d.targetW.toFixed(1), u: 'kg', accent: true },
    { lb: 'To lose', v: d.cut.toFixed(1), u: 'kg' },
    { lb: 'Timeline', v: String(d.weeks), u: 'wks' },
  ];
  return (
    <div>
      <div style={{ display: 'flex' }}>
        {stats.map((s, i) => (
          <div key={s.lb} style={{ flex: 1, paddingLeft: i ? 11 : 0, borderLeft: i ? '1px solid var(--rule)' : 'none' }}>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 8.5, letterSpacing: '0.04em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{s.lb}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 2, marginTop: 6 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 25, lineHeight: 1, letterSpacing: '-0.03em', color: s.accent ? 'var(--accent)' : 'var(--ink)' }}>{s.v}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 8.5, color: 'var(--ink-3)', fontWeight: 600 }}>{s.u}</span></div>
          </div>
        ))}
      </div>
    </div>
  );
}

// the coach's read kicker + headline + body, type-led (condensed)
function CoachRead({ c }) {
  if (!c.tip) return null;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
        <div style={{ minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 700 }}>{c.d.firstName ? `${c.d.firstName}’s camp` : 'Your camp'}</span>
            <span style={{ width: 18, height: 1, background: 'var(--accent)', opacity: 0.45 }} />
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{c.d.sport} · {(c.d.division || c.d.sport)}</span>
          </div>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600, marginTop: 8 }}>Fight night {c.FC.fightDateShort || 'Jan 1'} · weigh-in {c.weighShort}</div>
        </div>
        {c.glyph && window.SportGlyph && <div style={{ flexShrink: 0, marginTop: 1 }}><window.SportGlyph name={c.glyph} size={38} ink="var(--ink)" accent="var(--accent)" /></div>}
      </div>
      <div style={{ fontFamily: 'var(--sans)', fontSize: 21, fontWeight: 700, lineHeight: 1.24, letterSpacing: '-0.02em', color: 'var(--ink)', marginTop: 16, textWrap: 'balance' }}>{c.tip.headline}</div>
      <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 9, textWrap: 'pretty' }}>{c.tip.body}</div>
    </div>
  );
}

// the "sharpens in setup" value row — title + supporting value copy (hollow ring)
function SharpenRow({ t, s, tag, first }) {
  return (
    <div style={{ display: 'flex', gap: 11, padding: '10px 0', alignItems: 'flex-start', borderTop: first ? 'none' : '1px solid var(--rule)' }}>
      <span style={{ flexShrink: 0, marginTop: 2, width: 16, height: 16, borderRadius: '50%', border: '1.5px solid var(--rule-2)' }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7, flexWrap: 'wrap' }}>
          <span style={{ fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 600, color: 'var(--ink)' }}>{t}</span>
          {tag && <span style={{ fontFamily: 'var(--mono)', fontSize: 8, letterSpacing: '0.05em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--ink-3)', background: 'var(--paper-2)', border: '1px solid var(--rule)', borderRadius: 100, padding: '2px 7px' }}>{tag}</span>}
        </div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', marginTop: 2, lineHeight: 1.4, textWrap: 'pretty' }}>{s}</div>
      </div>
    </div>
  );
}

// collapses the ticked essentials into one confirmation line
function LockedSummary({ included }) {
  return (
    <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
      <span style={{ flexShrink: 0, marginTop: 1, width: 18, height: 18, borderRadius: '50%', background: 'var(--green)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><svg width="9" height="7" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink)' }}>{included.length} essentials locked in</div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', marginTop: 3, lineHeight: 1.45 }}>{included.map(i => i.t).join(' · ')}</div>
      </div>
    </div>
  );
}

// A1 · CONDENSED EDITORIAL — merged camp band, locked collapsed, value-copy pending
function RevealCampA() {
  const c = useCampData(); const d = c.d;
  const total = c.included.length + c.pending.length;
  const Rule = ({ m = 18 }) => <div style={{ height: 1, background: 'var(--rule)', margin: `${m}px 0` }} />;
  return (
    <RevealFrame label="Reveal · Your Camp — A1 · Condensed editorial" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ padding: '22px 26px 24px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <CoachRead c={c} />
        <Rule />
        <CampBand c={c} />
        <div style={{ margin: '16px 0 12px' }}><DescentChart c={c} /></div>
        <PacedLine ratePct={d.ratePct} refineNote />
        <Rule />
        {/* YOUR PLAN — collapsed locked + value-copy pending */}
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 700 }}>Your plan</div>
          <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, fontWeight: 600, color: 'var(--ink-2)' }}><span style={{ color: 'var(--ink)', fontWeight: 700 }}>{c.included.length}</span> of {total} set</span>
        </div>
        <div style={{ marginTop: 12, marginBottom: 14 }}><ProgressBar done={c.included.length} total={total} /></div>
        <LockedSummary included={c.included} />
        <div style={{ marginTop: 16, marginBottom: 2 }}><GroupLabel color="var(--accent)">Sharpens once camp is set up</GroupLabel></div>
        {c.pending.map((it, i) => <SharpenRow key={i} t={it.t} s={it.s} tag={it.tag} first={i === 0} />)}
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// A3 · VALUE BLOCK — locked as one progress line; the sharpen-later value copy
// gets its own tinted block so the upside reads loud (conversion lean).
function RevealCampA3() {
  const c = useCampData(); const d = c.d;
  const total = c.included.length + c.pending.length;
  const Rule = ({ m = 18 }) => <div style={{ height: 1, background: 'var(--rule)', margin: `${m}px 0` }} />;
  return (
    <RevealFrame label="Reveal · Your Camp — A3 · Value block" footer={<PrimaryNext label="Unlock & finish setup" sub={`${total - c.included.length} more inputs sharpen your plan.`} />}>
      <div style={{ padding: '22px 26px 24px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <CoachRead c={c} />
        <Rule />
        <CampBand c={c} />
        <div style={{ margin: '16px 0 12px' }}><DescentChart c={c} /></div>
        <PacedLine ratePct={d.ratePct} refineNote />
        <Rule />
        {/* locked as a single progress line */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
          <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: '50%', background: 'var(--green)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><svg width="9" height="7" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
          <span style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink)' }}>The {c.included.length} essentials are locked in</span>
        </div>
        <div style={{ marginTop: 12 }}><ProgressBar done={c.included.length} total={total} /></div>
        {/* value block — what sharpens next */}
        <div style={{ marginTop: 18, background: 'var(--accent-soft)', borderRadius: 'var(--radius)', padding: '15px 17px' }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 700 }}>Sharpens in setup</span>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.04em', color: 'var(--accent)', fontWeight: 600 }}>{c.pending.length} more</span>
          </div>
          <div style={{ marginTop: 4 }}>
            {c.pending.map((it, i) => <SharpenRow key={i} t={it.t} s={it.s} tag={it.tag} first={i === 0} />)}
          </div>
        </div>
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// MODULAR BLOCKS — composable pieces for the reveal explorations (E-series),
// so order + hierarchy can be remixed without re-writing markup each time.
// ═══════════════════════════════════════════════════════════════════════════
function MetaHeader({ c, dark }) {
  const sub = dark ? 'rgba(250,247,241,0.7)' : 'var(--ink-3)';
  const kAcc = dark ? '#e0563d' : 'var(--accent)';
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
      <div style={{ minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
          <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: kAcc, fontWeight: 700 }}>{c.d.firstName ? `${c.d.firstName}’s camp` : 'Your camp'}</span>
          <span style={{ width: 18, height: 1, background: kAcc, opacity: 0.45 }} />
          <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: sub, fontWeight: 600 }}>{c.d.sport} · {(c.d.division || c.d.sport)}</span>
        </div>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: sub, fontWeight: 600, marginTop: 8 }}>Fight night {c.FC.fightDateShort || 'Jan 1'} · weigh-in {c.weighShort}</div>
      </div>
      {c.glyph && window.SportGlyph && <div style={{ flexShrink: 0, marginTop: 1 }}><window.SportGlyph name={c.glyph} size={38} ink={dark ? '#faf7f1' : 'var(--ink)'} accent={dark ? '#e0563d' : 'var(--accent)'} /></div>}
    </div>
  );
}

function ReadBody({ c, dark, compact }) {
  if (!c.tip) return null;
  const ink = dark ? '#faf7f1' : 'var(--ink)';
  const ink2 = dark ? 'rgba(250,247,241,0.78)' : 'var(--ink-2)';
  return (
    <div>
      <div style={{ fontFamily: 'var(--sans)', fontSize: compact ? 19 : 21, fontWeight: 700, lineHeight: 1.24, letterSpacing: '-0.02em', color: ink, textWrap: 'balance' }}>{c.tip.headline}</div>
      {!compact && <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: ink2, marginTop: 9, textWrap: 'pretty' }}>{c.tip.body}</div>}
    </div>
  );
}

// the dominant cut figure — the focal point that fixes the flatness
function HeroCut({ c, dark, size = 76 }) {
  const d = c.d;
  const ink = dark ? '#faf7f1' : 'var(--ink)';
  const sub = dark ? 'rgba(250,247,241,0.6)' : 'var(--ink-3)';
  const acc = dark ? '#e0563d' : 'var(--accent)';
  return (
    <div style={{ textAlign: 'center' }}>
      <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: sub }}>{d.startW.toFixed(1)} → {d.targetW.toFixed(1)} kg make-weight</div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 8, marginTop: 6 }}>
        <span style={{ fontFamily: 'var(--num)', fontWeight: 200, fontSize: size, lineHeight: 1, letterSpacing: '-0.03em', color: ink }}>−{d.cut.toFixed(1)}</span>
        <span style={{ fontFamily: 'var(--display)', fontSize: 16, letterSpacing: '0.08em', fontWeight: 600, color: sub }}>KG</span>
      </div>
      <div style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: acc, fontWeight: 600, marginTop: 8 }}>in {d.weeks} weeks</div>
    </div>
  );
}

function CampStats({ c, cols, dark }) {
  const ink = dark ? '#faf7f1' : 'var(--ink)';
  const sub = dark ? 'rgba(250,247,241,0.55)' : 'var(--ink-3)';
  const rule = dark ? 'rgba(250,247,241,0.16)' : 'var(--rule)';
  const acc = dark ? '#e0563d' : 'var(--accent)';
  return (
    <div style={{ display: 'flex' }}>
      {cols.map((s, i) => (
        <div key={s.lb} style={{ flex: 1, paddingLeft: i ? 12 : 0, borderLeft: i ? `1px solid ${rule}` : 'none' }}>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 8.5, letterSpacing: '0.04em', textTransform: 'uppercase', color: sub, fontWeight: 600 }}>{s.lb}</div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 2, marginTop: 6 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 25, lineHeight: 1, letterSpacing: '-0.03em', color: s.accent ? acc : ink }}>{s.v}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 8.5, color: sub, fontWeight: 600 }}>{s.u}</span></div>
        </div>
      ))}
    </div>
  );
}
const STATS_3 = (c) => [
  { lb: 'Class limit', v: (c.equip ? (c.FC.maxWithGi || c.d.targetW) : c.d.targetW).toFixed(1), u: 'kg' },
  { lb: 'Body target', v: c.d.targetW.toFixed(1), u: 'kg', accent: true },
  { lb: 'Timeline', v: String(c.d.weeks), u: 'wks' },
];
const STATS_4 = (c) => [
  { lb: 'Class limit', v: (c.equip ? (c.FC.maxWithGi || c.d.targetW) : c.d.targetW).toFixed(1), u: 'kg' },
  { lb: 'Body target', v: c.d.targetW.toFixed(1), u: 'kg', accent: true },
  { lb: 'To lose', v: c.d.cut.toFixed(1), u: 'kg' },
  { lb: 'Timeline', v: String(c.d.weeks), u: 'wks' },
];

// plan block — collapsed locked + value-copy pending (the "set / to sharpen" beat)
function PlanBlock({ c, label = 'Your plan' }) {
  const total = c.included.length + c.pending.length;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 700 }}>{label}</div>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, fontWeight: 600, color: 'var(--ink-2)' }}><span style={{ color: 'var(--ink)', fontWeight: 700 }}>{c.included.length}</span> of {total} set</span>
      </div>
      <div style={{ marginTop: 12, marginBottom: 14 }}><ProgressBar done={c.included.length} total={total} /></div>
      <LockedSummary included={c.included} />
      <div style={{ marginTop: 16, marginBottom: 2 }}><GroupLabel color="var(--accent)">Sharpens once camp is set up</GroupLabel></div>
      {c.pending.map((it, i) => <SharpenRow key={i} t={it.t} s={it.s} tag={it.tag} first={i === 0} />)}
    </div>
  );
}

// plan as a tinted value block — locked in one line, pending value copy highlighted
function PlanValueBlock({ c }) {
  const total = c.included.length + c.pending.length;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
        <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: '50%', background: 'var(--green)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><svg width="9" height="7" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink)' }}>The {c.included.length} essentials are locked in</span>
      </div>
      <div style={{ marginTop: 12 }}><ProgressBar done={c.included.length} total={total} /></div>
      <div style={{ marginTop: 18, background: 'var(--accent-soft)', borderRadius: 'var(--radius)', padding: '15px 17px' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
          <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 700 }}>Sharpens in setup</span>
          <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.04em', color: 'var(--accent)', fontWeight: 600 }}>{c.pending.length} more</span>
        </div>
        <div style={{ marginTop: 4 }}>
          {c.pending.map((it, i) => <SharpenRow key={i} t={it.t} s={it.s} tag={it.tag} first={i === 0} />)}
        </div>
      </div>
    </div>
  );
}

// E1 · NUMBER LEADS — the −cut figure is the hero; read supports, chart proves.
function RevealE1() {
  const c = useCampData(); const d = c.d;
  const Rule = ({ m = 18 }) => <div style={{ height: 1, background: 'var(--rule)', margin: `${m}px 0` }} />;
  return (
    <RevealFrame label="Reveal · E1 · Number leads" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ padding: '22px 26px 24px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <MetaHeader c={c} />
        <div style={{ margin: '24px 0 8px' }}><HeroCut c={c} size={78} /></div>
        <Rule />
        <ReadBody c={c} />
        <Rule />
        <DescentChart c={c} />
        <div style={{ marginTop: 12 }}><PacedLine ratePct={d.ratePct} refineNote /></div>
        <Rule />
        <PlanBlock c={c} />
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// E2 · DARK HERO REMIX — dark band leads with meta + hero figure + read;
// the proof (stats, chart, plan) lands on paper. Strong figure-ground + focal.
function RevealE2() {
  const c = useCampData(); const d = c.d;
  return (
    <RevealFrame label="Reveal · E2 · Dark hero remix" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div style={{ background: '#15140f', color: '#faf7f1', padding: '24px 22px 26px', position: 'relative', overflow: 'hidden' }}>
          {c.glyph && window.SportGlyph && <div style={{ position: 'absolute', top: 70, right: -22, opacity: 0.1 }}><window.SportGlyph name={c.glyph} size={150} ink="#faf7f1" accent="#faf7f1" /></div>}
          <div style={{ position: 'relative' }}>
            <MetaHeader c={c} dark />
            <div style={{ margin: '24px 0 20px' }}><HeroCut c={c} dark size={74} /></div>
            <div style={{ height: 1, background: 'rgba(250,247,241,0.16)', marginBottom: 18 }} />
            <ReadBody c={c} dark />
          </div>
        </div>
        <div style={{ padding: '20px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <CampStats c={c} cols={STATS_3(c)} />
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <div>
            <DescentChart c={c} />
            <div style={{ marginTop: 12 }}><PacedLine ratePct={d.ratePct} refineNote /></div>
          </div>
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <PlanValueBlock c={c} />
        </div>
      </div>
    </RevealFrame>
  );
}

// E3 · PROOF CARD — read first; the numbers + chart live in one contained
// "proof" card (paper-2) to break the flat flow; plan as a tinted value block.
function RevealE3() {
  const c = useCampData(); const d = c.d;
  return (
    <RevealFrame label="Reveal · E3 · Proof card" footer={<PrimaryNext label="Unlock & finish setup" sub={`${c.pending.length} more inputs sharpen your plan.`} />}>
      <div style={{ padding: '22px 26px 24px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <MetaHeader c={c} />
        <div style={{ marginTop: 16 }}><ReadBody c={c} /></div>
        {/* contained proof card */}
        <div style={{ marginTop: 20, border: '1px solid var(--rule)', borderRadius: 'var(--radius)', background: 'var(--paper-2)', padding: '17px 17px 15px' }}>
          <CampStats c={c} cols={STATS_4(c)} />
          <div style={{ height: 1, background: 'var(--rule)', margin: '15px 0' }} />
          <DescentChart c={c} />
          <div style={{ marginTop: 12 }}><PacedLine ratePct={d.ratePct} refineNote /></div>
        </div>
        <div style={{ marginTop: 20 }}><PlanValueBlock c={c} /></div>
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// POLISHED DIRECTIONS (P-series) — built from the crit: one clear hero, a real
// type scale, minimal labels, the accent used with conviction, a confident
// chart that carries the numbers (shaded make-weight zone + annotated drop),
// and the plan collapsed to a locked-line + the value copy that sharpens it.
// ═══════════════════════════════════════════════════════════════════════════

// one sparse mono kicker — used sparingly so labels actually rank
function Kicker({ children, color = 'var(--ink-3)' }) {
  return <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.14em', textTransform: 'uppercase', color, fontWeight: 700 }}>{children}</span>;
}

// confident descent chart: shaded make-weight zone, annotated drop, endpoints
// labelled — so the numbers live ON the chart instead of repeating as stats.
function HeroGlide({ c, dark, width = 341, height = 184, annotate = true }) {
  const d = c.d;
  const W = width, H = height, padL = 16, padR = 16, padT = 40, padB = 30;
  const innerW = W - padL - padR, innerH = H - padT - padB;
  const drop = (d.startW - d.targetW) || 1;
  const x = (t) => padL + t * innerW;
  const y = (v) => padT + ((d.startW - v) / drop) * innerH;
  const sx = x(0), sy = y(d.startW), ex = x(1), ey = y(d.targetW);
  const mx = (sx + ex) / 2, my = (sy + ey) / 2;
  const lineD = `M ${sx} ${sy} L ${ex} ${ey}`;
  const areaD = `${lineD} L ${ex} ${padT + innerH} L ${sx} ${padT + innerH} Z`;
  const ink = dark ? '#faf7f1' : 'var(--ink)';
  const sub = dark ? 'rgba(250,247,241,0.55)' : 'var(--ink-3)';
  const acc = dark ? '#e0563d' : 'var(--accent)';
  const paper = dark ? '#15140f' : 'var(--paper)';
  const gid = dark ? 'hgD' : 'hgL';
  return (
    <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} style={{ display: 'block' }} role="img" aria-label={`Cut from ${d.startW} to ${d.targetW} kg over ${d.weeks} weeks`}>
      <defs><linearGradient id={gid} x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor={acc} stopOpacity={dark ? 0.3 : 0.16} /><stop offset="1" stopColor={acc} stopOpacity="0" /></linearGradient></defs>
      {/* make-weight zone */}
      <rect x={padL} y={ey} width={innerW} height={padT + innerH - ey} fill={acc} opacity={dark ? 0.1 : 0.06} />
      <line x1={padL} x2={W - padR} y1={ey} y2={ey} stroke={acc} strokeWidth="1" strokeDasharray="3 3" opacity="0.55" />
      <path d={areaD} fill={`url(#${gid})`} />
      <path d={lineD} fill="none" stroke={acc} strokeWidth="2.6" strokeLinecap="round" />
      <circle cx={sx} cy={sy} r="4.5" fill={ink} />
      <circle cx={ex} cy={ey} r="5.5" fill={acc} stroke={paper} strokeWidth="2" />
      {/* endpoint values */}
      <text x={sx} y={sy - 22} textAnchor="start" fontFamily="var(--mono)" fontSize="8" letterSpacing="0.08em" fill={sub} fontWeight="700">TODAY</text>
      <text x={sx} y={sy - 10} textAnchor="start" fontFamily="var(--num)" fontSize="14" fontWeight="500" fill={ink}>{d.startW.toFixed(1)}</text>
      <text x={ex} y={ey + 20} textAnchor="end" fontFamily="var(--mono)" fontSize="8" letterSpacing="0.08em" fill={acc} fontWeight="700">MAKE-WEIGHT</text>
      <text x={ex} y={ey - 12} textAnchor="end" fontFamily="var(--num)" fontSize="14" fontWeight="600" fill={acc}>{d.targetW.toFixed(1)}</text>
      {/* the single canonical drop annotation, on the line (off when the −cut figure is the hero elsewhere) */}
      {annotate && <text x={mx + 8} y={my - 8} textAnchor="start" fontFamily="var(--num)" fontSize="17" fontWeight="500" fill={ink}>−{d.cut.toFixed(1)} kg</text>}
      {annotate && <text x={mx + 8} y={my + 6} textAnchor="start" fontFamily="var(--mono)" fontSize="8" letterSpacing="0.06em" fill={sub} fontWeight="600">OVER {d.weeks} WEEKS</text>}
    </svg>
  );
}

// plan collapsed to a locked-line + the value copy that sharpens it
function PlanFooter({ c, dark }) {
  const total = c.included.length + c.pending.length;
  const ink = dark ? '#faf7f1' : 'var(--ink)';
  const ink2 = dark ? 'rgba(250,247,241,0.78)' : 'var(--ink-2)';
  const sub = dark ? 'rgba(250,247,241,0.55)' : 'var(--ink-3)';
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 15, fontWeight: 700, color: ink }}>Your plan</span>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, fontWeight: 600, color: ink2 }}><span style={{ color: ink, fontWeight: 700 }}>{c.included.length}</span> of {total} set</span>
      </div>
      <div style={{ marginTop: 11 }}><ProgressBar done={c.included.length} total={total} dark={dark} /></div>
      <div style={{ fontFamily: 'var(--sans)', fontSize: 12, color: sub, marginTop: 10, lineHeight: 1.45 }}>{c.included.map(i => i.t).join(' · ')} — locked.</div>
      <div style={{ marginTop: 17 }}>
        <Kicker color={dark ? '#e0563d' : 'var(--accent)'}>Sharpens once you set up camp</Kicker>
        <div style={{ marginTop: 7 }}>
          {c.pending.map((it, i) => <SharpenRow key={i} t={it.t} s={it.s} tag={it.tag} first={i === 0} />)}
        </div>
      </div>
    </div>
  );
}

// P1 · CINEMATIC — dark hero carries the read headline (dominant); the chart is
// the hero on paper. Read → chart → quiet plan.
// P1 colour themes — non-black hero grounds drawn from the OnWeight palette
const P1_THEMES = {
  clay:     { bg: '#8a2c1a', ink: '#fbeee6', sub: 'rgba(251,238,230,0.74)', kicker: '#f4b8a3' },
  forest:   { bg: '#21401d', ink: '#eef3e6', sub: 'rgba(238,243,230,0.74)', kicker: '#a6c992' },
  espresso: { bg: '#2c2620', ink: '#f6efe6', sub: 'rgba(246,239,230,0.74)', kicker: '#e0866a' },
  mustard:  { bg: '#473a18', ink: '#f7f0dd', sub: 'rgba(247,240,221,0.76)', kicker: '#edc878' },
};
function RevealP1({ theme = 'clay' }) {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  const TH = P1_THEMES[theme] || P1_THEMES.clay;
  return (
    <RevealFrame label={`Reveal · P1 · ${theme}`} footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {/* COLOUR HERO — the verdict */}
        <div style={{ background: TH.bg, color: TH.ink, padding: '24px 24px 28px' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
            <Kicker color={TH.kicker}>{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</Kicker>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: TH.sub, fontWeight: 600 }}>{d.sport} · {(d.division || d.sport)}</span>
              {c.glyph && window.SportGlyph && <window.SportGlyph name={c.glyph} size={28} ink={TH.ink} accent={TH.kicker} />}
            </div>
          </div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 27, fontWeight: 700, lineHeight: 1.18, letterSpacing: '-0.02em', color: TH.ink, marginTop: 18, textWrap: 'balance' }}>{c.tip.headline}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: TH.sub, marginTop: 12, textWrap: 'pretty' }}>{c.tip.body}</div>
        </div>
        {/* PAPER — chart hero + plan */}
        <div style={{ padding: '22px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div>
            <Kicker>The cut · {d.sport} {(d.division || '')}</Kicker>
            <div style={{ marginTop: 10 }}><HeroGlide c={c} width={349} /></div>
            <div style={{ marginTop: 10, fontFamily: 'var(--sans)', fontSize: 11.5, fontStyle: 'italic', color: 'var(--ink-3)', lineHeight: 1.45 }}>A starting cut — the pace tightens once you finish setting up camp.</div>
          </div>
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <PlanFooter c={c} />
        </div>
      </div>
    </RevealFrame>
  );
}

// P2 · THE NUMBER — the −cut figure is enormous and is the whole top of the
// screen; the read is one supporting line; the chart proves it underneath.
function RevealP2() {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  return (
    <RevealFrame label="Reveal · P2 · The number" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ padding: '24px 26px 24px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
          <Kicker color="var(--accent)">{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</Kicker>
          <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{d.sport} · {(d.division || d.sport)}</span>
            {c.glyph && window.SportGlyph && <window.SportGlyph name={c.glyph} size={26} ink="var(--ink)" accent="var(--accent)" />}
          </div>
        </div>
        {/* GIANT NUMBER */}
        <div style={{ textAlign: 'center', margin: '30px 0 4px' }}>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink-3)' }}>{d.startW.toFixed(1)} → {d.targetW.toFixed(1)} kg make-weight</div>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 10, marginTop: 6 }}>
            <span style={{ fontFamily: 'var(--num)', fontWeight: 200, fontSize: 104, lineHeight: 0.9, letterSpacing: '-0.04em', color: 'var(--ink)' }}>−{d.cut.toFixed(1)}</span>
            <span style={{ fontFamily: 'var(--display)', fontSize: 22, letterSpacing: '0.06em', fontWeight: 600, color: 'var(--ink-3)' }}>KG</span>
          </div>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, marginTop: 16, background: 'var(--accent)', borderRadius: 100, padding: '7px 15px' }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--paper)', fontWeight: 700 }}>{d.weeks} weeks · {d.ratePct.toFixed(2)}%/wk · under the safe line</span>
          </div>
        </div>
        {/* one-line read */}
        <div style={{ fontFamily: 'var(--sans)', fontSize: 18, fontWeight: 700, lineHeight: 1.3, letterSpacing: '-0.01em', color: 'var(--ink)', marginTop: 26, textWrap: 'balance' }}>{c.tip.headline}</div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 9, textWrap: 'pretty' }}>{c.tip.body}</div>
        {/* secondary chart */}
        <div style={{ height: 1, background: 'var(--rule)', margin: '22px 0 0' }} />
        <div style={{ marginTop: 18 }}><Kicker>Your descent to fight night</Kicker><div style={{ marginTop: 10 }}><HeroGlide c={c} width={341} height={168} /></div></div>
        <div style={{ fontFamily: 'var(--sans)', fontSize: 11.5, fontStyle: 'italic', color: 'var(--ink-3)', marginTop: 8 }}>A starting cut — the pace tightens once you finish setting up camp.</div>
        <div style={{ height: 1, background: 'var(--rule)', margin: '20px 0' }} />
        <PlanFooter c={c} />
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// P3 · BRIEFING CARD — the camp is one elevated object: a dark header strip +
// the read + the chart, contained in a card with depth. Plan sits on paper below.
function RevealP3() {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  return (
    <RevealFrame label="Reveal · P3 · Briefing card" footer={<PrimaryNext label="Unlock & finish setup" sub={`${c.pending.length} more inputs sharpen your plan.`} />}>
      <div style={{ padding: '20px 20px 24px', flex: 1, display: 'flex', flexDirection: 'column', gap: 20, background: 'var(--paper-2)' }}>
        {/* the camp card */}
        <div style={{ borderRadius: 18, overflow: 'hidden', border: '1px solid var(--rule)', boxShadow: '0 1px 2px rgba(21,20,15,0.05), 0 14px 30px rgba(21,20,15,0.10)' }}>
          {/* dark header strip */}
          <div style={{ background: '#15140f', color: '#faf7f1', padding: '17px 19px 16px', position: 'relative', overflow: 'hidden' }}>
            {c.glyph && window.SportGlyph && <div style={{ position: 'absolute', top: 12, right: -14, opacity: 0.12 }}><window.SportGlyph name={c.glyph} size={92} ink="#faf7f1" accent="#faf7f1" /></div>}
            <div style={{ position: 'relative' }}>
              <Kicker color="#e0563d">{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</Kicker>
              <div style={{ fontFamily: 'var(--display)', fontSize: 24, letterSpacing: '0.01em', fontWeight: 600, lineHeight: 1.02, color: '#faf7f1', marginTop: 8 }}>{(d.division || d.sport).toUpperCase()} · {d.sport.toUpperCase()}</div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'rgba(250,247,241,0.62)', fontWeight: 600, marginTop: 7 }}>Fight night {c.FC.fightDateShort || 'Jan 1'} · weigh-in {c.weighShort}</div>
            </div>
          </div>
          {/* body */}
          <div style={{ background: 'var(--paper)', padding: '18px 19px 17px' }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 18, fontWeight: 700, lineHeight: 1.3, letterSpacing: '-0.01em', color: 'var(--ink)', textWrap: 'balance' }}>{c.tip.headline}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13, lineHeight: 1.52, color: 'var(--ink-2)', marginTop: 8, textWrap: 'pretty' }}>{c.tip.body}</div>
            <div style={{ marginTop: 16 }}><HeroGlide c={c} width={313} height={176} /></div>
            <div style={{ marginTop: 10, fontFamily: 'var(--sans)', fontSize: 11.5, fontStyle: 'italic', color: 'var(--ink-3)', lineHeight: 1.45 }}>A starting cut — the pace tightens once you finish setting up camp.</div>
          </div>
        </div>
        {/* plan on paper */}
        <PlanFooter c={c} />
      </div>
    </RevealFrame>
  );
}

// boxing-poster crop marks (from the app's poster motif)
function CornerTicks({ color = 'var(--accent)', inset = 10, size = 11, stroke = 1.5 }) {
  const b = { position: 'absolute', width: size, height: size, pointerEvents: 'none' };
  return (
    <React.Fragment>
      <svg style={{ ...b, top: inset, left: inset }} viewBox="0 0 11 11"><path d="M0 0 H11 M0 0 V11" stroke={color} strokeWidth={stroke} fill="none" /></svg>
      <svg style={{ ...b, top: inset, right: inset }} viewBox="0 0 11 11"><path d="M11 0 H0 M11 0 V11" stroke={color} strokeWidth={stroke} fill="none" /></svg>
      <svg style={{ ...b, bottom: inset, left: inset }} viewBox="0 0 11 11"><path d="M0 11 H11 M0 11 V0" stroke={color} strokeWidth={stroke} fill="none" /></svg>
      <svg style={{ ...b, bottom: inset, right: inset }} viewBox="0 0 11 11"><path d="M11 11 H0 M11 11 V0" stroke={color} strokeWidth={stroke} fill="none" /></svg>
    </React.Fragment>
  );
}

// P4 · CLAY POSTER — warm clay banner + crop-marks + Oswald matchup, drawn from
// the HQ "warm clay poster" hero and the brand's tale-of-the-tape language.
function RevealClay() {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  return (
    <RevealFrame label="Reveal · Clay poster" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div style={{ background: '#e9ddcd', color: 'var(--ink)', padding: '24px 24px 26px', position: 'relative' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
            <span style={{ fontFamily: 'var(--display)', fontSize: 12, letterSpacing: '0.2em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{d.weeks} wks out</span>
              {c.glyph && window.SportGlyph && <window.SportGlyph name={c.glyph} size={28} ink="var(--ink)" accent="var(--accent)" />}
            </div>
          </div>
          <div style={{ fontFamily: 'var(--display)', fontSize: 30, letterSpacing: '0.01em', fontWeight: 600, lineHeight: 1.0, color: 'var(--ink)', marginTop: 15 }}>{(d.division || d.sport).toUpperCase()} · {d.sport.toUpperCase()}</div>
          <div style={{ height: 3, width: 58, background: 'var(--accent)', margin: '13px 0 15px' }} />
          <div style={{ fontFamily: 'var(--sans)', fontSize: 18, fontWeight: 700, lineHeight: 1.28, color: 'var(--ink)', textWrap: 'balance' }}>{c.tip.headline}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 9, textWrap: 'pretty' }}>{c.tip.body}</div>
        </div>
        <div style={{ padding: '22px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div>
            <Kicker>The cut · {d.sport} {(d.division || '')}</Kicker>
            <div style={{ marginTop: 10 }}><HeroGlide c={c} width={349} /></div>
            <div style={{ marginTop: 10, fontFamily: 'var(--sans)', fontSize: 11.5, fontStyle: 'italic', color: 'var(--ink-3)', lineHeight: 1.45 }}>A starting cut — the pace tightens once you finish setting up camp.</div>
          </div>
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <PlanFooter c={c} />
        </div>
      </div>
    </RevealFrame>
  );
}

// CLAY + NUMBER — clay poster banner with the giant −cut figure as the hero
// moment inside it; the read, chart and plan land on paper below.
function RevealClayNumber() {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  return (
    <RevealFrame label="Reveal · Clay + number" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {/* CLAY HERO with the giant number */}
        <div style={{ background: '#e9ddcd', color: 'var(--ink)', padding: '24px 24px 28px', position: 'relative' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
            <span style={{ fontFamily: 'var(--display)', fontSize: 12, letterSpacing: '0.2em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{d.sport} · {(d.division || d.sport)}</span>
              {c.glyph && window.SportGlyph && <window.SportGlyph name={c.glyph} size={28} ink="var(--ink)" accent="var(--accent)" />}
            </div>
          </div>
          <div style={{ fontFamily: 'var(--display)', fontSize: 22, letterSpacing: '0.02em', fontWeight: 600, color: 'var(--ink)', marginTop: 14 }}>{(d.division || d.sport).toUpperCase()} · {d.sport.toUpperCase()}</div>
          <div style={{ textAlign: 'center', marginTop: 16 }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600, color: 'var(--ink-3)' }}>{d.startW.toFixed(1)} → {d.targetW.toFixed(1)} kg make-weight</div>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 9, marginTop: 4 }}>
              <span style={{ fontFamily: 'var(--num)', fontWeight: 200, fontSize: 94, lineHeight: 0.9, letterSpacing: '-0.04em', color: 'var(--ink)' }}>−{d.cut.toFixed(1)}</span>
              <span style={{ fontFamily: 'var(--display)', fontSize: 20, letterSpacing: '0.06em', fontWeight: 600, color: 'var(--ink-3)' }}>KG</span>
            </div>
            <div style={{ display: 'inline-flex', alignItems: 'center', marginTop: 14, background: 'var(--accent)', borderRadius: 100, padding: '7px 15px' }}>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--paper)', fontWeight: 700 }}>{d.weeks} weeks · {d.ratePct.toFixed(2)}%/wk · under the safe line</span>
            </div>
          </div>
        </div>
        {/* paper: read + chart + plan */}
        <div style={{ padding: '22px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 18, fontWeight: 700, lineHeight: 1.3, letterSpacing: '-0.01em', color: 'var(--ink)', textWrap: 'balance' }}>{c.tip.headline}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 9, textWrap: 'pretty' }}>{c.tip.body}</div>
          </div>
          <div>
            <Kicker>Your descent to fight night</Kicker>
            <div style={{ marginTop: 10 }}><HeroGlide c={c} width={349} /></div>
            <div style={{ marginTop: 10, fontFamily: 'var(--sans)', fontSize: 11.5, fontStyle: 'italic', color: 'var(--ink-3)', lineHeight: 1.45 }}>A starting cut — the pace tightens once you finish setting up camp.</div>
          </div>
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <PlanFooter c={c} />
        </div>
      </div>
    </RevealFrame>
  );
}

// DASHBOARD STYLE — mirrors the app dashboard: status banner, a readout card
// (mono labels + tone badge + big number + inline chart), a metric grid, an
// analysis card. The reveal as the Today screen they're about to live in.
function RevealDash() {
  const c = useCampData(); const d = c.d;
  const Num = window.Num, ToneBadge = window.ToneBadge;
  const metrics = [
    { k: 'TO LOSE', v: '−' + d.cut.toFixed(1), u: 'kg', t: 'var(--accent)' },
    { k: 'SAFE PACE', v: d.ratePct.toFixed(2), u: '%/wk', t: 'var(--t-green)' },
    { k: 'TIMELINE', v: String(d.weeks), u: 'wks', t: 'var(--ink)' },
    { k: d.water ? 'REAL-WEIGHT BASE' : 'ALL REAL WEIGHT', v: (d.water ? d.campKg : d.cut).toFixed(1), u: 'kg', t: 'var(--ink)' },
  ];
  return (
    <RevealFrame label="Reveal · Dashboard style" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ padding: '6px 18px 24px', display: 'flex', flexDirection: 'column', gap: 14 }}>
        {/* status banner */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '4px 2px 2px' }}>
          <span style={{ flexShrink: 0, width: 38, height: 38, borderRadius: '50%', background: 'var(--t-green-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <svg width="16" height="12" viewBox="0 0 16 12" fill="none"><path d="M1.5 6.5 L6 11 L14.5 1.5" stroke="var(--t-green)" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 700, color: 'var(--ink)', letterSpacing: '-0.01em' }}>Your camp is ready.</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)' }}>{d.firstName ? d.firstName + ' · ' : ''}{d.sport} · {(d.division || d.sport)} · {d.weeks} wks out</div>
          </div>
        </div>
        {/* readout card */}
        <Card pad={18}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.18em', color: 'var(--ink-3)', fontWeight: 600 }}>MAKE-WEIGHT TARGET</span>
            {ToneBadge ? <ToneBadge tone="green">SAFE PACE</ToneBadge> : null}
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 12, marginTop: 12 }}>
            {Num ? <Num size={72} weight={300} color="var(--ink)">{d.targetW.toFixed(1)}</Num> : <span style={{ fontFamily: 'var(--num)', fontSize: 72 }}>{d.targetW.toFixed(1)}</span>}
            <div style={{ paddingBottom: 9 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 13, color: 'var(--ink-3)', fontWeight: 600 }}>KG</div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--accent)', fontWeight: 700, marginTop: 5 }}>−{d.cut.toFixed(1)} FROM TODAY</div>
            </div>
          </div>
          <div style={{ marginTop: 12, borderTop: '1px solid var(--rule)', paddingTop: 12 }}>
            <HeroGlide c={c} width={315} height={150} />
          </div>
        </Card>
        {/* metric grid */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          {metrics.map(m => (
            <div key={m.k} style={{ background: 'var(--paper)', border: '1px solid var(--rule)', borderRadius: 'var(--radius)', padding: '14px 15px', position: 'relative', overflow: 'hidden' }}>
              <span style={{ position: 'absolute', top: 0, left: 0, width: 3, height: '100%', background: m.t, opacity: 0.5 }} />
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.13em', color: 'var(--ink-3)', fontWeight: 600 }}>{m.k}</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 9 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 400, fontSize: 26, letterSpacing: '-0.02em', color: m.t }}>{m.v}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>{m.u}</span></div>
            </div>
          ))}
        </div>
        {/* analysis card */}
        {c.tip && (
          <div style={{ background: 'var(--paper)', border: '1px solid var(--rule)', borderRadius: 'var(--radius)', padding: '15px 16px', borderLeft: '3px solid var(--accent)' }}>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.16em', color: 'var(--ink-3)', fontWeight: 600 }}>COACH’S READ</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 15.5, fontWeight: 600, color: 'var(--ink)', marginTop: 8, textWrap: 'balance' }}>{c.tip.headline}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'var(--ink-2)', lineHeight: 1.5, marginTop: 6, textWrap: 'pretty' }}>{c.tip.body}</div>
          </div>
        )}
        <div style={{ height: 1, background: 'var(--rule)' }} />
        <PlanFooter c={c} />
      </div>
    </RevealFrame>
  );
}

// PLAN STYLE — mirrors the in-app Plan screen: "About this camp" hero card,
// "Your cut" card + descent, the CoachTip read, then grouped-list rows for the
// plan (locked, with values) and what sharpens in setup.
function RevealPlan() {
  const c = useCampData(); const d = c.d;
  const SH = window.SectionHeader, GL = window.GroupedList, Row = window.Row;
  const cuts = [['To lose', d.cut.toFixed(1), 'kg'], ['Timeline', String(d.weeks), 'wks'], ['Pace', (d.cut / d.weeks).toFixed(2), 'kg/wk']];
  const check = <svg width="13" height="10" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="var(--t-green)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>;
  return (
    <RevealFrame label="Reveal · Plan style" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ padding: '6px 20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div>
          <Kicker color="var(--accent)">{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</Kicker>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 24, fontWeight: 700, letterSpacing: '-0.02em', color: 'var(--ink)', marginTop: 8 }}>Your camp is ready.</div>
        </div>
        {/* About this camp */}
        <Card pad={22}>
          {c.glyph && window.SportGlyph && <div style={{ position: 'absolute', top: 20, right: 20 }}><window.SportGlyph name={c.glyph} size={34} ink="var(--ink)" accent="var(--accent)" /></div>}
          <Eyebrow color="var(--accent)">About this camp</Eyebrow>
          <div style={{ fontFamily: 'var(--display)', fontSize: 28, letterSpacing: '0.01em', fontWeight: 600, marginTop: 9, color: 'var(--ink)' }}>{(d.division || d.sport).toUpperCase()} · {d.sport.toUpperCase()}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 14, color: 'var(--ink-2)', marginTop: 8 }}>Fight night {c.FC.fightDateShort || 'Jan 1'}, 2026 · weigh-in {c.weighPhrase}.</div>
          <div style={{ height: 1, background: 'var(--rule)', margin: '18px 0 16px' }} />
          <div style={{ display: 'flex' }}>
            {c.equip
              ? <Stat label="Class limit" value={(c.FC.maxWithGi || d.targetW).toFixed(1)} unit="kg" sub="in gear" i={0} />
              : <Stat label="Class limit" value={d.targetW.toFixed(1)} unit="kg" sub="on the scale" i={0} />}
            <Stat label="Body target" value={d.targetW.toFixed(1)} unit="kg" color="var(--accent)" sub={c.equip ? `−${c.S.equipmentKg} gear` : 'underwear'} i={1} />
          </div>
        </Card>
        {/* Your cut */}
        <Card pad={20}>
          <Eyebrow color="var(--accent)">Your cut</Eyebrow>
          <div style={{ display: 'flex', marginTop: 12, marginBottom: 4 }}>
            {cuts.map(([lb, v, u], i) => (
              <div key={lb} style={{ flex: 1, paddingLeft: i ? 16 : 0, borderLeft: i ? '1px solid var(--rule)' : 'none' }}>
                <div style={{ fontFamily: 'var(--sans)', fontSize: 11, fontWeight: 600, color: 'var(--ink-3)' }}>{lb}</div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 6 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 26, letterSpacing: '-0.02em', color: i === 0 ? 'var(--accent)' : 'var(--ink)' }}>{v}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, color: 'var(--ink-3)', fontWeight: 600 }}>{u}</span></div>
              </div>
            ))}
          </div>
          <div style={{ marginTop: 16, paddingTop: 14, borderTop: '1px solid var(--rule)' }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink-2)' }}>Your descent to fight day</div>
            <div style={{ marginTop: 12 }}><HeroGlide c={c} width={291} /></div>
          </div>
        </Card>
        {c.tip && <CoachTip chip={`${d.sport} · ${c.chipTier}`} headline={c.tip.headline} body={c.tip.body} tone={d.water ? 'accent' : 'amber'} coach />}
        {/* plan as grouped lists */}
        {SH && GL && Row && (
          <React.Fragment>
            <div>
              <SH>In your camp</SH>
              <GL>
                {c.included.map((it, i) => <Row key={i} label={it.t} value={check} note={it.s} chevron={false} last={i === c.included.length - 1} />)}
              </GL>
            </div>
            <div>
              <SH>Sharpens in setup</SH>
              <GL>
                {c.pending.map((it, i) => <Row key={i} label={it.t} value={<span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 700 }}>{it.tag || 'To set'}</span>} note={it.s} chevron={false} last={i === c.pending.length - 1} />)}
              </GL>
            </div>
          </React.Fragment>
        )}
      </div>
    </RevealFrame>
  );
}

// plan as a scannable list — locked items get a green check + their value;
// the sharpen items keep their value copy. Replaces the dense run-on line.
function PlanList({ c }) {
  const total = c.included.length + c.pending.length;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 15, fontWeight: 700, color: 'var(--ink)' }}>Your plan</span>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, fontWeight: 600, color: 'var(--ink-2)' }}><span style={{ color: 'var(--ink)', fontWeight: 700 }}>{c.included.length}</span> of {total} set</span>
      </div>
      <div style={{ marginTop: 11, marginBottom: 4 }}><ProgressBar done={c.included.length} total={total} /></div>
      <div>
        {c.included.map((it, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '9px 0', borderTop: i ? '1px solid var(--rule)' : 'none' }}>
            <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: '50%', background: 'var(--t-green-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><svg width="10" height="8" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="var(--t-green)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
            <span style={{ flex: 1, minWidth: 0, fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 600, color: 'var(--ink)' }}>{it.t}</span>
            <span style={{ flexShrink: 0, fontFamily: 'var(--sans)', fontSize: 12, color: 'var(--ink-3)', textAlign: 'right', maxWidth: '46%' }}>{it.s}</span>
          </div>
        ))}
      </div>
      <div style={{ marginTop: 16, marginBottom: 2 }}><Kicker color="var(--accent)">Sharpens once you set up camp</Kicker></div>
      {c.pending.map((it, i) => <SharpenRow key={i} t={it.t} s={it.s} tag={it.tag} first={i === 0} />)}
    </div>
  );
}

// NEW A · CLAY + CHECKLIST — clay hero carries the −cut figure once; the chart
// shows only the endpoints (no repeat); the plan is the scannable green-check list.
function RevealClayList() {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  return (
    <RevealFrame label="Reveal · Clay + checklist" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {/* clay hero — the number lives here, once */}
        <div style={{ background: '#e9ddcd', color: 'var(--ink)', padding: '24px 24px 26px', position: 'relative' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
            <span style={{ fontFamily: 'var(--display)', fontSize: 12, letterSpacing: '0.2em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{(d.division || d.sport)} · {d.sport}</span>
              {c.glyph && window.SportGlyph && <window.SportGlyph name={c.glyph} size={28} ink="var(--ink)" accent="var(--accent)" />}
            </div>
          </div>
          <div style={{ textAlign: 'center', marginTop: 16 }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600, color: 'var(--ink-3)' }}>{d.startW.toFixed(1)} → {d.targetW.toFixed(1)} kg make-weight</div>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 9, marginTop: 4 }}>
              <span style={{ fontFamily: 'var(--num)', fontWeight: 200, fontSize: 90, lineHeight: 0.9, letterSpacing: '-0.04em', color: 'var(--ink)' }}>−{d.cut.toFixed(1)}</span>
              <span style={{ fontFamily: 'var(--display)', fontSize: 20, letterSpacing: '0.06em', fontWeight: 600, color: 'var(--ink-3)' }}>KG</span>
            </div>
            <div style={{ display: 'inline-flex', marginTop: 13, background: 'var(--accent)', borderRadius: 100, padding: '7px 15px' }}>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--paper)', fontWeight: 700 }}>{d.weeks} weeks · {d.ratePct.toFixed(2)}%/wk · under the safe line</span>
            </div>
          </div>
        </div>
        {/* paper */}
        <div style={{ padding: '20px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 18, fontWeight: 700, lineHeight: 1.3, letterSpacing: '-0.01em', color: 'var(--ink)', textWrap: 'balance' }}>{c.tip.headline}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 9, textWrap: 'pretty' }}>{c.tip.body}</div>
          </div>
          <div>
            <Kicker>Your descent to fight night</Kicker>
            <div style={{ marginTop: 10 }}><HeroGlide c={c} width={349} annotate={false} /></div>
          </div>
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <PlanList c={c} />
        </div>
      </div>
    </RevealFrame>
  );
}

// NEW B · TICKET — the camp as a single fight-ticket / weigh-in card: clay stub
// with the matchup + −cut, a tear-line, then the plan as receipt line items.
function RevealTicket() {
  const c = useCampData(); const d = c.d;
  if (!c.tip) return null;
  const total = c.included.length + c.pending.length;
  const Perf = () => (
    <div style={{ position: 'relative', height: 18, background: '#e9ddcd' }}>
      <div style={{ position: 'absolute', left: 12, right: 12, top: 8, borderTop: '2px dashed color-mix(in srgb, var(--ink) 26%, transparent)' }} />
      <div style={{ position: 'absolute', left: -9, top: -1, width: 18, height: 18, borderRadius: '50%', background: 'var(--paper-2)' }} />
      <div style={{ position: 'absolute', right: -9, top: -1, width: 18, height: 18, borderRadius: '50%', background: 'var(--paper-2)' }} />
    </div>
  );
  return (
    <RevealFrame label="Reveal · Ticket" footer={<PrimaryNext label="See my full plan" sub="Your camp is ready — yours to keep." />}>
      <div style={{ padding: '18px 18px 22px', flex: 1, display: 'flex', flexDirection: 'column', gap: 16, background: 'var(--paper-2)' }}>
        <div style={{ borderRadius: 16, overflow: 'hidden', boxShadow: '0 1px 2px rgba(21,20,15,0.06), 0 16px 34px rgba(21,20,15,0.10)' }}>
          {/* clay stub */}
          <div style={{ background: '#e9ddcd', color: 'var(--ink)', padding: '18px 20px 16px' }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
              <span style={{ fontFamily: 'var(--display)', fontSize: 11.5, letterSpacing: '0.2em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>{d.firstName ? `${d.firstName}’s camp` : 'Your camp'}</span>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{d.weeks} wks · {(d.division || d.sport)}</span>
            </div>
            <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 12, marginTop: 12 }}>
              <div>
                <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>Make weight</div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 4 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 40, lineHeight: 0.9, letterSpacing: '-0.03em', color: 'var(--ink)' }}>{d.targetW.toFixed(1)}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>kg</span></div>
              </div>
              <div style={{ textAlign: 'right' }}>
                <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>The cut</div>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'flex-end', gap: 4, marginTop: 4 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 40, lineHeight: 0.9, letterSpacing: '-0.03em', color: 'var(--accent)' }}>−{d.cut.toFixed(1)}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>kg</span></div>
              </div>
            </div>
          </div>
          <Perf />
          {/* receipt body */}
          <div style={{ background: 'var(--paper)', padding: '16px 20px 18px' }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 15.5, fontWeight: 700, lineHeight: 1.3, color: 'var(--ink)', textWrap: 'balance' }}>{c.tip.headline}</div>
            <div style={{ marginTop: 14 }}><HeroGlide c={c} width={313} height={150} annotate={false} /></div>
            <div style={{ marginTop: 14, paddingTop: 14, borderTop: '1px dashed var(--rule-2)' }}>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 700 }}>Your plan</span>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.05em', color: 'var(--ink-3)', fontWeight: 600 }}>{c.included.length} / {total} set</span>
              </div>
              <div style={{ marginTop: 10 }}>
                {c.included.map((it, i) => (
                  <div key={i} style={{ display: 'flex', alignItems: 'baseline', gap: 8, padding: '7px 0' }}>
                    <span style={{ flexShrink: 0, color: 'var(--t-green)', fontFamily: 'var(--sans)', fontWeight: 700, fontSize: 13 }}>✓</span>
                    <span style={{ fontFamily: 'var(--sans)', fontSize: 13.5, color: 'var(--ink)', fontWeight: 600 }}>{it.t}</span>
                    <span style={{ flex: 1, alignSelf: 'center', borderBottom: '1px dotted var(--rule-2)', opacity: 0.7, margin: '0 3px' }} />
                    <span style={{ flexShrink: 0, fontFamily: 'var(--sans)', fontSize: 12, color: 'var(--ink-3)' }}>{it.s}</span>
                  </div>
                ))}
                {c.pending.map((it, i) => (
                  <div key={'p' + i} style={{ display: 'flex', alignItems: 'baseline', gap: 8, padding: '7px 0' }}>
                    <span style={{ flexShrink: 0, color: 'var(--ink-3)', fontFamily: 'var(--sans)', fontWeight: 700, fontSize: 13 }}>○</span>
                    <span style={{ fontFamily: 'var(--sans)', fontSize: 13.5, color: 'var(--ink-2)', fontWeight: 600 }}>{it.t}</span>
                    <span style={{ flex: 1, alignSelf: 'center', borderBottom: '1px dotted var(--rule-2)', opacity: 0.7, margin: '0 3px' }} />
                    <span style={{ flexShrink: 0, fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 700 }}>{it.tag || 'in setup'}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// B · BOLD COVER — dark inverted hero carries coach's read + the matchup;
// the cut + plan land on paper below. High figure-ground contrast.
function RevealCampB() {
  const c = useCampData(); const d = c.d;
  const total = c.included.length + c.pending.length;
  const ACC = '#e0563d';
  const cuts = [['To lose', d.cut.toFixed(1), 'kg'], ['Timeline', String(d.weeks), 'wks'], ['Pace', (d.cut / d.weeks).toFixed(2), 'kg/wk']];
  return (
    <RevealFrame label="Reveal · Your Camp — B · Bold cover" footer={<PrimaryNext sub="Your camp is ready — yours to keep." />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {/* DARK HERO — coach's read + matchup */}
        <div style={{ background: '#15140f', color: '#faf7f1', padding: '26px 22px 28px', position: 'relative', overflow: 'hidden' }}>
          {c.glyph && window.SportGlyph && <div style={{ position: 'absolute', top: 20, right: -8, opacity: 0.13 }}><window.SportGlyph name={c.glyph} size={132} ink="#faf7f1" accent="#faf7f1" /></div>}
          {c.tip && (
            <div style={{ position: 'relative' }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', color: ACC, fontWeight: 700 }}>Coach’s read · {d.sport} · {c.chipTier}</div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 23, fontWeight: 700, lineHeight: 1.22, letterSpacing: '-0.02em', color: '#faf7f1', marginTop: 13, textWrap: 'balance' }}>{c.tip.headline}</div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.58, color: 'rgba(250,247,241,0.78)', marginTop: 11, textWrap: 'pretty' }}>{c.tip.body}</div>
            </div>
          )}
          <div style={{ height: 1, background: 'rgba(250,247,241,0.16)', margin: '20px 0 18px' }} />
          <div style={{ fontFamily: 'var(--display)', fontSize: 30, letterSpacing: '0.01em', fontWeight: 600, lineHeight: 1.02, color: '#faf7f1' }}>{(d.division || d.sport).toUpperCase()} · {d.sport.toUpperCase()}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'rgba(250,247,241,0.7)', marginTop: 6 }}>Fight night {c.FC.fightDateShort || 'Jan 1'} · weigh-in {c.weighShort}</div>
          <div style={{ display: 'flex', marginTop: 18, gap: 0 }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'rgba(250,247,241,0.55)', fontWeight: 600 }}>Class limit</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 8 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 40, lineHeight: 1, letterSpacing: '-0.03em', color: '#faf7f1' }}>{(c.equip ? (c.FC.maxWithGi || d.targetW) : d.targetW).toFixed(1)}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'rgba(250,247,241,0.55)', fontWeight: 600 }}>kg</span></div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 11.5, color: 'rgba(250,247,241,0.55)', marginTop: 6 }}>{c.equip ? 'in gear' : 'on the scale'}</div>
            </div>
            <div style={{ width: 1, background: 'rgba(250,247,241,0.16)', margin: '4px 0' }} />
            <div style={{ flex: 1, paddingLeft: 22 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'rgba(250,247,241,0.55)', fontWeight: 600 }}>Body target</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 8 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 40, lineHeight: 1, letterSpacing: '-0.03em', color: ACC }}>{d.targetW.toFixed(1)}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'rgba(250,247,241,0.55)', fontWeight: 600 }}>kg</span></div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 11.5, color: 'rgba(250,247,241,0.55)', marginTop: 6 }}>{c.equip ? `−${c.S.equipmentKg} gear` : 'underwear'}</div>
            </div>
          </div>
        </div>
        {/* PAPER — cut + plan */}
        <div style={{ padding: '20px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div>
            <Eyebrow color="var(--accent)">Your cut</Eyebrow>
            <div style={{ display: 'flex', marginTop: 12 }}>
              {cuts.map(([lb, v, u], i) => (
                <div key={lb} style={{ flex: 1, paddingLeft: i ? 14 : 0, borderLeft: i ? '1px solid var(--rule)' : 'none' }}>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 3 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 27, letterSpacing: '-0.02em', color: i === 0 ? 'var(--accent)' : 'var(--ink)' }}>{v}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 9, color: 'var(--ink-3)', fontWeight: 600 }}>{u}</span></div>
                  <div style={{ fontFamily: 'var(--sans)', fontSize: 11, color: 'var(--ink-3)', marginTop: 5 }}>{lb}</div>
                </div>
              ))}
            </div>
            <div style={{ margin: '16px 0 14px' }}>{window.PlanGlide && <window.PlanGlide startW={d.startW} targetW={d.targetW} campWeeks={d.weeks} todayWeek={0} water={d.water} width={345} />}</div>
            <PacedLine ratePct={d.ratePct} refineNote />
          </div>
          <div style={{ height: 1, background: 'var(--rule)' }} />
          <div>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
              <Eyebrow color="var(--accent)">Your plan</Eyebrow>
              <span style={{ fontFamily: 'var(--sans)', fontSize: 12.5, fontWeight: 600, color: 'var(--ink-2)' }}><span style={{ color: 'var(--ink)', fontWeight: 700 }}>{c.included.length}</span> of {total} set</span>
            </div>
            <div style={{ marginTop: 12, marginBottom: 6 }}><ProgressBar done={c.included.length} total={total} /></div>
            {c.included.map((it, i) => <CheckRow key={'i' + i} done t={it.t} s={it.s} />)}
            <div style={{ marginTop: 12, marginBottom: 2 }}><GroupLabel color="var(--accent)">Sharpens in setup</GroupLabel></div>
            {c.pending.map((it, i) => <CheckRow key={'p' + i} done={false} t={it.t} s={it.s} tag={it.tag} last={i === c.pending.length - 1} />)}
          </div>
        </div>
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

// C · DOSSIER — technical / tabular. Mono labels, spec rows, segmented status.
function RevealCampC() {
  const c = useCampData(); const d = c.d;
  const total = c.included.length + c.pending.length;
  const doneN = c.included.length;
  const HeaderBar = ({ children, right }) => (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, background: 'var(--ink)', padding: '8px 13px' }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.13em', textTransform: 'uppercase', color: 'var(--paper)', fontWeight: 600 }}>{children}</span>
      {right && <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.06em', color: 'rgba(250,247,241,0.6)', fontWeight: 600 }}>{right}</span>}
    </div>
  );
  const Block = ({ children }) => <div style={{ border: '1px solid var(--ink)', borderRadius: 4, overflow: 'hidden' }}>{children}</div>;
  const cuts = [['To lose', d.cut.toFixed(1), 'kg'], ['Timeline', String(d.weeks), 'wks'], ['Pace', (d.cut / d.weeks).toFixed(2), 'kg/wk']];
  return (
    <RevealFrame label="Reveal · Your Camp — C · Dossier" footer={<PrimaryNext label="Unlock & finish setup" sub={`${total - doneN} more inputs sharpen your plan in setup.`} />}>
      <div style={{ padding: '16px 18px 24px', flex: 1, display: 'flex', flexDirection: 'column', gap: 13 }}>
        {/* dossier masthead */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, paddingBottom: 11, borderBottom: '2px solid var(--ink)' }}>
          <div>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>Camp dossier</div>
            <div style={{ fontFamily: 'var(--display)', fontSize: 22, letterSpacing: '0.02em', fontWeight: 600, color: 'var(--ink)', marginTop: 3 }}>{(d.division || d.sport).toUpperCase()} · {d.sport.toUpperCase()}</div>
          </div>
          {c.glyph && window.SportGlyph && <window.SportGlyph name={c.glyph} size={38} ink="var(--ink)" accent="var(--accent)" />}
        </div>
        {/* COACH'S READ — bordered callout, left accent bar */}
        {c.tip && (
          <div style={{ borderLeft: '3px solid var(--accent)', background: 'var(--accent-soft)', padding: '14px 16px', borderRadius: '0 4px 4px 0' }}>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 700 }}>Coach’s read // {d.sport} · {c.chipTier}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 700, lineHeight: 1.28, color: 'var(--ink)', marginTop: 9, textWrap: 'balance' }}>{c.tip.headline}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13, lineHeight: 1.52, color: 'var(--ink-2)', marginTop: 7, textWrap: 'pretty' }}>{c.tip.body}</div>
          </div>
        )}
        {/* ABOUT — spec table */}
        <Block>
          <HeaderBar right={`FIGHT ${(c.FC.fightDateShort || 'JAN 1').toUpperCase()}`}>About this camp</HeaderBar>
          <div style={{ padding: '4px 14px 8px' }}>
            <SpecRow k="Class limit" v={`${(c.equip ? (c.FC.maxWithGi || d.targetW) : d.targetW).toFixed(1)} kg`} />
            <SpecRow k="Body target" v={`${d.targetW.toFixed(1)} kg`} accent />
            <SpecRow k="Gear" v={c.equip ? `${c.S.equipmentKg} kg` : 'none'} />
            <SpecRow k="Weigh-in" v={c.weighShort} last />
          </div>
        </Block>
        {/* CUT — tabular + chart */}
        <Block>
          <HeaderBar right={`${d.weeks} WKS`}>Your cut</HeaderBar>
          <div style={{ padding: '14px 14px 12px' }}>
            <div style={{ display: 'flex' }}>
              {cuts.map(([lb, v, u], i) => (
                <div key={lb} style={{ flex: 1, paddingLeft: i ? 13 : 0, borderLeft: i ? '1px solid var(--rule)' : 'none' }}>
                  <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>{lb}</div>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 6 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 26, letterSpacing: '-0.02em', color: i === 0 ? 'var(--accent)' : 'var(--ink)' }}>{v}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 9, color: 'var(--ink-3)', fontWeight: 600 }}>{u}</span></div>
                </div>
              ))}
            </div>
            <div style={{ margin: '14px 0 12px' }}>{window.PlanGlide && <window.PlanGlide startW={d.startW} targetW={d.targetW} campWeeks={d.weeks} todayWeek={0} water={d.water} width={319} />}</div>
            <PacedLine ratePct={d.ratePct} refineNote />
          </div>
        </Block>
        {/* PLAN STATUS — segmented + numbered rows */}
        <Block>
          <HeaderBar right={`${doneN} / ${total} SET`}>Plan status</HeaderBar>
          <div style={{ padding: '14px 14px 6px' }}>
            <Seg total={total} done={doneN} />
            <div style={{ marginTop: 14 }}>
              {[...c.included.map(it => ({ ...it, done: true })), ...c.pending.map(it => ({ ...it, done: false }))].map((it, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '10px 0', borderTop: i ? '1px solid var(--rule)' : 'none' }}>
                  <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600, width: 18, flexShrink: 0 }}>{String(i + 1).padStart(2, '0')}</span>
                  <span style={{ flexShrink: 0, width: 17, height: 17, borderRadius: 3, display: 'flex', alignItems: 'center', justifyContent: 'center', background: it.done ? 'var(--accent)' : 'transparent', border: it.done ? 'none' : '1.5px solid var(--rule-2)' }}>{it.done && <svg width="9" height="7" viewBox="0 0 11 9" fill="none"><path d="M1 4.5 L4 7.5 L10 1" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>}</span>
                  <span style={{ flex: 1, minWidth: 0, fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 600, color: it.done ? 'var(--ink)' : 'var(--ink-2)' }}>{it.t}</span>
                  {it.tag && <span style={{ fontFamily: 'var(--mono)', fontSize: 8, letterSpacing: '0.05em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--ink-3)', border: '1px solid var(--rule)', borderRadius: 100, padding: '2px 7px', flexShrink: 0 }}>{it.tag}</span>}
                </div>
              ))}
            </div>
          </div>
        </Block>
        <div style={{ flex: 1 }} />
      </div>
    </RevealFrame>
  );
}

Object.assign(window, {
  RevealClayList, RevealTicket, RevealClay, RevealClayNumber, RevealDash, RevealPlan, RevealP1, RevealP2, RevealCampA, RevealCampA3, RevealE1, RevealE2, RevealE3, RevealCampB, RevealCampC, RevealRefine, RefineTeaser, CheckRow,
  PaywallRoadmap, PaywallVerdict, PostPaywallActivation,
  RevealLabPaceMeter: PaceMeter,
  // shared helpers for sibling reveal files (separate babel scope → must go via window)
  useCampData, RevealFrame, PrimaryNext, HeroGlide, Kicker, ProgressBar, PlanList,
});
