// TopSet — core reusable components
// Plate stack, bar diagram, set rows, rest ring, AMRAP counter, lift cards.
// All scoped via the .ts wrapper class.

// ── icons ────────────────────────────────────────────────────────────
const Ico = {
  Today:    () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M4 12h3l3-8 4 16 3-8h3"/></svg>,
  History:  () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></svg>,
  Progress: () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M4 19V5M4 19h16M7 16l3-4 3 3 5-7"/></svg>,
  Settings: () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M4 6h12M4 12h8M4 18h14"/><circle cx="19" cy="6" r="2.5"/><circle cx="15" cy="12" r="2.5"/><circle cx="17" cy="18" r="2.5"/></svg>,
  Plus:     () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M12 5v14M5 12h14"/></svg>,
  Minus:    () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14"/></svg>,
  Check:    () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M4 12l5 5L20 6"/></svg>,
  Chevron:  () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M9 6l6 6-6 6"/></svg>,
  Grip:     () => <svg viewBox="0 0 24 24" fill="currentColor"><circle cx="9" cy="6" r="1.5"/><circle cx="15" cy="6" r="1.5"/><circle cx="9" cy="12" r="1.5"/><circle cx="15" cy="12" r="1.5"/><circle cx="9" cy="18" r="1.5"/><circle cx="15" cy="18" r="1.5"/></svg>,
  Flag:     () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M5 21V4M5 4h12l-3 4 3 4H5"/></svg>,
  Bolt:     () => <svg viewBox="0 0 24 24" fill="currentColor"><path d="M13 2 4 14h6l-1 8 9-12h-6l1-8z"/></svg>,
  Star:     () => <svg viewBox="0 0 24 24" fill="currentColor"><path d="m12 2 2.9 6.9L22 10l-5.5 4.8L18 22l-6-3.6L6 22l1.5-7.2L2 10l7.1-1.1L12 2z"/></svg>,
  Sound:    () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M4 10v4h3l5 4V6L7 10H4zM16 8c1.5 2 1.5 6 0 8M19 5c3 4 3 10 0 14"/></svg>,
  Heart:    () => <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 21s-7-4.5-9-9c-1.5-3.4 1-7 4.5-7 1.7 0 3.3 1 4.5 2.5C13.2 6 14.8 5 16.5 5 20 5 22.5 8.6 21 12c-2 4.5-9 9-9 9z"/></svg>,
  Close:    () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><path d="M6 6l12 12M18 6L6 18"/></svg>,
  Bar:      () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><rect x="2" y="11" width="20" height="2"/><rect x="5" y="8" width="2" height="8"/><rect x="17" y="8" width="2" height="8"/></svg>,
  Calc:     () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75"><rect x="5" y="3" width="14" height="18" rx="2"/><rect x="8" y="6" width="8" height="3"/><circle cx="9" cy="13" r="0.8" fill="currentColor"/><circle cx="12" cy="13" r="0.8" fill="currentColor"/><circle cx="15" cy="13" r="0.8" fill="currentColor"/><circle cx="9" cy="17" r="0.8" fill="currentColor"/><circle cx="12" cy="17" r="0.8" fill="currentColor"/><circle cx="15" cy="17" r="0.8" fill="currentColor"/></svg>,
};

// ── status bar (iOS-ish, frameless) ──────────────────────────────────
const StatusBar = ({ time = '9:41', light = true }) => (
  <div className="ts-status" style={{ color: light ? 'var(--ts-text)' : '#000' }}>
    <span>{time}</span>
    <span className="ts-status-r">
      {/* signal */}
      <svg viewBox="0 0 18 12" fill="currentColor"><rect x="0" y="8" width="3" height="4" rx="0.5"/><rect x="5" y="6" width="3" height="6" rx="0.5"/><rect x="10" y="3" width="3" height="9" rx="0.5"/><rect x="15" y="0" width="3" height="12" rx="0.5"/></svg>
      {/* wifi */}
      <svg viewBox="0 0 18 12" fill="currentColor"><path d="M9 11.5l1.4-1.4a2 2 0 0 0-2.8 0L9 11.5zM6.2 8.6l1.1-1.1a4 4 0 0 1 3.4 0l1.1 1.1a5.5 5.5 0 0 0-5.6 0zM3.3 5.7l1 1A8 8 0 0 1 14.7 6.7l1-1A9.5 9.5 0 0 0 3.3 5.7z"/></svg>
      {/* battery */}
      <svg viewBox="0 0 28 12" fill="none" stroke="currentColor" strokeWidth="1"><rect x="0.5" y="0.5" width="23" height="11" rx="2.5"/><rect x="2" y="2" width="18" height="8" rx="1.2" fill="currentColor"/><rect x="25" y="4" width="2" height="4" rx="1" fill="currentColor"/></svg>
    </span>
  </div>
);

// ── home indicator ──────────────────────────────────────────────────
const Home = () => <div className="ts-home" />;

// ── tab bar ──────────────────────────────────────────────────────────
const TabBar = ({ active = 'today' }) => (
  <nav className="ts-tabbar">
    {[
      ['today', 'Today', Ico.Today],
      ['history', 'History', Ico.History],
      ['progress', 'Progress', Ico.Progress],
      ['settings', 'Settings', Ico.Settings],
    ].map(([k, label, IcoC]) => (
      <div key={k} className={'ts-tab' + (active === k ? ' active' : '')}>
        <IcoC/>
        <span>{label}</span>
      </div>
    ))}
  </nav>
);

// ── plate stack (side view) ──────────────────────────────────────────
// Renders a bar with plates on either side, exactly mirroring loadout.
// `plates` is an array of plate weights per side (heaviest to lightest).
// Plate visual size scales with weight.
// Real-world Olympic proportions, stylised. Plate diameter relative to
// thickness roughly matches Eleiko-style training plates:
//   45 lb  450mm dia × 50mm thick  (~9 : 1)
//   25 lb  380mm × 30mm           (~12 : 1)
//   10 lb  305mm × 20mm           (~15 : 1)
//   5  lb  230mm × 16mm           (~14 : 1)
// Thicker plates are markedly taller; "change" plates step down sharply.
const PLATE_VIS = {
  45:  { h: 152, w: 11, color: '#F4F4F5', ring: '#D4D4D8' },
  35:  { h: 134, w: 10, color: '#E5E5EA', ring: '#BABABF' },
  25:  { h: 116, w: 8,  color: '#C9C9D1', ring: '#9F9FA8' },
  10:  { h: 82,  w: 5,  color: '#9D9DA6', ring: '#7C7C86' },
  5:   { h: 60,  w: 4,  color: '#7C7C86', ring: '#5C5C66' },
  2.5: { h: 44,  w: 3,  color: '#5A5A66', ring: '#42424B' },
};

// Side-view of a 7-ft Olympic bar with plates loaded against the shoulder.
// Anatomy: end-cap · sleeve (with rotating-collar ribs) · shoulder · knurled
// shaft · shoulder · sleeve · end-cap. Plates butt the shoulder heaviest-first
// and step outward toward a spring-clip clamp on the outermost plate.
function PlateStack({ plates = [45, 45], bar = 45, height = 180, showWeight = false }) {
  const total = bar + plates.reduce((s, p) => s + p * 2, 0);
  const W = 460;
  const cy = height / 2;

  // Plate sizing scales with available height (baseline = 160 vbU).
  const sc = height / 160;
  const ph = (w) => (PLATE_VIS[w]?.h || PLATE_VIS[2.5].h) * sc;
  const pw = (w) => (PLATE_VIS[w]?.w || PLATE_VIS[2.5].w) * sc;

  // Bar thicknesses (vbU). Scaled mildly so they read at small heights too.
  const SHAFT_T    = Math.max(3.5, 5.5 * sc);
  const SLEEVE_T   = Math.max(11,   15 * sc);
  const SHOULDER_T = Math.max(15,   20 * sc);
  const ENDCAP_T   = Math.max(18,   24 * sc);

  // X geometry — keep absolute, the bar should read long.
  const xEndL    = 6;
  const xEndR    = W - 6;
  const sleeveLx = 10;
  const sleeveLe = 140;
  const sleeveRx = W - 140;
  const sleeveRe = W - 10;
  const shoulderLx = sleeveLe;
  const shoulderRx = sleeveRx - 6;
  const shaftStart = shoulderLx + 6;
  const shaftEnd   = shoulderRx;

  // Plate cascade — heaviest plate first, butted against the shoulder.
  const GAP = 1.4, INSET = 1.8;
  let curL = sleeveLe - INSET;
  const leftPlates = plates.map((w) => {
    const t = pw(w);
    curL -= t;
    const x = curL;
    curL -= GAP;
    return { weight: w, x, t };
  });
  let curR = sleeveRx + INSET;
  const rightPlates = plates.map((w) => {
    const t = pw(w);
    const x = curR;
    curR += t + GAP;
    return { weight: w, x, t };
  });

  // Spring-clip clamps on the outer edge of each plate stack.
  const clipL = leftPlates.length ? leftPlates[leftPlates.length - 1] : null;
  const clipR = rightPlates.length ? rightPlates[rightPlates.length - 1] : null;

  return (
    <div style={{ position: 'relative', width: '100%', height }}>
      <svg viewBox={`0 0 ${W} ${height}`} preserveAspectRatio="xMidYMid meet"
        style={{ width: '100%', height: '100%', display: 'block', overflow: 'visible' }}>
        {/* end caps (the small bumps at the very ends of the bar) */}
        <rect x={xEndL - 4} y={cy - ENDCAP_T/2} width={4} height={ENDCAP_T} rx={1} fill="#5A5A66"/>
        <rect x={xEndR}     y={cy - ENDCAP_T/2} width={4} height={ENDCAP_T} rx={1} fill="#5A5A66"/>

        {/* rotating sleeves (where plates load) */}
        <rect x={sleeveLx} y={cy - SLEEVE_T/2} width={sleeveLe - sleeveLx} height={SLEEVE_T}
          fill="#262630" stroke="#3A3A45" strokeWidth={0.6}/>
        <rect x={sleeveRx} y={cy - SLEEVE_T/2} width={sleeveRe - sleeveRx} height={SLEEVE_T}
          fill="#262630" stroke="#3A3A45" strokeWidth={0.6}/>
        {/* sleeve ribs (texture toward the outer end of each sleeve) */}
        {Array.from({ length: 5 }).map((_, i) => (
          <rect key={'rl'+i} x={sleeveLx + 3 + i * 2.6} y={cy - SLEEVE_T/2 - 0.4}
            width={0.9} height={SLEEVE_T + 0.8} fill="#3A3A45"/>
        ))}
        {Array.from({ length: 5 }).map((_, i) => (
          <rect key={'rr'+i} x={sleeveRe - 4 - i * 2.6} y={cy - SLEEVE_T/2 - 0.4}
            width={0.9} height={SLEEVE_T + 0.8} fill="#3A3A45"/>
        ))}

        {/* shoulders — step where the rotating sleeve meets the static shaft */}
        <rect x={shoulderLx} y={cy - SHOULDER_T/2} width={6} height={SHOULDER_T} rx={0.6} fill="#5A5A66"/>
        <rect x={shoulderRx} y={cy - SHOULDER_T/2} width={6} height={SHOULDER_T} rx={0.6} fill="#5A5A66"/>

        {/* main shaft (thin, the lifter's grip area) */}
        <rect x={shaftStart} y={cy - SHAFT_T/2} width={shaftEnd - shaftStart} height={SHAFT_T}
          fill="#3A3A45" rx={1}/>
        {/* knurled center grip */}
        {Array.from({ length: 28 }).map((_, i) => {
          const mid = (shaftStart + shaftEnd) / 2;
          const x = mid - 42 + i * 3;
          return <rect key={'k'+i} x={x} y={cy - SHAFT_T/2} width={0.9} height={SHAFT_T} fill="#22222A"/>;
        })}

        {/* plates — left */}
        {leftPlates.map((p, i) => {
          const v = PLATE_VIS[p.weight] || PLATE_VIS[2.5];
          const H = ph(p.weight);
          return (
            <g key={'l'+i}>
              <rect x={p.x} y={cy - H/2} width={p.t} height={H} rx={1.6}
                fill={v.color} stroke={v.ring} strokeWidth={0.6}/>
              {/* hub recess where the sleeve passes through (subtle darker line) */}
              <rect x={p.x} y={cy - SLEEVE_T/2 + 0.5} width={p.t} height={SLEEVE_T - 1}
                fill="rgba(0,0,0,0.18)"/>
            </g>
          );
        })}
        {/* plates — right (mirrored) */}
        {rightPlates.map((p, i) => {
          const v = PLATE_VIS[p.weight] || PLATE_VIS[2.5];
          const H = ph(p.weight);
          return (
            <g key={'r'+i}>
              <rect x={p.x} y={cy - H/2} width={p.t} height={H} rx={1.6}
                fill={v.color} stroke={v.ring} strokeWidth={0.6}/>
              <rect x={p.x} y={cy - SLEEVE_T/2 + 0.5} width={p.t} height={SLEEVE_T - 1}
                fill="rgba(0,0,0,0.18)"/>
            </g>
          );
        })}

        {/* spring clips locking the outermost plate */}
        {clipL && (
          <g>
            <rect x={clipL.x - 3.5} y={cy - SLEEVE_T/2 - 3} width={2.5} height={SLEEVE_T + 6}
              rx={1} fill="#8A8A95"/>
            <rect x={clipL.x - 3.5} y={cy - SLEEVE_T/2 - 3} width={2.5} height={1.6} fill="#A1A1AA"/>
            <rect x={clipL.x - 3.5} y={cy + SLEEVE_T/2 + 1.4} width={2.5} height={1.6} fill="#A1A1AA"/>
          </g>
        )}
        {clipR && (
          <g>
            <rect x={clipR.x + clipR.t + 1} y={cy - SLEEVE_T/2 - 3} width={2.5} height={SLEEVE_T + 6}
              rx={1} fill="#8A8A95"/>
            <rect x={clipR.x + clipR.t + 1} y={cy - SLEEVE_T/2 - 3} width={2.5} height={1.6} fill="#A1A1AA"/>
            <rect x={clipR.x + clipR.t + 1} y={cy + SLEEVE_T/2 + 1.4} width={2.5} height={1.6} fill="#A1A1AA"/>
          </g>
        )}
      </svg>
      {showWeight && (
        <div style={{ position: 'absolute', top: 6, right: 8, fontFamily: 'var(--ts-mono)', fontSize: 11, color: 'var(--ts-text-mute)', letterSpacing: '-0.02em' }}>
          {total} <span style={{ color: 'var(--ts-text-dim)' }}>LB</span>
        </div>
      )}
    </div>
  );
}

// ── plate diagram (front view / abstract token stack) ───────────────
// Used in smaller / inline contexts. Shows plates as horizontal tiers.
function PlateTokens({ plates = [45, 45], dense = false }) {
  return (
    <div style={{ display: 'flex', gap: dense ? 2 : 3, alignItems: 'flex-end', height: dense ? 28 : 36 }}>
      {plates.map((w, i) => {
        const v = PLATE_VIS[w] || PLATE_VIS[2.5];
        const h = dense ? v.h * 0.17 : v.h * 0.21;
        return (
          <div key={i} style={{
            width: dense ? 6 : 7,
            height: h,
            background: v.color,
            borderRadius: 1.5,
          }}/>
        );
      })}
    </div>
  );
}

// ── set row ──────────────────────────────────────────────────────────
function SetRow({ idx, weight, reps, status = 'queued', actual, isAmrap, isWarmup, percent }) {
  const done = status === 'done';
  const current = status === 'current';
  const skipped = status === 'skipped';
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: '28px 1fr auto auto',
      alignItems: 'center',
      gap: 12,
      padding: '14px 16px',
      background: current ? (isAmrap ? 'var(--ts-accent-soft)' : 'var(--ts-surface-2)') : 'transparent',
      borderTop: '1px solid var(--ts-border)',
      borderLeft: current ? `3px solid ${isAmrap ? 'var(--ts-accent)' : 'var(--ts-text)'}` : '3px solid transparent',
      opacity: skipped ? 0.4 : 1,
    }}>
      <div className="mono" style={{
        fontSize: 11,
        color: current ? (isAmrap ? 'var(--ts-accent)' : 'var(--ts-text)') : 'var(--ts-text-dim)',
        fontWeight: 600,
        letterSpacing: '0.04em',
      }}>
        {isWarmup ? `W${idx}` : String(idx).padStart(2, '0')}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
          <span className="mono" style={{
            fontSize: 17,
            fontWeight: 600,
            color: done ? 'var(--ts-text-mute)' : 'var(--ts-text)',
            textDecoration: skipped ? 'line-through' : 'none',
          }}>{weight}</span>
          <span className="mono" style={{ fontSize: 10, color: 'var(--ts-text-dim)' }}>LB</span>
          <span className="mono" style={{ fontSize: 13, color: 'var(--ts-text-dim)', marginLeft: 4 }}>×</span>
          <span className="mono" style={{
            fontSize: 17,
            fontWeight: 600,
            color: isAmrap ? 'var(--ts-accent)' : (done ? 'var(--ts-text-mute)' : 'var(--ts-text)'),
          }}>{reps}{isAmrap && '+'}</span>
        </div>
        {percent != null && (
          <div className="mono" style={{ fontSize: 10, color: 'var(--ts-text-dim)', letterSpacing: '0.04em' }}>
            {isWarmup ? 'WARMUP · ' : ''}{percent}% TM
          </div>
        )}
      </div>
      <div>
        {isAmrap && current && (
          <span className="kicker accent" style={{ fontSize: 10 }}>AMRAP</span>
        )}
        {done && actual != null && (
          <span className="mono" style={{
            fontSize: 13,
            color: 'var(--ts-text)',
            background: isAmrap ? 'var(--ts-accent)' : 'transparent',
            padding: isAmrap ? '2px 6px' : 0,
            borderRadius: 4,
            color: isAmrap ? '#000' : 'var(--ts-text)',
            fontWeight: isAmrap ? 700 : 500,
          }}>{actual}</span>
        )}
      </div>
      <div style={{ width: 22, height: 22, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        {done && <span style={{ color: 'var(--ts-text-mute)' }}><Ico.Check/></span>}
        {skipped && <span style={{ color: 'var(--ts-text-dim)' }}><Ico.Close/></span>}
        {current && !done && !skipped && (
          <div style={{ width: 8, height: 8, borderRadius: 4, background: isAmrap ? 'var(--ts-accent)' : 'var(--ts-text)' }}/>
        )}
      </div>
    </div>
  );
}

// ── rest timer ring ──────────────────────────────────────────────────
function RestRing({ size = 56, progress = 0.6, label = '1:24', accent = false, strokeWidth = 4 }) {
  const r = (size - strokeWidth) / 2;
  const c = 2 * Math.PI * r;
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--ts-surface-3)" strokeWidth={strokeWidth}/>
        <circle cx={size/2} cy={size/2} r={r} fill="none"
          stroke={accent ? 'var(--ts-accent)' : 'var(--ts-text)'}
          strokeWidth={strokeWidth} strokeLinecap="round"
          strokeDasharray={c} strokeDashoffset={c * (1 - progress)}/>
      </svg>
      <div className="mono" style={{
        position: 'absolute', inset: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontSize: size > 80 ? 22 : 13, fontWeight: 600, letterSpacing: '-0.04em'
      }}>{label}</div>
    </div>
  );
}

// ── lift card (Today screen) ─────────────────────────────────────────
function LiftCard({ lift, abbr, weight, reps, isAmrap, status = 'queued', lastAmrap, lastWeight, e1rm }) {
  const next = status === 'next';
  const done = status === 'done';
  const skipped = status === 'skipped';
  return (
    <div style={{
      position: 'relative',
      background: next ? 'var(--ts-surface)' : 'transparent',
      border: '1px solid ' + (next ? 'var(--ts-border-2)' : 'var(--ts-border)'),
      borderRadius: 16,
      padding: '16px 16px 14px',
      opacity: skipped ? 0.45 : 1,
    }}>
      {/* status corner */}
      <div style={{ position: 'absolute', top: 14, right: 14, display: 'flex', alignItems: 'center', gap: 6 }}>
        {done && <span className="mono" style={{ fontSize: 11, color: 'var(--ts-text-mute)' }}>{lastAmrap}+ @ {lastWeight}</span>}
        {done && <span className="badge" style={{ background: 'var(--ts-surface-3)' }}><Ico.Check/></span>}
        {skipped && <span style={{ color: 'var(--ts-text-dim)' }}><Ico.Flag/></span>}
        {next && <span className="kicker accent" style={{ fontSize: 10 }}>NEXT</span>}
      </div>

      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14 }}>
        {/* abbr stamp */}
        <div style={{
          width: 44, height: 44,
          borderRadius: 10,
          background: next ? 'var(--ts-text)' : 'var(--ts-surface-2)',
          color: next ? 'var(--ts-bg)' : 'var(--ts-text-mute)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontFamily: 'var(--ts-mono)', fontWeight: 700, fontSize: 20, letterSpacing: '-0.04em',
        }}>{abbr}</div>

        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 15, fontWeight: 600, marginBottom: 8 }}>{lift}</div>

          <div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
            <span className="mono" style={{ fontSize: 28, fontWeight: 700, letterSpacing: '-0.05em', color: done ? 'var(--ts-text-mute)' : 'var(--ts-text)' }}>{weight}</span>
            <span className="mono" style={{ fontSize: 11, color: 'var(--ts-text-dim)' }}>LB</span>
            <span className="mono" style={{ fontSize: 14, color: 'var(--ts-text-dim)', marginLeft: 6, marginRight: 2 }}>×</span>
            <span className="mono" style={{ fontSize: 22, fontWeight: 600, color: isAmrap ? 'var(--ts-accent)' : 'var(--ts-text)' }}>{reps}{isAmrap && '+'}</span>
          </div>

          {/* tiny plate icon row */}
          <div style={{ marginTop: 10 }}>
            <PlateTokens plates={[45, 25, 10, 5]} dense/>
          </div>
        </div>
      </div>

      {next && (
        <div style={{
          marginTop: 14, paddingTop: 12,
          borderTop: '1px dashed var(--ts-border)',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        }}>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <span className="kicker">Top set</span>
            <span className="mono" style={{ fontSize: 12, color: 'var(--ts-text-mute)' }}>e1RM ≈ {e1rm}</span>
          </div>
          <span className="kicker accent" style={{ fontSize: 10 }}>AMRAP ›</span>
        </div>
      )}
    </div>
  );
}

// ── training week chip — "X of 4 done" with mini progress ───────────
function TrainingWeekChip({ done = 2, total = 4, week = 'W1' }) {
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10, padding: '6px 12px 6px 8px', background: 'var(--ts-surface-2)', borderRadius: 999, border: '1px solid var(--ts-border)' }}>
      <span style={{ display: 'flex', gap: 3 }}>
        {Array.from({ length: total }).map((_, i) => (
          <span key={i} style={{
            width: 6, height: 14, borderRadius: 2,
            background: i < done ? 'var(--ts-text)' : 'var(--ts-surface-3)'
          }}/>
        ))}
      </span>
      <span className="mono" style={{ fontSize: 11, color: 'var(--ts-text-mute)', letterSpacing: '0.02em' }}>
        {done}/{total} · {week}
      </span>
    </div>
  );
}

// ── bar diagram (minimal silhouette for inline use) ────────────────
function BarDiagram({ plates = [45, 45], width = 100 }) {
  const W = 230, cy = 28;
  const sleeveLx = 6, sleeveLe = 78;
  const sleeveRx = W - 78, sleeveRe = W - 6;
  const SLEEVE_T = 11;
  const tScale = 0.55, hScale = 0.32;

  // heaviest plate first, butted against the shoulder
  let curL = sleeveLe - 1.4;
  const left = plates.map((w) => {
    const v = PLATE_VIS[w] || PLATE_VIS[2.5];
    const t = v.w * tScale;
    curL -= t;
    const x = curL;
    curL -= 0.8;
    return { x, t, v };
  });
  let curR = sleeveRx + 1.4;
  const right = plates.map((w) => {
    const v = PLATE_VIS[w] || PLATE_VIS[2.5];
    const t = v.w * tScale;
    const x = curR;
    curR += t + 0.8;
    return { x, t, v };
  });

  return (
    <svg viewBox={`0 0 ${W} 56`} width={width} fill="none" style={{ overflow: 'visible' }}>
      {/* end caps */}
      <rect x="2" y={cy - 10} width="3" height="20" rx="0.6" fill="#5A5A66"/>
      <rect x={W - 5} y={cy - 10} width="3" height="20" rx="0.6" fill="#5A5A66"/>
      {/* sleeves */}
      <rect x={sleeveLx} y={cy - SLEEVE_T/2} width={sleeveLe - sleeveLx} height={SLEEVE_T}
        fill="#262630" stroke="#3A3A45" strokeWidth="0.4"/>
      <rect x={sleeveRx} y={cy - SLEEVE_T/2} width={sleeveRe - sleeveRx} height={SLEEVE_T}
        fill="#262630" stroke="#3A3A45" strokeWidth="0.4"/>
      {/* shoulders */}
      <rect x={sleeveLe} y={cy - 8} width="3" height="16" fill="#5A5A66"/>
      <rect x={sleeveRx - 3} y={cy - 8} width="3" height="16" fill="#5A5A66"/>
      {/* shaft */}
      <rect x={sleeveLe + 3} y={cy - 1.6} width={(sleeveRx - 3) - (sleeveLe + 3)} height={3.2} fill="#3A3A45"/>
      {/* knurl */}
      {Array.from({ length: 14 }).map((_, i) => (
        <rect key={i} x={W/2 - 18 + i * 2.6} y={cy - 1.6} width="0.7" height={3.2} fill="#22222A"/>
      ))}
      {/* plates */}
      {left.map((p, i) => (
        <rect key={'l'+i} x={p.x} y={cy - (p.v.h * hScale)/2}
          width={p.t} height={p.v.h * hScale} fill={p.v.color} rx="0.7" stroke={p.v.ring} strokeWidth="0.3"/>
      ))}
      {right.map((p, i) => (
        <rect key={'r'+i} x={p.x} y={cy - (p.v.h * hScale)/2}
          width={p.t} height={p.v.h * hScale} fill={p.v.color} rx="0.7" stroke={p.v.ring} strokeWidth="0.3"/>
      ))}
    </svg>
  );
}

// ── share globals ────────────────────────────────────────────────────
Object.assign(window, {
  Ico, StatusBar, Home, TabBar,
  PlateStack, PlateTokens, BarDiagram,
  SetRow, RestRing, LiftCard, TrainingWeekChip,
});
