// fc-dash.jsx, four DISTINCT dashboard designs, one per visual direction.
// Dispatched by theme flag `layout`. Each is a different composition & UI
// language, not a recolor: Editorial (cards), Clean iOS (summary + rings +
// grouped list), Retro Fighter (fight-poster scoreboard + tale of the tape),
// Elite Lab (light instrument readout + metric grid + sparkline).

const { FC, TONE, computePace, Phone, Eyebrow, Num, ToneBadge, HeroMotif, CornerTicks,
        Card, SectionHeader, StatusBar, HomeIndicator, LargeTitle, GearButton,
        TabBar, PrimaryButton, TextButton, FCChart, FCHealthChart, FCHealthCard, getStyle } = window;

const dToday = (p) => p.hist[p.hist.length - 1][1];
const dDelta = (p) => +(dToday(p) - p.hist[p.hist.length - 2][1]).toFixed(1);

// Disclosure chevron, the consistent "this card opens a detail view" affordance.
function Disc() {
  return <svg width="8" height="13" viewBox="0 0 8 13" fill="none" aria-hidden="true"><path d="M1.5 1 L6.5 6.5 L1.5 12" stroke="var(--rule-2)" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>;
}

// ════════════════════════════════════════════════════════════════════════════
// EDITORIAL (paper), the original: warm white cards, Oswald eyebrows, verdict.
// ════════════════════════════════════════════════════════════════════════════
function DashEditorial({ styleKey, paceKey }) {
  const p = computePace(paceKey), tone = TONE[p.tone];
  const today = dToday(p), d = dDelta(p), down = d <= 0;
  const weekTarget = 0.45, weekLoss = Math.abs(p.weeklyVel);
  const Mini = ({ k, v, c = 'var(--ink)', i = 0 }) => (
    <div style={{ flex: 1, paddingLeft: i ? 16 : 0, borderLeft: i ? '1px solid var(--rule)' : 'none' }}>
      <Eyebrow color="var(--ink-3)" style={{ fontSize: 10 }}>{k}</Eyebrow>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 7 }}><Num size={22} color={c}>{v}</Num><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>kg</span></div>
    </div>
  );
  return (
    <Phone styleKey={styleKey} label="Dashboard">
      <StatusBar />
      <LargeTitle eyebrow={`OnWeight · Round ${FC.todayDay}/${FC.campDays}`} title={`Hi, ${FC.firstName}`} trailing={<GearButton />} />
      <div style={{ flex: 1, padding: '4px 20px 26px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <Card pad={22}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
            <Eyebrow style={{ minWidth: 0 }}>Today · Fasted 06:18</Eyebrow>
            <span style={{ flexShrink: 0 }}><ToneBadge tone={p.tone}>{p.badge}</ToneBadge></span>
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 9, marginTop: 18 }}>
            <Num size={84} style={{ lineHeight: 0.9 }}>{today.toFixed(1)}</Num>
            <span style={{ fontFamily: 'var(--sans)', fontSize: 23, fontWeight: 600, color: 'var(--ink-3)', letterSpacing: '-0.01em' }}>kg</span>
          </div>
          <div style={{ marginTop: 10, fontFamily: 'var(--sans)', fontSize: 13.5, color: 'var(--ink-2)', fontWeight: 500 }}>
            <span style={{ color: down ? 'var(--t-green)' : 'var(--ink-2)', fontWeight: 600 }}>{down ? '\u2193' : '\u2191'} {Math.abs(d).toFixed(1)} kg</span> since yesterday
          </div>
          <div style={{ height: 1, background: 'var(--rule)', margin: '18px 0' }} />
          <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={{ width: 22, height: 22, background: 'var(--accent)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><svg width="11" height="11" viewBox="0 0 10 10" fill="none"><line x1="5" y1="1.5" x2="5" y2="8.5" stroke="#fff" strokeWidth="1.6" strokeLinecap="round"/><line x1="1.5" y1="5" x2="8.5" y2="5" stroke="#fff" strokeWidth="1.6" strokeLinecap="round"/></svg></span>
            <span style={{ fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600, whiteSpace: 'nowrap' }}>Log today's weight</span>
          </button>
        </Card>
        <div>
          <SectionHeader trailing={<Disc />}>Today’s read</SectionHeader>
          <Card pad={18}>
          <div style={{ display: 'flex', gap: 12, alignItems: 'stretch' }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 17, fontWeight: 600, lineHeight: 1.25, color: 'var(--ink)', textWrap: 'balance' }}>{p.state.verdict}</div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.5, color: 'var(--ink-2)', marginTop: 7, textWrap: 'pretty' }}>{p.state.line}</div>
            </div>
          </div>
          <div style={{ height: 1, background: 'var(--rule)', margin: '15px 0 14px' }} />
          <div style={{ display: 'flex' }}>
            <Mini k="Fight-day limit" v={FC.goalWeight.toFixed(1)} c="var(--accent)" />
            <Mini k="Projected" v={p.projected.toFixed(1)} c={p.gap <= 0.15 ? 'var(--ink)' : tone.ink} i={1} />
            <Mini k={p.daysOut + ' days'} v={Math.abs(p.toGo).toFixed(1)} i={1} />
          </div>
        </Card>
        </div>
        <div>
          <SectionHeader trailing={<Disc />}>Your trend</SectionHeader>
          <Card pad={'16px 10px 12px'} style={{ alignItems: 'center' }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 14.5, color: 'var(--ink-2)', lineHeight: 1.5, alignSelf: 'stretch', padding: '0 8px 4px', textWrap: 'pretty' }}>{p.state.chartCaption}</div>
            <FCChart paceKey={paceKey} width={335} height={236} />
          </Card>
        </div>
        <div>
          <SectionHeader trailing={<Disc />}>This week</SectionHeader>
          <Card pad={18}>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
              <span style={{ fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600, color: 'var(--ink)' }}>{p.state.weekLine}</span>
              <span style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'var(--ink-3)' }}><strong style={{ color: tone.ink, fontWeight: 600 }}>{weekLoss.toFixed(1)}</strong> / {weekTarget.toFixed(2)} kg</span>
            </div>
            <div style={{ height: 6, background: 'var(--rule)', borderRadius: 4, overflow: 'hidden', marginTop: 13 }}><div style={{ width: `${Math.min(100, weekLoss / weekTarget * 100)}%`, height: '100%', background: tone.ink, borderRadius: 4 }} /></div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', lineHeight: 1.5, marginTop: 12, textWrap: 'pretty' }}>This week’s target is eased for your <strong style={{ color: 'var(--ink-2)', fontWeight: 600 }}>luteal phase</strong>.</div>
          </Card>
        </div>
        <div>
          <SectionHeader trailing={<Disc />}>From the corner</SectionHeader>
          <Card pad={18}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <window.CoachMark sport={(window.FC && window.FC.sport) || 'boxing'} size={30} />
                <div style={{ fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 600 }}>Coach Donnelly</div>
              </div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)' }}>06:42 today</div>
            </div>
            <div style={{ fontFamily: 'var(--serif)', fontSize: 15, lineHeight: 1.5, marginTop: 13, fontStyle: 'italic', textWrap: 'pretty' }}>&ldquo;{p.state.coach}&rdquo;</div>
          </Card>
        </div>
      </div>
      <TabBar active="home" /><HomeIndicator />
    </Phone>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// CLEAN iOS, Health-style summary: ring + big number, segmented control,
// inset grouped list. Rounded, friendly, system. No Oswald, warm bg.
// ════════════════════════════════════════════════════════════════════════════
function ProgressRing({ pct, size = 96, sw = 9, color = 'var(--accent)' }) {
  const r = (size - sw) / 2, c = 2 * Math.PI * r, off = c * (1 - Math.max(0, Math.min(1, pct)));
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--rule)" strokeWidth={sw} />
      <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth={sw} strokeLinecap="round" strokeDasharray={c} strokeDashoffset={off} transform={`rotate(-90 ${size/2} ${size/2})`} />
    </svg>
  );
}
function IOSSeg({ items, active }) {
  const [sel, setSel] = React.useState(active);
  React.useEffect(() => setSel(active), [active]);
  return (
    <div style={{ display: 'flex', background: 'var(--paper-2)', borderRadius: 11, padding: 3, gap: 2 }}>
      {items.map(it => (
        <button key={it} type="button" onClick={(e) => { e.stopPropagation(); setSel(it); }} style={{ flex: 1, textAlign: 'center', padding: '7px 0', border: 'none', cursor: 'pointer', borderRadius: 8, background: it === sel ? 'var(--paper)' : 'transparent', boxShadow: it === sel ? '0 1px 3px rgba(0,0,0,0.12)' : 'none', fontFamily: 'var(--sans)', fontSize: 13, fontWeight: it === sel ? 600 : 500, color: it === sel ? 'var(--ink)' : 'var(--ink-3)' }}>{it}</button>
      ))}
    </div>
  );
}
function DashIOS({ styleKey, paceKey }) {
  const p = computePace(paceKey), tone = TONE[p.tone];
  const today = dToday(p), d = dDelta(p), down = d <= 0;
  const startW = 80.2, pctToGoal = (startW - today) / (startW - FC.goalWeight);
  const IRow = ({ icon, label, value, vColor = 'var(--ink)', last }) => (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '0 16px', minHeight: 52 }}>
        <span style={{ width: 29, height: 29, borderRadius: 8, background: tone.soft, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{icon}</span>
        <span style={{ flex: 1, fontFamily: 'var(--sans)', fontSize: 15.5, color: 'var(--ink)' }}>{label}</span>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 15.5, fontWeight: 600, color: vColor, fontFeatureSettings: '"tnum"' }}>{value}</span>
        <svg width="7" height="12" viewBox="0 0 7 12" fill="none"><path d="M1 1 L6 6 L1 11" stroke="var(--rule-2)" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>
      </div>
      {!last && <div style={{ height: 1, background: 'var(--rule)', marginLeft: 58 }} />}
    </div>
  );
  const dot = (cc) => <span style={{ width: 7, height: 7, borderRadius: '50%', background: cc, display: 'block' }} />;
  return (
    <Phone styleKey={styleKey} label="Dashboard">
      <StatusBar />
      <LargeTitle title="Summary" trailing={<div style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--accent)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--sans)', fontWeight: 600, fontSize: 15 }}>A</div>} />
      <div style={{ flex: 1, padding: '4px 18px 26px', display: 'flex', flexDirection: 'column', gap: 18 }}>
        {/* summary card: ring + weight + log */}
        <Card pad={20}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 20 }}>
            <div style={{ position: 'relative', width: 96, height: 96, flexShrink: 0 }}>
              <ProgressRing pct={pctToGoal} color={tone.ink} />
              <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
                <span style={{ fontFamily: 'var(--sans)', fontSize: 19, fontWeight: 700, color: 'var(--ink)' }}>{Math.round(pctToGoal*100)}%</span>
                <span style={{ fontFamily: 'var(--sans)', fontSize: 9.5, color: 'var(--ink-3)', fontWeight: 500 }}>of cut</span>
              </div>
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'var(--ink-3)', fontWeight: 500 }}>Current weight</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 3 }}><Num size={46} weight={600}>{today.toFixed(1)}</Num><span style={{ fontFamily: 'var(--sans)', fontSize: 15, color: 'var(--ink-3)', fontWeight: 600 }}>kg</span></div>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 5, marginTop: 6, fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600, color: down ? 'var(--t-green)' : 'var(--ink-3)' }}>{dot(down ? 'var(--t-green)' : 'var(--ink-3)')}{down ? '\u2193' : '\u2191'} {Math.abs(d).toFixed(1)} kg today</div>
            </div>
          </div>
          <button style={{ width: '100%', marginTop: 18, background: 'var(--accent)', color: '#fff', border: 'none', borderRadius: 'var(--radius-ctl)', minHeight: 50, fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}>
            <svg width="17" height="17" viewBox="0 0 17 17" fill="none"><line x1="8.5" y1="3" x2="8.5" y2="14" stroke="#fff" strokeWidth="1.8" strokeLinecap="round"/><line x1="3" y1="8.5" x2="14" y2="8.5" stroke="#fff" strokeWidth="1.8" strokeLinecap="round"/></svg>
            Log Weight
          </button>
        </Card>

        <IOSSeg items={['Day', 'Week', 'Camp']} active="Week" />

        {/* status banner */}
        <Card pad={'15px 18px'} style={{ flexDirection: 'row', alignItems: 'center', gap: 13 }}>
          <span style={{ width: 38, height: 38, borderRadius: '50%', background: tone.soft, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{dot(tone.ink)}</span>
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600, color: 'var(--ink)' }}>{p.state.verdict}</div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'var(--ink-2)', marginTop: 3, lineHeight: 1.5, textWrap: 'pretty' }}>{p.state.line}</div>
          </div>
        </Card>

        {/* grouped list */}
        <div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600, color: 'var(--ink-3)', padding: '0 16px 7px' }}>This camp</div>
          <Card pad={0}>
            <IRow icon={dot(tone.ink)} label="Trending / week" value={(p.weeklyVel>=0?'+':'−')+Math.abs(p.weeklyVel).toFixed(1)+' kg'} vColor={tone.ink} />
            <IRow icon={dot('var(--accent)')} label="Projected fight-day" value={p.projected.toFixed(1)+' kg'} />
            <IRow icon={dot('var(--ink-3)')} label="To go" value={Math.abs(p.toGo).toFixed(1)+' kg'} />
            <IRow icon={dot('var(--ink-3)')} label="Days to weigh-in" value={p.daysOut} last />
          </Card>
        </div>

        {/* trend */}
        <div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600, color: 'var(--ink-3)', padding: '0 16px 7px' }}>Weight trend</div>
          <Card pad={'16px 10px 14px'} style={{ alignItems: 'center' }}>
            <FCChart paceKey={paceKey} width={333} height={232} />
          </Card>
        </div>
      </div>
      <TabBar active="home" /><HomeIndicator />
    </Phone>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// RETRO FIGHTER, fight poster: ink banner, scoreboard weight, tale of the tape.
// ════════════════════════════════════════════════════════════════════════════
function DashFighter({ styleKey, paceKey }) {
  const p = computePace(paceKey), tone = TONE[p.tone];
  const today = dToday(p), d = dDelta(p), down = d <= 0;
  const star = <span style={{ color: 'var(--accent)' }}>{'\u2731'}</span>;
  const tape = [
    { k: 'WALK-IN', v: '80.2', sub: 'CAMP START' },
    { k: 'TODAY', v: today.toFixed(1), sub: 'FASTED AM', hot: true },
    { k: 'TARGET', v: FC.goalWeight.toFixed(1), sub: 'THE LIMIT' },
    { k: 'PROJECTED', v: p.projected.toFixed(1), sub: p.gap <= 0.15 ? 'MAKES IT' : 'OVER BY ' + p.gap.toFixed(1), over: p.gap > 0.15 },
  ];
  return (
    <Phone styleKey={styleKey} label="Dashboard">
      <StatusBar />
      {/* POSTER BANNER */}
      <div style={{ background: 'var(--ink)', color: 'var(--paper)', padding: '14px 20px 16px', position: 'relative', flexShrink: 0 }}>
        <CornerTicks color="var(--accent)" inset={8} />
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontFamily: 'var(--display)', fontSize: 10.5, letterSpacing: '0.22em', color: 'rgba(245,237,220,0.65)' }}>
          <span>MAIN EVENT {star} {FC.division.toUpperCase()}</span><span>ROUND {FC.todayDay}/{FC.campDays}</span>
        </div>
        <div style={{ fontFamily: 'var(--display)', fontSize: 34, fontWeight: 700, letterSpacing: '0.01em', marginTop: 6, lineHeight: 0.98 }}>ALEX &ldquo;THE STORM&rdquo; MERCER</div>
        <div style={{ height: 3, background: 'var(--accent)', width: 64, marginTop: 10 }} />
      </div>
      <div style={{ flex: 1, padding: '16px 18px 26px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        {/* SCOREBOARD */}
        <div style={{ background: 'var(--ink)', color: 'var(--paper)', padding: '18px 20px', position: 'relative' }}>
          <HeroMotif motif="poster" />
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.22em', color: 'rgba(245,237,220,0.6)' }}>ON THE SCALE {star} 06:18</span>
            <ToneBadge tone={p.tone} dark>{p.badge}</ToneBadge>
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 12, marginTop: 8 }}>
            <span style={{ fontFamily: 'var(--num)', fontWeight: 600, fontSize: 104, lineHeight: 0.8, letterSpacing: '0.01em' }}>{today.toFixed(1)}</span>
            <div style={{ paddingBottom: 10 }}>
              <div style={{ fontFamily: 'var(--display)', fontSize: 18, letterSpacing: '0.1em', color: 'rgba(245,237,220,0.7)' }}>KG</div>
              <div style={{ fontFamily: 'var(--display)', fontSize: 13, letterSpacing: '0.08em', color: down ? '#cdd98e' : 'rgba(245,237,220,0.6)', marginTop: 4 }}>{down ? '\u2193' : '\u2191'}{Math.abs(d).toFixed(1)} TODAY</div>
            </div>
          </div>
        </div>

        {/* TALE OF THE TAPE */}
        <div style={{ border: '1.5px solid var(--ink)' }}>
          <div style={{ background: 'var(--ink)', color: 'var(--paper)', textAlign: 'center', fontFamily: 'var(--display)', fontSize: 13, letterSpacing: '0.26em', padding: '8px 0' }}>{star} TALE OF THE TAPE {star}</div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
            {tape.map((t, i) => (
              <div key={t.k} style={{ padding: '14px 16px', borderTop: i >= 2 ? '1px solid var(--rule)' : 'none', borderLeft: i % 2 ? '1px solid var(--rule)' : 'none', background: t.hot ? 'var(--accent-soft)' : 'transparent' }}>
                <div style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.16em', color: 'var(--ink-3)' }}>{t.k}</div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 6 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 600, fontSize: 32, color: t.over ? 'var(--accent)' : 'var(--ink)' }}>{t.v}</span><span style={{ fontFamily: 'var(--display)', fontSize: 11, color: 'var(--ink-3)' }}>KG</span></div>
                <div style={{ fontFamily: 'var(--display)', fontSize: 9.5, letterSpacing: '0.12em', color: t.over ? 'var(--accent)' : 'var(--ink-3)', marginTop: 5 }}>{t.sub}</div>
              </div>
            ))}
          </div>
        </div>

        {/* trend */}
        <div style={{ border: '1px solid var(--ink)', padding: '12px 8px 10px' }}>
          <div style={{ fontFamily: 'var(--display)', fontSize: 12, letterSpacing: '0.2em', color: 'var(--ink)', padding: '0 10px 6px' }}>THE TRAJECTORY</div>
          <FCChart paceKey={paceKey} width={331} height={228} />
        </div>

        {/* FROM THE CORNER */}
        <div style={{ background: 'var(--ink)', color: 'var(--paper)', padding: '16px 18px', position: 'relative' }}>
          <div style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.24em', color: 'var(--accent)' }}>{star} FROM THE CORNER {star}</div>
          <div style={{ fontFamily: 'var(--serif)', fontSize: 16, fontStyle: 'italic', lineHeight: 1.5, marginTop: 11, textWrap: 'pretty' }}>&ldquo;{p.state.coach}&rdquo;</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12 }}>
            <window.CoachMark sport={(window.FC && window.FC.sport) || 'boxing'} size={22} bg="var(--paper)" ink="var(--ink)" accent="var(--accent)" />
            <div style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.16em', color: 'rgba(245,237,220,0.6)' }}>COACH DONNELLY</div>
          </div>
        </div>

        <button style={{ width: '100%', background: 'var(--accent)', color: '#fff', border: 'none', minHeight: 56, fontFamily: 'var(--display)', fontSize: 16, fontWeight: 600, letterSpacing: '0.16em', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 12 }}>
          LOG TODAY&rsquo;S WEIGHT
          <span style={{ width: 24, height: 24, border: '1.5px solid rgba(255,255,255,0.7)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><svg width="10" height="10" viewBox="0 0 10 10"><line x1="5" y1="1.5" x2="5" y2="8.5" stroke="#fff" strokeWidth="1.5"/><line x1="1.5" y1="5" x2="8.5" y2="5" stroke="#fff" strokeWidth="1.5"/></svg></span>
        </button>
      </div>
      <TabBar active="home" /><HomeIndicator />
    </Phone>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// ELITE LAB, light scientific instrument: mono readouts, sparkline, metric grid.
// ════════════════════════════════════════════════════════════════════════════
function Sparkline({ p, w = 300, h = 44 }) {
  const ys = p.trend.map(t => t[1]);
  const min = Math.min(...ys), max = Math.max(...ys), rng = max - min || 1;
  const pts = p.trend.map((t, i) => [ (i / (p.trend.length - 1)) * w, h - 4 - ((t[1]-min)/rng)*(h-8) ]);
  const dPath = pts.map((q, i) => (i ? 'L' : 'M') + q[0].toFixed(1) + ' ' + q[1].toFixed(1)).join(' ');
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} style={{ display: 'block' }}>
      <path d={`${dPath} L ${w} ${h} L 0 ${h} Z`} fill="var(--accent-soft)" />
      <path d={dPath} fill="none" stroke="var(--accent)" strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={pts[pts.length-1][0]} cy={pts[pts.length-1][1]} r="3" fill="var(--accent)" />
    </svg>
  );
}
function DashElite({ styleKey, paceKey }) {
  const p = computePace(paceKey), tone = TONE[p.tone];
  const today = dToday(p), d = dDelta(p), down = d <= 0;
  const metrics = [
    { k: 'TREND / WK', v: (p.weeklyVel>=0?'+':'−')+Math.abs(p.weeklyVel).toFixed(2), u: 'kg', t: tone.ink },
    { k: 'PROJECTED', v: p.projected.toFixed(1), u: 'kg', t: p.gap<=0.15?'var(--ink)':tone.ink },
    { k: '\u0394 vs LIMIT', v: (p.gap>=0?'+':'−')+Math.abs(p.gap).toFixed(1), u: 'kg', t: p.gap<=0.15?'var(--t-green)':tone.ink },
    { k: 'TO WEIGH-IN', v: p.daysOut, u: 'days', t: 'var(--ink)' },
  ];
  return (
    <Phone styleKey={styleKey} label="Dashboard">
      <StatusBar />
      {/* readout bar */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '4px 20px 12px', flexShrink: 0 }}>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.16em', color: 'var(--ink-2)', fontWeight: 600 }}>IN CAMP <span style={{ color: 'var(--ink-3)' }}>// {FC.division.toUpperCase()}</span></span>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.12em', color: 'var(--accent)', fontWeight: 700 }}>D−{p.daysOut}</span>
      </div>
      <div style={{ height: 1, background: 'var(--rule)', flexShrink: 0 }} />
      <div style={{ flex: 1, padding: '16px 18px 26px', display: 'flex', flexDirection: 'column', gap: 14 }}>
        {/* primary readout */}
        <Card pad={18}>
          <HeroMotif motif="grid-light" />
          <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 }}>CURRENT MASS · FASTED</span>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.12em', color: tone.ink, fontWeight: 700, border: `1px solid ${tone.ink}`, borderRadius: 4, padding: '3px 7px' }}><span style={{ width: 5, height: 5, borderRadius: '50%', background: tone.ink }} />{p.badge}</span>
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 12, marginTop: 12 }}>
            <Num size={72} weight={500}>{today.toFixed(1)}</Num>
            <div style={{ paddingBottom: 8 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 13, color: 'var(--ink-3)', fontWeight: 600 }}>KG</div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 12, color: down ? 'var(--t-green)' : 'var(--ink-3)', fontWeight: 700, marginTop: 5 }}>{down ? '−' : '+'}{Math.abs(d).toFixed(1)} 24H</div>
            </div>
          </div>
          <div style={{ marginTop: 10, borderTop: '1px solid var(--rule)', paddingTop: 12 }}><Sparkline p={p} w={303} h={42} /></div>
        </Card>

        <button style={{ width: '100%', background: 'var(--accent)', color: '#fff', border: 'none', borderRadius: 'var(--radius-ctl)', minHeight: 50, fontFamily: 'var(--mono)', fontSize: 13, fontWeight: 700, letterSpacing: '0.14em', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10 }}>
          <svg width="14" height="14" viewBox="0 0 14 14"><line x1="7" y1="2" x2="7" y2="12" stroke="#fff" strokeWidth="1.8" strokeLinecap="round"/><line x1="2" y1="7" x2="12" y2="7" stroke="#fff" strokeWidth="1.8" strokeLinecap="round"/></svg>
          LOG MASS
        </button>

        {/* metric grid */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          {metrics.map(m => (
            <div key={m.k} style={{ background: 'var(--paper)', border: 'var(--card-border)', borderRadius: 'var(--radius)', boxShadow: 'var(--card-shadow)', 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.16em', color: 'var(--ink-3)', fontWeight: 600 }}>{m.k}</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 9 }}><Num size={27} weight={500} color={m.t}>{m.v}</Num><span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)', fontWeight: 600 }}>{m.u}</span></div>
            </div>
          ))}
        </div>

        {/* verdict readout */}
        <div style={{ background: 'var(--paper)', border: 'var(--card-border)', borderRadius: 'var(--radius)', boxShadow: 'var(--card-shadow)', padding: '15px 16px', borderLeft: `3px solid ${tone.ink}` }}>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: 'var(--ink-3)', fontWeight: 600 }}>ANALYSIS</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 15.5, fontWeight: 600, color: 'var(--ink)', marginTop: 8, textWrap: 'balance' }}>{p.state.verdict}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'var(--ink-2)', lineHeight: 1.5, marginTop: 6, textWrap: 'pretty' }}>{p.state.line}</div>
        </div>

        {/* trajectory */}
        <div>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.18em', color: 'var(--ink-3)', fontWeight: 600, padding: '4px 2px 8px' }}>TRAJECTORY · 5-DAY EWMA</div>
          <Card pad={'14px 10px 14px'} style={{ alignItems: 'center' }}><FCChart paceKey={paceKey} width={331} height={236} /></Card>
        </div>
      </div>
      <TabBar active="home" /><HomeIndicator />
    </Phone>
  );
}

// Punchy editorial headline per pace state (Full Editorial layout).
const EDITORIAL_HEAD = { onTrack: 'Hold the line.', tooFast: 'Ease off the gas.', trailing: 'Claw it back this week.', danger: 'This needs attention.' };

// ════════════════════════════════════════════════════════════════════════════
// FULL EDITORIAL, flat Weight-Camp aesthetic: hairline rules, no cards, huge
// light numeral, Oswald caps, sharp edges. The "brave" Today screen.
// ════════════════════════════════════════════════════════════════════════════
function DashEditorialFull({ styleKey, paceKey }) {
  const p = computePace(paceKey), tone = TONE[p.tone];
  const today = dToday(p), d = dDelta(p), down = d <= 0;
  const yest = p.hist[p.hist.length - 2][1];
  const RULE = { height: 1, background: 'var(--rule)' };
  const Eye = ({ children, color = 'var(--ink-3)' }) => (
    <div style={{ fontFamily: 'var(--display)', fontSize: 10.5, letterSpacing: '0.22em', textTransform: 'uppercase', color, fontWeight: 600 }}>{children}</div>
  );
  return (
    <Phone styleKey={styleKey} label="Dashboard">
      <StatusBar />
      <div style={{ padding: '6px 22px 12px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
          <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--accent)' }} />
          <span style={{ fontFamily: 'var(--display)', fontSize: 15, letterSpacing: '0.12em', textTransform: 'uppercase', fontWeight: 600 }}>In Camp · {FC.division}</span>
        </div>
        <GearButton />
      </div>
      <div style={RULE} />
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {/* hero */}
        <div style={{ padding: '22px 22px 20px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 12 }}>
            <Eye>Fasted morning · 06:18</Eye>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, flexShrink: 0, fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.16em', color: tone.ink, fontWeight: 700, textTransform: 'uppercase' }}><span style={{ width: 6, height: 6, borderRadius: '50%', background: tone.ink }} />{p.badge}</span>
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 11, marginTop: 14 }}>
            <span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 116, lineHeight: 0.84, letterSpacing: '-0.03em', color: 'var(--ink)' }}>{today.toFixed(1)}</span>
            <div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 13, letterSpacing: '0.18em', color: 'var(--ink-3)', fontWeight: 600 }}>KG</div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 12, letterSpacing: '0.1em', color: down ? 'var(--t-green)' : 'var(--ink-3)', fontWeight: 600, marginTop: 6 }}>{down ? '−' : '+'}{Math.abs(d).toFixed(1)} / 24H</div>
            </div>
          </div>
          <button style={{ width: '100%', marginTop: 20, background: 'var(--ink)', color: 'var(--paper)', border: 'none', borderRadius: 0, minHeight: 54, padding: '0 18px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <span style={{ fontFamily: 'var(--display)', fontSize: 14, letterSpacing: '0.2em', fontWeight: 600 }}>ADD TODAY'S WEIGHT</span>
            <span style={{ width: 24, height: 24, border: '1px solid rgba(255,255,255,0.4)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><svg width="10" height="10" viewBox="0 0 10 10" fill="none"><line x1="5" y1="1.5" x2="5" y2="8.5" stroke="#fff" strokeWidth="1.3" strokeLinecap="round"/><line x1="1.5" y1="5" x2="8.5" y2="5" stroke="#fff" strokeWidth="1.3" strokeLinecap="round"/></svg></span>
          </button>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', color: 'var(--ink-3)', fontWeight: 500, marginTop: 10 }}>LOGGED 06:18 · TAP TO UPDATE</div>
        </div>
        <div style={RULE} />
        {/* three-up */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr' }}>
          {[['Yesterday', yest.toFixed(1), 'var(--ink)'], ['7-day trend', p.trendingToday.toFixed(1), tone.ink], ['Weigh-in limit', FC.goalWeight.toFixed(1), 'var(--accent)']].map((it, i) => (
            <div key={it[0]} style={{ padding: '16px 18px', borderLeft: i ? '1px solid var(--rule)' : 'none' }}>
              <Eye>{it[0]}</Eye>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 3, marginTop: 10 }}><span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 27, color: it[2] }}>{it[1]}</span><span style={{ fontFamily: 'var(--mono)', fontSize: 9, color: 'var(--ink-3)', fontWeight: 600 }}>KG</span></div>
            </div>
          ))}
        </div>
        <div style={RULE} />
        {/* verdict */}
        <div style={{ padding: '20px 22px' }}>
          <Eye color={tone.ink}>{p.state.badge}</Eye>
          <div style={{ fontFamily: 'var(--display)', fontSize: 30, lineHeight: 1.02, letterSpacing: '0.01em', textTransform: 'uppercase', color: 'var(--ink)', marginTop: 12 }}>{EDITORIAL_HEAD[paceKey] || EDITORIAL_HEAD.onTrack}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 14, lineHeight: 1.5, color: 'var(--ink-2)', marginTop: 12, textWrap: 'pretty' }}>{p.state.line}</div>
        </div>
        <div style={RULE} />
        {/* trajectory */}
        <div style={{ padding: '16px 12px 18px' }}>
          <div style={{ padding: '0 10px' }}><Eye>Trajectory · 5-day EWMA</Eye></div>
          <div style={{ marginTop: 8 }}><FCChart paceKey={paceKey} width={349} height={232} /></div>
        </div>
        <div style={RULE} />
        {/* coach */}
        <div style={{ padding: '18px 22px 24px' }}>
          <Eye>From the corner · 06:42</Eye>
          <div style={{ fontFamily: 'var(--serif)', fontSize: 17, fontStyle: 'italic', lineHeight: 1.45, color: 'var(--ink)', marginTop: 12, textWrap: 'pretty' }}>&ldquo;{p.state.coach}&rdquo;</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12 }}>
            <window.CoachMark sport={(window.FC && window.FC.sport) || 'boxing'} size={22} />
            <div style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.16em', color: 'var(--ink-3)', fontWeight: 600 }}>DONNELLY</div>
          </div>
        </div>
      </div>
      <TabBar active="home" /><HomeIndicator />
    </Phone>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// TRACKING DETAIL, the "bigger summary" pushed when the How-you're-tracking card
// is tapped. iOS navigation-push pattern: own status bar, back header, scroll body.
// ════════════════════════════════════════════════════════════════════════════
function TrackingDetail({ paceKey, onClose }) {
  const p = computePace(paceKey), tone = TONE[p.tone];
  const goal = FC.goalWeight, proj = p.projected, gap = proj - goal;
  const targetWk = -(p.toGo) / (p.daysOut / 7);
  const daysToGoal = p.dailyVel < -0.001 ? Math.round(p.toGo / -p.dailyVel) : null;
  const rel = daysToGoal == null ? null : daysToGoal - p.daysOut;
  let head, hcol;
  if (paceKey === 'onTrack') { hcol = 'var(--t-green)'; head = <>Making weight, {Math.abs(gap).toFixed(1)} kg to spare.</>; }
  else if (paceKey === 'tooFast') { hcol = tone.ink; head = <>Making weight, but cutting too fast.</>; }
  else { hcol = tone.ink; head = <>At this pace, {gap.toFixed(1)} kg over.</>; }
  const margin = gap <= 0 ? `${Math.abs(gap).toFixed(1)} kg under` : `${gap.toFixed(1)} kg over`;
  const marginCol = gap <= 0 ? 'var(--t-green)' : tone.ink;
  const reaches = daysToGoal == null ? 'Not at this pace' : (rel <= 0 ? `${Math.abs(rel)} days early` : `~${rel} days late`);
  const reachesCol = daysToGoal == null ? tone.ink : (rel <= 0 ? 'var(--t-green)' : tone.ink);
  const explain = {
    onTrack: 'Your trend is right on target. Daily ups and downs are normal, so trust the line. Hold this and you hit fight week in great shape.',
    tooFast: 'You’re dropping faster than planned. Hard cuts cost power and recovery. Add food back and protect fight night.',
    trailing: 'A little behind, nothing major. Tighten your food slightly to course-correct. Small moves now, no crash later.',
    danger: 'This rate won’t make the limit safely. Push harder and you risk your performance and your health. Move up a class or rework the plan now.',
  }[paceKey] || '';
  const eyebrow = (t) => <div style={{ fontFamily: 'var(--display)', fontSize: 10.5, letterSpacing: '0.18em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600, padding: '0 4px 9px' }}>{t}</div>;
  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 40, background: 'var(--paper-2)', display: 'flex', flexDirection: 'column' }}>
      <StatusBar />
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 14px 12px' }}>
        <button onClick={onClose} aria-label="Back" style={{ display: 'inline-flex', alignItems: 'center', gap: 4, minHeight: 44, color: 'var(--accent)', fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 500 }}>
          <svg width="10" height="16" viewBox="0 0 10 16" fill="none"><path d="M8 1 L2 8 L8 15" stroke="var(--accent)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>Today
        </button>
      </div>
      <div className="scroll" style={{ padding: '4px 20px 28px', display: 'flex', flexDirection: 'column', gap: 22 }}>
        <div>
          <div style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--ink-3)', fontWeight: 600 }}>How you{'’'}re tracking</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 27, fontWeight: 600, lineHeight: 1.2, color: 'var(--ink)', marginTop: 10, textWrap: 'balance' }}>{head}</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 14.5, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 12, textWrap: 'pretty' }}>{explain}</div>
        </div>

        {/* DRIFT-WATCH, the soft CUSUM early-warning tier (§9.5). Off the alarm
            channel: a quiet note when a consistent drift is building, days before
            the 7-day rate would confirm it. Never red, never fires re-plan. */}
        {(() => {
          const dw = window.driftWatch ? window.driftWatch(paceKey) : { status: 'clear', pct: 0 };
          const map = {
            clear: { dot: 'var(--t-green)', label: 'No drift', body: 'Your trend is holding against plan. Nothing building under the daily noise.' },
            behind: { dot: 'var(--t-amber)', label: 'Watching a slow drift', body: `You've trended a touch behind for ${dw.days} days running. Not acting yet, just flagging it early so there's room to adjust gently.` },
            fast: { dot: 'var(--t-amber)', label: 'Watching a fast drift', body: `You've trended a little quick for ${dw.days} days running. Not acting yet, just keeping an eye so the cut stays controlled.` },
          };
          const m = map[dw.status] || map.clear;
          return (
            <div style={{ background: 'var(--paper)', border: 'var(--card-border)', borderRadius: 'var(--radius)', boxShadow: 'var(--card-shadow)', padding: '15px 16px' }}>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: m.dot, flexShrink: 0 }} />
                  <span style={{ fontFamily: 'var(--display)', fontSize: 10.5, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--ink-2)', fontWeight: 700 }}>Drift watch · {m.label}</span>
                </div>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.06em', color: 'var(--ink-3)', fontWeight: 600 }}>EARLY SIGNAL</span>
              </div>
              {/* accumulation bar: how close the drift is to opening a watch */}
              <div style={{ height: 5, borderRadius: 3, background: 'var(--rule)', marginTop: 11, overflow: 'hidden' }}>
                <div style={{ width: `${Math.round((dw.pct || 0) * 100)}%`, height: '100%', borderRadius: 3, background: m.dot, transition: 'width .3s' }} />
              </div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', lineHeight: 1.5, marginTop: 10, textWrap: 'pretty' }}>{m.body}{dw.tightened && dw.status === 'clear' ? ' Sensitivity is raised this close to fight day.' : ''}</div>
            </div>
          );
        })()}
        <div>
          <SectionHeader>The projection</SectionHeader>
          <GroupedList>
            <Row label="Current trend" value={`${p.trendingToday.toFixed(1)} kg`} chevron={false} />
            <Row label="Projected at weigh-in" value={`${proj.toFixed(1)} kg`} chevron={false} />
            <Row label="The limit" value={`${goal.toFixed(1)} kg`} chevron={false} />
            <Row label="Margin" value={margin} valueColor={marginCol} chevron={false} last />
          </GroupedList>
        </div>
        <div>
          <SectionHeader>Your pace</SectionHeader>
          <GroupedList>
            <Row label="7-day rate" value={`${p.weeklyVel.toFixed(2)} kg/wk`} chevron={false} />
            <Row label="Rate needed" value={`${targetWk.toFixed(2)} kg/wk`} chevron={false} />
            <Row label="Reaches limit" value={reaches} valueColor={reachesCol} chevron={false} />
            <Row label="Days to weigh-in" value={`${p.daysOut} days`} chevron={false} last />
          </GroupedList>
        </div>

        {/* HOW WE READ IT, the tracking cascade (§9.1), so the verdict is trusted */}
        <div>
          {eyebrow('How we read your weight')}
          <Card pad={18}>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)', textWrap: 'pretty' }}>Daily weight is mostly water. We never call your cut on one reading. We step through three timescales and judge it on the rate.</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 0, marginTop: 14 }}>
              {[
                ['Daily number', 'Logged, never a verdict. Too much noise.', false],
                ['3-day average', 'A smoother read. A filter, not the call.', false],
                ['7-day rate', 'This is the verdict. Signal beats the noise here.', true],
              ].map(([t, d, on], i, a) => (
                <div key={t} style={{ display: 'flex', gap: 12, paddingBottom: i < a.length - 1 ? 12 : 0 }}>
                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flexShrink: 0 }}>
                    <span style={{ width: 11, height: 11, borderRadius: '50%', background: on ? 'var(--accent)' : 'transparent', border: on ? 'none' : '1.6px solid var(--rule-2)', marginTop: 3 }} />
                    {i < a.length - 1 && <span style={{ width: 1.5, flex: 1, background: 'var(--rule)', marginTop: 3 }} />}
                  </div>
                  <div style={{ paddingBottom: 2 }}>
                    <div style={{ fontFamily: 'var(--sans)', fontSize: 14.5, fontWeight: on ? 700 : 600, color: on ? 'var(--ink)' : 'var(--ink-2)' }}>{t}</div>
                    <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', lineHeight: 1.45, marginTop: 1, textWrap: 'pretty' }}>{d}</div>
                  </div>
                </div>
              ))}
            </div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 12.5, color: 'var(--ink-3)', lineHeight: 1.5, marginTop: 14, paddingTop: 13, borderTop: '1px solid var(--rule)', textWrap: 'pretty' }}>Every read is checked against your <strong style={{ color: 'var(--ink-2)', fontWeight: 600 }}>cycle-adjusted</strong> plan, so a water week never reads as falling behind.</div>
          </Card>
        </div>
      </div>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// BALANCED, editorial hero (flat, big light numeral) on the canvas, then native
// iOS structure below: segmented control, status banner, grouped cells, chart card.
// ════════════════════════════════════════════════════════════════════════════
function DashBalanced({ styleKey, paceKey, btnStyle = 'solid', logPos = 'below', chartPlace = 'left' }) {
  const [detail, setDetail] = React.useState(false);
  const [manage, setManage] = React.useState(false);
  const p = computePace(paceKey), tone = TONE[p.tone];
  const today = dToday(p), d = dDelta(p), down = d <= 0;
  const cardSurface = { background: 'var(--paper)', borderRadius: 'var(--radius)', boxShadow: 'var(--card-shadow)', border: 'var(--card-border)' };
  return (
    <Phone styleKey={styleKey} label="Dashboard">
      <StatusBar />
      <DashBanner tone="ink" label="IN CAMP" meta={`${p.daysOut} DAYS OUT`} />
      <div style={{ padding: '10px 20px 0' }} />
      <LargeTitle title="Today" trailing={<GearButton />} eyebrowColor="var(--ink-3)" />
      <div style={{ flex: 1, padding: '2px 20px 28px', display: 'flex', flexDirection: 'column', gap: 24 }}>

        {/* HERO, big numeral, status, experimental CTA (btnStyle tweak) */}
        {(() => {
          const big = (sz) => ({ fontFamily: 'var(--num)', fontWeight: 300, fontSize: sz, lineHeight: 0.8, letterSpacing: '-0.035em', color: 'var(--ink)' });
          const unitS = { fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.12em', color: 'var(--ink-3)', fontWeight: 500 };
          const statusS = { fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.08em', color: tone.ink, fontWeight: 600, textTransform: 'uppercase', whiteSpace: 'nowrap' };
          const loggedS = { fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.1em', color: 'var(--ink-3)', fontWeight: 500, textTransform: 'uppercase' };
          const label = 'ADD TODAY’S WEIGHT';
          const lblS = { fontFamily: 'var(--display)', fontSize: 15, letterSpacing: '0.13em', fontWeight: 600, whiteSpace: 'nowrap' };
          const plus = (c) => <svg width="11" height="11" viewBox="0 0 10 10" fill="none"><line x1="5" y1="1.5" x2="5" y2="8.5" stroke={c} strokeWidth="1.5" strokeLinecap="round"/><line x1="1.5" y1="5" x2="8.5" y2="5" stroke={c} strokeWidth="1.5" strokeLinecap="round"/></svg>;
          const disc = (bg, c) => <span style={{ width: 24, height: 24, background: bg, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{plus(c)}</span>;
          const base = { width: '100%', minHeight: 58, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 12, border: 'none', borderRadius: 16 };
          // S2 — one canonical hero CTA everywhere; the btnStyle experiment is retired on the shipping screen.
          const addBtn = <HeroButton label={label} />;
          return (
            <div>
              <div style={{ display: 'flex', alignItems: 'flex-end', gap: 14, marginTop: 4 }}>
                <span style={big(112)}>{today.toFixed(1)}</span>
                <div style={{ paddingBottom: 0 }}><div style={unitS}>KG</div></div>
              </div>
              {/* pace-state + logged time, grouped tight so they read as one unit */}
              <div style={{ marginTop: 16 }}>
                <div style={{ fontFamily: 'var(--mono)', fontSize: 11.5, letterSpacing: '0.14em', textTransform: 'uppercase', color: tone.ink, fontWeight: 700 }}>{p.badge}</div>
                <div style={{ ...loggedS, marginTop: 3 }}>06:18 Today</div>
              </div>
              <div style={{ marginTop: 20 }}>{addBtn}</div>
            </div>
          );
        })()}

        {/* HOW YOU'RE TRACKING, one interpreted headline + projected / goal / timing. Mirrors the Progress "this camp" hierarchy: eyebrow, one bold human verdict, three quiet stats. */}
        {(() => {
          const goal = FC.goalWeight;
          const proj = p.projected;
          const gap = proj - goal;
          const daysToGoal = p.dailyVel < -0.001 ? Math.round(p.toGo / -p.dailyVel) : null;
          const rel = daysToGoal == null ? null : daysToGoal - p.daysOut;
          // THE point, will you make weight, in plain language.
          // diagnosis (coloured) + one-line interpretation
          let diag, diagCol, body;
          if (paceKey === 'onTrack') { diag = 'Making weight'; diagCol = 'var(--t-green)'; body = 'A safe, steady pace. You make weight without draining your power.'; }
          else if (paceKey === 'tooFast') { diag = 'Cutting too fast'; diagCol = tone.ink; body = 'Quicker than you need. Good for the scale, hard on your strength and recovery.'; }
          else if (paceKey === 'trailing') { diag = 'Slightly behind'; diagCol = tone.ink; body = 'A touch slow, but an easy fix. Tighten up this week and you’re back on it.'; }
          else { diag = 'Off the pace'; diagCol = tone.ink; body = 'Too slow to make weight safely. Time to rework the plan before fight week.'; }
          // timing, when this pace actually reaches the goal, relative to weigh-in.
          let tVal, tUnit, tCol;
          if (daysToGoal == null) { tVal = '\u2014'; tUnit = 'never'; tCol = tone.ink; }
          else if (rel <= 0) { tVal = Math.abs(rel); tUnit = 'd early'; tCol = 'var(--t-green)'; }
          else { tVal = rel; tUnit = 'd late'; tCol = tone.ink; }
          return (
            <div>
              <SectionHeader>How you{'’'}re tracking</SectionHeader>
              <button onClick={() => setDetail(true)} style={{ ...cardSurface, padding: '20px', width: '100%', textAlign: 'left', display: 'block' }}>
                <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontFamily: 'var(--sans)', fontSize: 20, fontWeight: 600, lineHeight: 1.2, color: diagCol, textWrap: 'balance' }}>{diag}</div>
                    <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.5, color: 'var(--ink-2)', marginTop: 6, textWrap: 'pretty' }}>{body}</div>
                  </div>
                  <svg width="8" height="14" viewBox="0 0 8 14" fill="none" style={{ marginTop: 4, flexShrink: 0 }}><path d="M1 1 L7 7 L1 13" stroke="var(--rule-2)" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>
                </div>
                <div style={{ display: 'flex', marginTop: 18, paddingTop: 18, borderTop: '1px solid var(--rule)' }}>
                  <Stat label="Projected" value={proj.toFixed(1)} unit="kg" i={0} />
                  <Stat label="Limit" value={goal.toFixed(1)} unit="kg" i={1} />
                  <Stat label="Hits limit" value={tVal} unit={tUnit} color={tCol} i={1} />
                </div>
              </button>
            </div>
          );
        })()}

        {/* TREND, section label above the card, matching the other cards' rhythm */}
        <div>
          <SectionHeader>Your trend</SectionHeader>
          <div style={{ ...cardSurface, padding: 20 }}>
            <FCHealthCard place={chartPlace} heading={null} paceKey={paceKey} width={331} />
          </div>
        </div>

        {/* CYCLE GLANCE, surfaces today's cycle read, links to the full section */}
        {window.CycleGlanceRow && (
          <div>
            <SectionHeader>Your cycle</SectionHeader>
            <window.CycleGlanceRow />
          </div>
        )}

        {/* CAMP AHEAD, the road to fight day at camp scale: where you are now,
            when the fight-week strategies fire, weigh-in, fight. Phases + dates,
            not daily weight, a horizon without the fluctuation noise. */}
        <div>
          <SectionHeader>Camp ahead</SectionHeader>
          <div style={{ ...cardSurface, padding: '6px 18px' }}>
            <window.StepList steps={[
              { label: 'NOW', title: 'Camp cut', detail: 'Real weight, ~0.5% a week', state: 'now' },
              { label: 'MON 6 JAN', title: 'Low fibre + low sodium', detail: 'Fight week starts — lighten the gut, start shedding water', state: 'todo' },
              { label: 'TUE–WED', title: 'Water load', detail: 'Drink big (~6–8 L) to flush sodium', state: 'todo' },
              { label: 'THU 9 JAN', title: 'Water taper', detail: 'Cut fluids right down', state: 'todo' },
              { label: 'FRI 10 JAN', title: 'Sweat-out → weigh-in', detail: `Last water off, land on ${FC.goalWeight.toFixed(1)} kg`, state: 'todo' },
              { label: 'FRI PM', title: 'Rehydrate + refuel', detail: 'Rebuild the moment you step off the scale', state: 'todo' },
              { label: 'SAT 11 JAN', title: 'Fight', detail: 'Rebuilt and back to fighting weight', state: 'goal' },
            ]} />
          </div>
        </div>

      </div>
      <TabBar active="home" /><HomeIndicator />
      {detail && <TrackingDetail paceKey={paceKey} onClose={() => setDetail(false)} />}
      {manage && window.ManageFightSheet && <window.ManageFightSheet onClose={() => setManage(false)} />}
    </Phone>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// FIGHT WEEK, distinct Today state for the final descent. Projection gives way to
// EXECUTION: a cycle-adjusted working target, the week's descent protocol, and
// today's single job. Dietician voice: supportive, scientific, never alarmist.
// ════════════════════════════════════════════════════════════════════════════
function DashFightWeek({ styleKey = 'balanced' }) {
  // ── fight-week model ────────────────────────────────────────────────────────
  const limit = FC.goalWeight;            // division limit, the hard line, 74.4
  // Weigh-in-week water = this athlete's LEARNED amplitude (§9.4/§15.4), not the
  // 0.5 kg population default and not an arbitrary guess. She has 3 cycles logged
  // and holds more than average, so the buffer is individualised upward.
  const retention = (window.LEARNED_CYCLE && window.LEARNED_CYCLE.blendKg) || FC.cycle.retention;
  const working = +(limit - retention).toFixed(1);  // aim point so she lands AT the limit
  const current = 74.9;                    // this morning's trend
  const toWorking = +(current - working).toFixed(1);
  const water = { logged: 3.2, target: 6 };
  const plan = [
    { label: 'MON', tag: 'Today', title: 'Water load', detail: '6 L. Flush and build a drop response', state: 'today' },
    { label: 'TUE', title: 'Water load', detail: '6 L. Hold the volume', state: 'todo' },
    { label: 'WED', title: 'Taper', detail: '4 L. Ease sodium down', state: 'todo' },
    { label: 'THU', title: 'Reduce', detail: '2 L. Low-residue food', state: 'todo' },
    { label: 'FRI', title: 'Water cut', detail: '250 ml. The final descent', state: 'todo' },
    { label: 'SAT', title: 'Weigh-in', detail: '9:00 AM, then rehydrate', state: 'goal' },
  ];
  const loggedS = { fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.1em', color: 'var(--ink-3)', fontWeight: 500, textTransform: 'uppercase' };
  // fight-week theme shift, warm, deepened clay surface + intensified accents.
  const FWV = { '--paper': '#fdf9f3', '--rule': '#ddd0bb', '--card-shadow': '0 1px 3px rgba(40,28,12,0.06), 0 10px 26px rgba(40,28,12,0.08)' };
  const FW_S = '#e9ddcd';
  const [manage, setManage] = React.useState(false);
  return (
    <Phone styleKey={styleKey} label="Fight Week">
      <StatusBar />
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', ...FWV, background: FW_S }}>
        {/* persistent fight-week banner, shared OnWeight phase strip, red = intensity */}
        <DashBanner tone="accent" label="FIGHT WEEK" meta="5 DAYS TO WEIGH-IN" />
        <div style={{ padding: '10px 20px 0', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span style={{ fontFamily: 'var(--title-font)', fontSize: 27, fontWeight: 700, letterSpacing: 'var(--title-spacing)', color: 'var(--ink)' }}>Saturday</span>
          <GearButton />
        </div>
      <div style={{ flex: 1, padding: '12px 20px 28px', display: 'flex', flexDirection: 'column', gap: 22, overflowY: 'auto' }}>

        {/* HERO, where you are this morning, and the one human read */}
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 11, marginTop: 4 }}>
            <span style={{ fontFamily: 'var(--num)', fontWeight: 300, fontSize: 112, lineHeight: 0.8, letterSpacing: '-0.035em', color: 'var(--ink)' }}>{current.toFixed(1)}</span>
            <div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 13, letterSpacing: '0.18em', color: 'var(--ink-3)', fontWeight: 600 }}>KG</div>
              <div style={{ ...loggedS, marginTop: 6 }}>06:18 Today</div>
            </div>
          </div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 20, fontWeight: 600, lineHeight: 1.25, color: 'var(--ink)', marginTop: 16, textWrap: 'balance' }}>On plan for Saturday. <span style={{ color: 'var(--t-green)' }}>{toWorking.toFixed(1)} kg</span> to your working target.</div>
        </div>

        {/* CYCLE-ADJUSTED TARGET, the headline insight: aim lower so you land AT the limit */}
        <div>
          <SectionHeader>Your working target</SectionHeader>
          <Card pad={20}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9, marginBottom: 11 }}>
              <CycleGlyph />
              <span style={{ fontFamily: 'var(--display)', fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 600 }}>Aim lower this week</span>
            </div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 15, lineHeight: 1.55, color: 'var(--ink)', textWrap: 'pretty' }}>
              Weigh-in falls in your high-retention week. You hold about <strong>{retention.toFixed(1)} kg</strong> of extra water then. Aim {retention.toFixed(1)} kg under, so you land on <strong>{limit.toFixed(1)} kg</strong> on the day.
            </div>
            <div style={{ display: 'flex', marginTop: 20, paddingTop: 18, borderTop: '1px solid var(--rule)' }}>
              <Stat label="Division limit" value={limit.toFixed(1)} unit="kg" i={0} />
              <Stat label="Cyclical water" value={'+' + retention.toFixed(1)} unit="kg" color="var(--ink-2)" i={1} />
              <Stat label="Work to" value={working.toFixed(1)} unit="kg" color="var(--accent)" i={1} />
            </div>
          </Card>
        </div>

        {/* TODAY'S JOB, single focus, with progress */}
        <div>
          <SectionHeader>Today · Monday</SectionHeader>
          <Card pad={20}>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
              <span style={{ fontFamily: 'var(--sans)', fontSize: 19, fontWeight: 600, color: 'var(--ink)' }}>Water load</span>
              <span style={{ fontFamily: 'var(--mono)', fontSize: 12, letterSpacing: '0.04em', color: 'var(--ink-2)', fontWeight: 600 }}>{water.logged.toFixed(1)} / {water.target} L</span>
            </div>
            <div style={{ marginTop: 13 }}><ProgressBar pct={water.logged / water.target} tone="green" /></div>
            <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.5, color: 'var(--ink-2)', marginTop: 13, textWrap: 'pretty' }}>Keep the volume up. Loading now makes Friday&rsquo;s cut easier. Hit 6 L.</div>
          </Card>
        </div>

        {/* CUT STRATEGY — the whole cut on one arc: real weight across camp, then
            fight-week water. Same graph as the Plan screen. */}
        {(() => {
          const startW = (FC.planStart != null ? FC.planStart : current);
          const cut = +(startW - limit).toFixed(1);
          const pType = window.planTypeFor ? window.planTypeFor(FC.sport || 'MMA', true) : 'camp';
          const water = pType !== 'walk';
          const fwWater = water ? +(cut * 0.28).toFixed(1) : 0;
          const campKg = +(cut - fwWater).toFixed(1);
          const dsc = { targetW: limit, cut, fwWater, campKg, water };
          return (
            <div>
              <SectionHeader>Your cut strategy</SectionHeader>
              <Card pad={20}>
                <div style={{ fontFamily: 'var(--sans)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink-2)' }}>Your descent to fight day</div>
                <div style={{ marginTop: 8 }}><window.RROStrategyDescent d={dsc} width={291} height={224} /></div>
              </Card>
            </div>
          );
        })()}

        {/* THE WEEK, descent protocol, today highlighted (shared StepList) */}
        <div>
          <SectionHeader>The descent</SectionHeader>
          <Card pad="6px 18px"><StepList steps={plan} /></Card>
        </div>

      </div>
      </div>
      <TabBar active="home" /><HomeIndicator />
      {manage && window.ManageFightSheet && <window.ManageFightSheet onClose={() => setManage(false)} />}
    </Phone>
  );
}

// small cycle glyph, a phase ring, no clinical iconography
function CycleGlyph() {
  return (
    <svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
      <circle cx="10" cy="10" r="7.5" stroke="var(--accent)" strokeWidth="1.6" opacity="0.35" />
      <path d="M10 2.5 A7.5 7.5 0 0 1 17.5 10" stroke="var(--accent)" strokeWidth="1.6" strokeLinecap="round" />
      <circle cx="17.5" cy="10" r="1.6" fill="var(--accent)" />
    </svg>
  );
}

// dispatcher
function Dashboard({ styleKey = 'paper', paceKey = 'onTrack', btnStyle = 'solid', logPos = 'below', chartPlace = 'left' }) {
  const layout = getStyle(styleKey).layout;
  if (layout === 'full') return <DashEditorialFull styleKey={styleKey} paceKey={paceKey} />;
  if (layout === 'balanced') return <DashBalanced styleKey={styleKey} paceKey={paceKey} btnStyle={btnStyle} logPos={logPos} chartPlace={chartPlace} />;
  return <DashEditorial styleKey={styleKey} paceKey={paceKey} />;
}

Object.assign(window, { Dashboard, DashEditorial, DashEditorialFull, DashBalanced, DashFightWeek });
