// runner.jsx — "Session Runner": one-circuit-per-page live workout mode.
//
// From the 7/1 design session with Mike Albright:
//   1. Note/flag consistency — the note + pain-flag icons always sit
//      attached to the exercise title, in the same place on every screen.
//      Every circuit here pages round-by-round, and the exercise title +
//      note/flag repeat above every round bucket — identically whether the
//      circuit has one exercise or several. (The companion fix for the
//      table-based Main Sets screen — giving single-exercise circuits the
//      same round-bucket treatment InterleavedBlock already had — lives in
//      interleaved.jsx / circuits.jsx, not here.)
//   2. Edit overlay — one "Edit circuit" button above "Next circuit" on
//      every page. Add round / Subtract round (confirm — truncates the
//      last round for every exercise), Swap exercise (one-tap instant
//      replace), Search/change exercise (keyword + filter chips, or build
//      a custom exercise by hand).
//
// This is a NEW screen (route 'main-sets-run'), additive to the existing
// table-based Main Sets screen — not a replacement. Main Sets stays the
// detailed number-entry view; this is the swipeable "run the session" view.
// Reachable from the "Run session" pill next to "Print view" on Main Sets.
//
// Notes and pain/feedback reuse the SAME NoteEditor + FeedbackModal already
// wired at the App level (not a second, parallel capture UI) — that's the
// literal meaning of "same place on every screen."

// ── helpers ──────────────────────────────────────────────────────────────
function srWeightVals(weight) {
  if (weight == null) return [];
  const list = Array.isArray(weight) ? weight : [weight];
  return list.map(w => (w && typeof w === 'object') ? w.value : w).filter(v => v != null && v !== '');
}
function srFmtWeight(weight, unit) {
  const vals = srWeightVals(weight);
  if (!vals.length) return null;
  return vals.join(' · ') + ' ' + unit;
}
// Quiet focus sub-line — only what THIS exercise declares as its point.
function srFocusBits(ex, set) {
  const focus = ex.focusColumns || [];
  const bits = [];
  if (focus.includes('tempo') && set.tempo) bits.push({ k: 'Tempo', v: set.tempo });
  if (focus.includes('rpe')   && set.rpe != null && set.rpe !== '') bits.push({ k: 'RPE', v: set.rpe });
  if (focus.includes('equip') && set.equip != null) {
    const vals = srWeightVals(set.equip);
    if (vals.length) bits.push({ k: 'Equip', v: vals.join(' · ') });
  }
  return bits;
}

// ── rest helpers ─────────────────────────────────────────────────────────
function parseRestSeconds(rest) {
  if (typeof rest === 'number') return rest;
  const m = String(rest || '').match(/\d+/);
  return m ? parseInt(m[0], 10) : 60;
}
function roundTo5(n) { return Math.max(0, Math.round(n / 5) * 5); }

// ── exercise swap/search library ────────────────────────────────────────
// PLACEHOLDER DATA — Mike's real exercise database isn't wired up yet
// (data.jsx has no searchable/taggable exercise catalog). Swap and Search
// draw from this small demo pool until real data exists. See integration
// report for what real data would need (systemName/shortName/fullName +
// searchable tags + a default set template, same shape as this array).
const EXERCISE_LIBRARY = [
  { systemName: 'JumpingJacks',   shortName: 'Jumping Jacks',    fullName: 'Jumping jacks, hands free',                 tags: ['jumping', 'hands-free', 'cardio'],        template: { reps: '30s', weight: null, rpe: 7 } },
  { systemName: 'HighKnees',      shortName: 'High Knees',       fullName: 'High knees in place, hands free',           tags: ['jumping', 'hands-free', 'cardio'],        template: { reps: '30s', weight: null, rpe: 7 } },
  { systemName: 'MountainClimb',  shortName: 'Mountain Climbers',fullName: 'Mountain climbers from a plank',            tags: ['jumping', 'core', 'cardio', 'hands-free'],template: { reps: '30s', weight: null, rpe: 8 } },
  { systemName: 'SkaterHops',     shortName: 'Skater Hops',      fullName: 'Lateral skater hops, hands free',           tags: ['jumping', 'legs', 'hands-free', 'cardio'],template: { reps: 16, weight: null, rpe: 7 } },
  { systemName: 'BoxStepUps',     shortName: 'Box Step-ups',     fullName: 'Box step-ups, alternating legs',            tags: ['legs', 'step'],                           template: { reps: 12, weight: null } },
  { systemName: 'GobletSquat',    shortName: 'Goblet Squat',     fullName: 'Goblet squat with dumbbell at chest',       tags: ['legs', 'squat'],                          template: { reps: 12, weight: 20 } },
  { systemName: 'WalkingLunge',   shortName: 'Walking Lunge',    fullName: 'Walking lunges, alternating legs',          tags: ['legs', 'lunge'],                          template: { reps: 12, weight: 10 } },
  { systemName: 'PlankHold',      shortName: 'Plank Hold',       fullName: 'Forearm plank hold',                        tags: ['core', 'hands-free'],                     template: { reps: '40s', weight: null } },
  { systemName: 'BicycleCrunch',  shortName: 'Bicycle Crunch',   fullName: 'Bicycle crunches, head cradled',            tags: ['core'],                                   template: { reps: 20, weight: null } },
  { systemName: 'BicepsCurl',     shortName: 'Biceps Curl',      fullName: 'Standing dumbbell biceps curl, supinated',  tags: ['upper', 'arms'],                          template: { reps: 12, weight: 15 } },
  { systemName: 'ShoulderPress',  shortName: 'Shoulder Press',   fullName: 'Seated dumbbell shoulder press',            tags: ['upper', 'shoulders'],                     template: { reps: 10, weight: 12 } },
  { systemName: 'ChestPress',     shortName: 'Chest Press',      fullName: 'Cable chest press, wide elbows',            tags: ['upper', 'chest'],                         template: { reps: 12, weight: 20, tempo: '2-1-2' } },
];
const SEARCH_FILTERS = ['jumping', 'hands-free', 'cardio', 'legs', 'core', 'upper', 'squat', 'lunge'];

// Build a fresh exercise object from a library/custom item, repeated across
// the current round count so the circuit keeps its shape after a swap.
function makeExerciseFromLib(lib, rounds) {
  const t = lib.template || {};
  const focus = [];
  if (t.tempo) focus.push('tempo');
  if (t.rpe != null && t.rpe !== '') focus.push('rpe');
  const mkSet = () => ({ reps: t.reps ?? 10, weight: t.weight ?? null, tempo: t.tempo ?? null, rpe: t.rpe ?? null, equip: t.equip ?? null, done: false });
  return {
    id: 'sw-' + Math.random().toString(36).slice(2, 8),
    systemName: lib.systemName || 'CustomExercise',
    shortName: lib.shortName || 'Custom exercise',
    fullName: lib.fullName || lib.shortName || 'Custom exercise',
    flagged: false,
    focusColumns: focus,
    sets: Array.from({ length: Math.max(1, rounds) }, mkSet),
  };
}

// Instant swap: prefer a library alternative that shares any tag with the
// current move; fall back to the first that isn't the current exercise.
function pickSwapAlternative(cur) {
  const curTags = cur.tags || [];
  const pool = EXERCISE_LIBRARY.filter(l => l.systemName !== cur.systemName);
  const tagged = pool.find(l => l.tags.some(t => curTags.includes(t)));
  return tagged || pool[0] || EXERCISE_LIBRARY[0];
}

// ── deck model ─────────────────────────────────────────────────────────────
// One page per circuit; its exercises weave round by round down the page.
// Single-exercise circuits get the same round buckets as multi (that's the
// whole point — see file header).
function buildDeck(circuits) {
  return circuits.map((c, ci) => ({ ci }));
}
// The set references (ci, ei, setIdx) that live on a given page.
function getPageRefs(page, circuits) {
  const c = circuits[page.ci];
  const refs = [];
  c.exercises.forEach((ex, ei) => ex.sets.forEach((s, i) => refs.push({ ci: page.ci, ei, setIdx: i })));
  return refs;
}
function exGlobalIndex(circuits, ci, ei) {
  let idx = 0;
  for (let c = 0; c < ci; c++) idx += circuits[c].exercises.length;
  return idx + ei;
}
function exAccent(theme, circuits, ci, ei) { return exerciseColor(theme, exGlobalIndex(circuits, ci, ei)); }
function pageAccent(theme, circuits, page) { return exAccent(theme, circuits, page.ci, 0); }
function pageAllDone(page, circuits) {
  return getPageRefs(page, circuits).every(r => circuits[r.ci].exercises[r.ei].sets[r.setIdx].done);
}

// ── root screen (routed as 'main-sets-run') ────────────────────────────────
function SessionRunnerScreen({
  theme, circuits, unit, detail, autoAdvance,
  onEditNote, onOpenFeedback, onUpdateSet,
  onAddRound, onRemoveRound, onSwapExercise, onApplyExercise, onChangeRest,
  onBack, onNav, onToast, onFinish,
}) {
  const [cur, setCur] = React.useState(0);
  const [view, setView] = React.useState('run'); // 'run' | 'search'
  const [menuOpen, setMenuOpen] = React.useState(false);
  const [editSet, setEditSet] = React.useState(null);           // { ci, ei, setIdx }
  const [editCircuitCtx, setEditCircuitCtx] = React.useState(null); // { ci }
  const [searchCtx, setSearchCtx] = React.useState(null);       // { ci, ei }
  const [finished, setFinished] = React.useState(false);
  const [anim, setAnim] = React.useState('');

  const deck = React.useMemo(() => buildDeck(circuits), [circuits]);
  React.useEffect(() => { setCur(c => Math.min(Math.max(0, c), Math.max(0, deck.length - 1))); }, [deck.length]);

  const flash = (m) => { onToast && onToast(m); };

  const totals = React.useMemo(() => {
    let total = 0, done = 0;
    circuits.forEach(c => c.exercises.forEach(ex => ex.sets.forEach(s => { total++; if (s.done) done++; })));
    return { total, done, left: total - done };
  }, [circuits]);

  const go = (dir) => {
    setCur(prev => {
      const next = prev + dir;
      if (next < 0) return prev;
      if (next >= deck.length) { setFinished(true); return prev; }
      setAnim(dir > 0 ? 'sr-in-right' : 'sr-in-left');
      setTimeout(() => setAnim(''), 280);
      return next;
    });
  };

  const toggleDone = (ci, ei, setIdx) => {
    const ex = circuits[ci].exercises[ei];
    const s = ex.sets[setIdx];
    const newDone = !s.done;
    onUpdateSet(ex.id, setIdx, { done: newDone });
    if (autoAdvance && newDone && view === 'run') {
      const page = deck[cur];
      if (page && page.ci === ci) {
        const refs = getPageRefs(page, circuits);
        const complete = refs.every(r => (r.ci === ci && r.ei === ei && r.setIdx === setIdx)
          ? true : circuits[r.ci].exercises[r.ei].sets[r.setIdx].done);
        if (complete) setTimeout(() => go(1), 420);
      }
    }
  };

  if (!deck.length) {
    return (
      <>
        <RunnerTopBar theme={theme} title="Session" totals={totals} onBack={onBack}/>
        <div style={{ padding: '40px 18px', textAlign: 'center', color: theme.muted, fontFamily: theme.uiFamily, fontSize: 13 }}>
          No circuits in this workout yet.
        </div>
      </>
    );
  }

  if (finished) {
    return (
      <FinishScreen theme={theme} totals={totals} circuits={circuits} unit={unit}
        onDone={() => { onFinish && onFinish(); }}/>
    );
  }

  if (view === 'search') {
    return (
      <>
        <RunnerTopBar theme={theme} title="Change exercise" totals={totals} backIsClose
          onBack={() => { setSearchCtx(null); setView('run'); }}/>
        <SearchExerciseScreen theme={theme}
          current={searchCtx ? circuits[searchCtx.ci].exercises[searchCtx.ei] : null}
          onPick={(lib) => {
            if (searchCtx) { onApplyExercise(searchCtx.ci, searchCtx.ei, lib); flash(`Changed → ${lib.shortName}`); }
            setSearchCtx(null); setView('run');
          }}
          onCancel={() => { setSearchCtx(null); setView('run'); }}/>
      </>
    );
  }

  const page = deck[Math.min(cur, deck.length - 1)];

  return (
    <>
      <style>{runnerCss}</style>
      <RunnerTopBar theme={theme} title="Session" totals={totals} showProgress showTools
        onBack={onBack} onMenu={() => setMenuOpen(true)}/>

      <Runner theme={theme} page={page} deck={deck} circuits={circuits} cur={cur} unit={unit} detail={detail} anim={anim}
        onToggle={toggleDone}
        onEdit={(ci, ei, setIdx) => setEditSet({ ci, ei, setIdx })}
        onNote={(ci, ei) => onEditNote('exercise', circuits[ci].exercises[ei].id, circuits[ci].exercises[ei].shortName)}
        onPain={(ci, ei) => onOpenFeedback({ exerciseId: circuits[ci].exercises[ei].id, exerciseName: circuits[ci].exercises[ei].shortName })}
        onEditCircuit={(ci) => setEditCircuitCtx({ ci })}
        onChangeRest={onChangeRest}
        onPrev={() => go(-1)} onNext={() => go(1)}/>

      {menuOpen && (
        <PowerMenu theme={theme} onClose={() => setMenuOpen(false)}
          onTable={() => { setMenuOpen(false); onNav('main-sets'); }}
          onSettings={() => { setMenuOpen(false); onNav('settings'); }}
          onPrint={() => { setMenuOpen(false); onNav('main-sets-print'); }}/>
      )}

      {editSet && (
        <SetEditSheet theme={theme} ex={circuits[editSet.ci].exercises[editSet.ei]} setIdx={editSet.setIdx} unit={unit}
          onSave={(patch) => { onUpdateSet(circuits[editSet.ci].exercises[editSet.ei].id, editSet.setIdx, patch); setEditSet(null); flash('Set updated'); }}
          onClose={() => setEditSet(null)}/>
      )}

      {editCircuitCtx && (
        <EditCircuitSheet theme={theme} circuit={circuits[editCircuitCtx.ci]} ci={editCircuitCtx.ci}
          onClose={() => setEditCircuitCtx(null)}
          onAddRound={() => onAddRound(editCircuitCtx.ci)}
          onRemoveRound={() => onRemoveRound(editCircuitCtx.ci)}
          onSwap={(ei) => onSwapExercise(editCircuitCtx.ci, ei)}
          onSearch={(ei) => { setSearchCtx({ ci: editCircuitCtx.ci, ei }); setEditCircuitCtx(null); setView('search'); }}/>
      )}
    </>
  );
}

// ── top bar: title + glanceable progress + ··· ──────────────────────────────
function RunnerTopBar({ theme, title, totals, showProgress, showTools, backIsClose, onMenu, onBack }) {
  const t = totals || { total: 0, done: 0, left: 0 };
  const pct = t.total ? Math.round((t.done / t.total) * 100) : 0;
  const mins = Math.max(0, Math.round(t.left * 1.3));
  return (
    <div style={{ position: 'sticky', top: 0, zIndex: 20, background: theme.bg, padding: '18px 18px 12px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <button onClick={onBack} style={srIconBtn(theme)} aria-label={backIsClose ? 'Close' : 'Back'}>
          <Icon name={backIsClose ? 'close' : 'chevronLeft'} size={backIsClose ? 18 : 20} color={theme.text} strokeWidth={2.2}/>
        </button>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: theme.displayFamily, fontSize: 21, fontWeight: 700, letterSpacing: -0.4, lineHeight: 1.1, color: theme.text }}>{title}</div>
        </div>
        {showTools && (
          <button onClick={onMenu} style={srIconBtn(theme)} aria-label="More">
            <svg width="20" height="6" viewBox="0 0 22 6"><circle cx="3" cy="3" r="2.6" fill={theme.muted}/><circle cx="11" cy="3" r="2.6" fill={theme.muted}/><circle cx="19" cy="3" r="2.6" fill={theme.muted}/></svg>
          </button>
        )}
      </div>
      {showProgress && (
        <>
          <div style={{ marginTop: 14, display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
            <div style={{ fontFamily: theme.monoFamily, fontSize: 12, fontWeight: 600, color: theme.muted, letterSpacing: 0.3 }}>
              {t.done} / {t.total} sets
            </div>
            <div style={{ fontFamily: theme.monoFamily, fontSize: 12, fontWeight: 600, color: theme.muted }}>
              {t.left === 0 ? 'all done' : `≈ ${mins} min left`}
            </div>
          </div>
          <div style={{ marginTop: 7, height: 6, borderRadius: 9999, background: exRgba(theme.primary, 0.14), overflow: 'hidden' }}>
            <div style={{ width: `${pct}%`, height: '100%', borderRadius: 9999, background: theme.primary, transition: 'width 0.35s ease' }}/>
          </div>
        </>
      )}
    </div>
  );
}

// ── runner: pages through the deck ─────────────────────────────────────────
function Runner({ theme, page, deck, circuits, cur, unit, detail, anim, onToggle, onEdit, onNote, onPain, onEditCircuit, onChangeRest, onPrev, onNext }) {
  const circuit = circuits[page.ci];
  const isLast = cur === deck.length - 1;
  const isFirst = cur === 0;
  const allDone = pageAllDone(page, circuits);

  // swipe
  const startX = React.useRef(null);
  const onDown = (e) => { startX.current = (e.touches ? e.touches[0].clientX : e.clientX); };
  const onUp = (e) => {
    if (startX.current == null) return;
    const x = (e.changedTouches ? e.changedTouches[0].clientX : e.clientX);
    const dx = x - startX.current; startX.current = null;
    if (dx < -55) onNext(); else if (dx > 55) onPrev();
  };

  return (
    <div style={{ padding: '8px 18px 210px' }}>
      {/* page position dots */}
      <div style={{ display: 'flex', gap: 5, padding: '6px 2px 14px' }}>
        {deck.map((p, i) => (
          <div key={i} style={{
            flex: 1, height: 3, borderRadius: 9999,
            background: i === cur ? pageAccent(theme, circuits, p)
              : (pageAllDone(p, circuits) ? exRgba(theme.success, 0.55) : exRgba(theme.text, 0.10)),
            transition: 'background 0.3s',
          }}/>
        ))}
      </div>

      <div key={cur} className={anim} onPointerDown={onDown} onPointerUp={onUp} style={{ touchAction: 'pan-y' }}>
        <CircuitPage theme={theme} circuit={circuit} ci={page.ci} circuits={circuits} unit={unit} detail={detail}
          onToggle={onToggle} onEdit={onEdit} onNote={onNote} onPain={onPain} onChangeRest={onChangeRest}/>
      </div>

      <NavBar theme={theme} allDone={allDone} isLast={isLast} isFirst={isFirst}
        onEdit={() => onEditCircuit(page.ci)} onPrev={onPrev} onNext={onNext}/>
    </div>
  );
}

// ── page content ────────────────────────────────────────────────────────────
function ContextLine({ theme, accent, label, sub }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: theme.monoFamily, fontSize: 10.5, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: accent }}>
        <span style={{ width: 8, height: 8, borderRadius: 3, background: accent }}/>{label}
      </span>
      {sub && <span style={{ fontFamily: theme.monoFamily, fontSize: 10.5, color: theme.muted }}>{sub}</span>}
    </div>
  );
}
function HeadTools({ theme, onNote, onPain, size = 16 }) {
  return (
    <div style={{ display: 'flex', gap: 6, flexShrink: 0 }}>
      <button onClick={onNote} style={srGhostBtn(theme)} aria-label="Note"><Icon name="notes" size={size} color={theme.muted} strokeWidth={2}/></button>
      <button onClick={onPain} style={srGhostBtn(theme)} aria-label="Pain"><Icon name="flag" size={size} color={theme.muted} strokeWidth={2}/></button>
    </div>
  );
}

// A plain, trainer-editable rest line. The seconds tap to edit and round to
// nearest 5.
function RestLine({ theme, circuit, ci, rounds, onChangeRest }) {
  const secs = parseRestSeconds(circuit.rest);
  const [editing, setEditing] = React.useState(false);
  const [val, setVal] = React.useState(String(secs));
  React.useEffect(() => { setVal(String(secs)); }, [secs]);

  const commit = () => {
    const n = parseInt(val, 10);
    const rounded = isNaN(n) ? secs : roundTo5(n);
    onChangeRest && onChangeRest(ci, rounded);
    setEditing(false);
  };

  return (
    <div style={{ fontSize: 13.5, color: theme.muted, marginTop: 6, display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
      <span style={{ fontWeight: 700, color: theme.text }}>{rounds} rounds</span>
      <span>· rest</span>
      {editing ? (
        <input autoFocus value={val} onChange={e => setVal(e.target.value.replace(/[^\d]/g, ''))}
          onBlur={commit} onKeyDown={e => { if (e.key === 'Enter') commit(); }}
          style={{ width: 46, padding: '2px 6px', borderRadius: 8, border: `1px solid ${theme.primary}`,
            background: theme.surface, color: theme.text, fontFamily: theme.monoFamily, fontSize: 13, fontWeight: 700,
            outline: 'none', textAlign: 'center' }}/>
      ) : (
        <button onClick={() => setEditing(true)} title="Tap to edit — rounds to nearest 5s" style={{
          padding: '2px 9px', borderRadius: 9999, cursor: 'pointer',
          border: `1px dashed ${exRgba(theme.text, 0.28)}`, background: 'transparent',
          color: theme.text, fontFamily: theme.monoFamily, fontSize: 13, fontWeight: 700,
        }}>{secs}s</button>
      )}
      <span>between each round</span>
    </div>
  );
}

// One circuit, round by round. Every round repeats the exercise title +
// note/flag directly above that exercise's set for the round — this is the
// consistency rule from the design session, and it applies identically
// whether the circuit has one exercise or several.
function CircuitPage({ theme, circuit, ci, circuits, unit, detail, onToggle, onEdit, onNote, onPain, onChangeRest }) {
  const accent = exAccent(theme, circuits, ci, 0);
  const rounds = Math.max(1, circuit.rounds || Math.max(...circuit.exercises.map(e => e.sets.length)));
  const refs = getPageRefs({ ci }, circuits);
  const done = refs.filter(r => circuits[r.ci].exercises[r.ei].sets[r.setIdx].done).length;
  const roundBorder = `1.5px solid ${exRgba(theme.text, theme.isDark ? 0.22 : 0.16)}`;

  return (
    <>
      <ContextLine theme={theme} accent={accent} label={`Circuit ${ci + 1} · ${KIND_LABEL[circuit.kind] || 'Set'}`}
        sub={`${done}/${refs.length} logged`}/>
      <div style={{ fontFamily: theme.displayFamily, fontSize: 27, fontWeight: 800, letterSpacing: -0.6, lineHeight: 1.12, color: theme.text }}>{circuit.label}</div>
      <RestLine theme={theme} circuit={circuit} ci={ci} rounds={rounds} onChangeRest={onChangeRest}/>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 14, marginTop: 20 }}>
        {Array.from({ length: rounds }).map((_, r) => {
          const roundItems = circuit.exercises
            .map((ex, ei) => ({ ex, ei, s: ex.sets[r] }))
            .filter(o => o.s);
          const rDone = roundItems.filter(o => o.s.done).length;
          const rAll = roundItems.length > 0 && rDone === roundItems.length;
          return (
            <div key={r} style={{
              borderRadius: 20, padding: '13px 13px 15px',
              border: rAll ? `1.5px solid ${exRgba(theme.success, 0.4)}` : roundBorder,
              background: rAll ? exRgba(theme.success, 0.08) : exRgba(accent, theme.isDark ? 0.12 : 0.07),
              transition: 'background 0.3s ease, border-color 0.3s ease',
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginBottom: 12, paddingLeft: 2 }}>
                <div style={{
                  width: 30, height: 30, borderRadius: 9999, flexShrink: 0,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  background: rAll ? theme.success : exRgba(accent, 0.16),
                  color: rAll ? '#fff' : accent,
                  fontFamily: theme.monoFamily, fontSize: 13, fontWeight: 700,
                  transition: 'background 0.3s ease',
                }}>
                  {rAll ? <Icon name="check" size={16} color="#fff" strokeWidth={3}/> : (r + 1)}
                </div>
                <div style={{ flex: 1, minWidth: 0, fontSize: 15.5, fontWeight: 700, letterSpacing: -0.2, color: theme.text }}>Round {r + 1}</div>
                <div style={{ fontFamily: theme.monoFamily, fontSize: 11, fontWeight: 600, color: rAll ? theme.success : theme.muted, transition: 'color 0.3s' }}>
                  {rAll ? 'done' : `${rDone}/${roundItems.length}`}
                </div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {roundItems.map(({ ex, ei, s }) => {
                  const exC = exAccent(theme, circuits, ci, ei);
                  return (
                    <div key={ei}>
                      {/* Exercise title + note/flag — repeated above every round
                          bucket so the note/flag always sits opposite the title,
                          identically for single- and multi-exercise circuits. */}
                      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8, paddingLeft: 2 }}>
                        <span style={{ width: 9, height: 9, borderRadius: 3, background: exC, flexShrink: 0 }}/>
                        <div style={{ flex: 1, minWidth: 0, fontSize: 15, fontWeight: 700, letterSpacing: -0.2, lineHeight: 1.15, color: theme.text }}>
                          {detail === 'basic' ? ex.shortName : ex.fullName}
                        </div>
                        <HeadTools theme={theme} size={15} onNote={() => onNote(ci, ei)} onPain={() => onPain(ci, ei)}/>
                      </div>
                      <SetCard theme={theme} accent={exC} set={s} idx={r} ex={ex} unit={unit} detail={detail} hideIdx
                        onToggle={() => onToggle(ci, ei, r)} onEdit={() => onEdit(ci, ei, r)}/>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
    </>
  );
}

function SetCard({ theme, accent, set, idx, ex, unit, detail, hideIdx, onToggle, onEdit }) {
  const done = !!set.done;
  const reps = set.reps;
  const repPart = (typeof reps === 'number') ? `${reps} reps` : `${reps}`;
  const wPart = srFmtWeight(set.weight, unit);
  const focus = detail === 'basic' ? [] : srFocusBits(ex, set);

  return (
    <div style={{
      position: 'relative', display: 'flex', alignItems: 'center', gap: 14,
      padding: '16px 16px', borderRadius: 16,
      background: done ? exRgba(theme.success, 0.09) : theme.surface,
      border: `1px solid ${done ? exRgba(theme.success, 0.30) : theme.border}`,
      boxShadow: done ? 'none' : `0 1px 2px rgba(0,0,0,0.04), 0 6px 16px ${exRgba(theme.primary, 0.05)}`,
      transition: 'background 0.2s, border-color 0.2s',
    }}>
      <div style={{ position: 'absolute', left: 0, top: 10, bottom: 10, width: 4, borderRadius: 9999, background: done ? exRgba(theme.success, 0.5) : accent }}/>

      {!hideIdx && (
        <div style={{ width: 26, textAlign: 'center', flexShrink: 0, fontFamily: theme.monoFamily, fontSize: 12, fontWeight: 700, color: theme.muted }}>
          {idx + 1}
        </div>
      )}

      <div onClick={onEdit} style={{ flex: 1, minWidth: 0, cursor: 'pointer', paddingLeft: hideIdx ? 8 : 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 21, fontWeight: 700, letterSpacing: -0.3, color: theme.text }}>{repPart}</span>
          {wPart && <span style={{ fontSize: 16, fontWeight: 600, color: theme.muted }}>· {wPart}</span>}
        </div>
        {focus.length > 0 && (
          <div style={{ display: 'flex', gap: 12, marginTop: 4, flexWrap: 'wrap' }}>
            {focus.map((b, i) => (
              <span key={i} style={{ fontFamily: theme.monoFamily, fontSize: 11, color: theme.muted, whiteSpace: 'nowrap' }}>
                <span style={{ opacity: 0.7 }}>{b.k} </span><span style={{ fontWeight: 600, color: theme.text }}>{b.v}</span>
              </span>
            ))}
          </div>
        )}
      </div>

      <button onClick={onToggle} aria-label={done ? 'Logged' : 'Mark done'} style={{
        flexShrink: 0, width: 40, height: 40, borderRadius: 9999, cursor: 'pointer',
        border: done ? 'none' : `2px solid ${exRgba(theme.text, 0.18)}`,
        background: done ? theme.success : 'transparent',
        display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'border-color 0.15s', padding: 0,
      }}>
        {done && <Icon name="check" size={20} color="#fff" strokeWidth={3}/>}
      </button>
    </div>
  );
}

// ── nav bar: Edit circuit above Prev / Next circuit ─────────────────────────
function NavBar({ theme, allDone, isLast, isFirst, onEdit, onPrev, onNext }) {
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 25,
      padding: '14px 18px 30px', background: `linear-gradient(to top, ${theme.bg} 68%, ${exRgba(theme.bg, 0)})`,
      display: 'flex', flexDirection: 'column', gap: 10,
    }}>
      <button onClick={onEdit} style={{
        width: '100%', padding: '11px 16px', borderRadius: 14, cursor: 'pointer',
        background: 'transparent', border: `1px solid ${theme.border}`, color: theme.text,
        boxShadow: '0 1px 2px rgba(0,0,0,0.04)',
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        fontFamily: theme.uiFamily, fontSize: 13.5, fontWeight: 600, letterSpacing: -0.1,
      }}>
        <Icon name="edit" size={15} color={theme.muted} strokeWidth={2}/>
        Edit circuit
      </button>

      <div style={{ display: 'flex', gap: 10 }}>
        <button onClick={isFirst ? undefined : onPrev} disabled={isFirst} aria-label="Previous circuit" style={{
          flex: 1, minWidth: 0, padding: '16px 8px', borderRadius: 16,
          cursor: isFirst ? 'default' : 'pointer', border: 'none',
          background: theme.surface, color: theme.text, opacity: isFirst ? 0.4 : 1,
          boxShadow: `0 1px 2px rgba(0,0,0,0.05), inset 0 0 0 1px ${theme.border}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5,
          fontFamily: theme.uiFamily, fontSize: 15, fontWeight: 700, letterSpacing: -0.2,
        }}>
          <Icon name="chevronLeft" size={16} color={theme.text} strokeWidth={2.4}/>
          Back
        </button>

        <button onClick={onNext} style={{
          flex: 3, padding: '16px 20px', borderRadius: 16, border: 'none', cursor: 'pointer',
          background: allDone ? theme.primary : theme.surface,
          color: allDone ? theme.primaryInk : theme.text,
          boxShadow: allDone ? `0 8px 22px ${exRgba(theme.primary, 0.32)}` : `0 1px 2px rgba(0,0,0,0.05), inset 0 0 0 1px ${theme.border}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
          fontFamily: theme.uiFamily, fontSize: 16, fontWeight: 700, letterSpacing: -0.2,
          transition: 'box-shadow 0.2s',
        }}>
          {isLast ? (allDone ? 'Finish workout' : 'Skip to finish') : 'Next circuit'}
          <Icon name="chevron" size={17} color={allDone ? theme.primaryInk : theme.text} strokeWidth={2.4}/>
        </button>
      </div>
    </div>
  );
}

// ── finish ────────────────────────────────────────────────────────────────
function FinishScreen({ theme, totals, circuits, unit, onDone }) {
  let volume = 0;
  circuits.forEach(c => c.exercises.forEach(ex => ex.sets.forEach(s => {
    if (!s.done) return;
    const reps = typeof s.reps === 'number' ? s.reps : 0;
    srWeightVals(s.weight).forEach(w => { volume += reps * (Number(w) || 0); });
  })));
  const mins = Math.round(totals.total * 1.3);
  return (
    <div style={{ padding: '30px 22px 40px', display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', minHeight: 460, justifyContent: 'center' }}>
      <div style={{ width: 76, height: 76, borderRadius: 9999, background: exRgba(theme.success, 0.14), display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 22 }}>
        <Icon name="check" size={38} color={theme.success} strokeWidth={2.6}/>
      </div>
      <div style={{ fontFamily: theme.displayFamily, fontSize: 28, fontWeight: 800, letterSpacing: -0.6, color: theme.text }}>Session complete</div>
      <div style={{ fontSize: 14.5, color: theme.muted, marginTop: 8, lineHeight: 1.5, maxWidth: 260 }}>
        Everything's logged. Notes and numbers are saved to this workout.
      </div>
      <div style={{ display: 'flex', gap: 10, marginTop: 28, width: '100%' }}>
        <FinishStat theme={theme} big={`${totals.done}`} label="sets logged"/>
        <FinishStat theme={theme} big={`${mins}m`} label="duration"/>
        <FinishStat theme={theme} big={volume >= 1000 ? `${(volume/1000).toFixed(1)}k` : `${volume}`} label={`${unit} volume`}/>
      </div>
      <button onClick={onDone} style={{
        marginTop: 30, padding: '14px 22px', borderRadius: 14, border: 'none', cursor: 'pointer',
        background: theme.primary, color: theme.primaryInk, fontFamily: theme.uiFamily, fontSize: 15, fontWeight: 700,
        boxShadow: `0 8px 22px ${exRgba(theme.primary, 0.3)}`,
      }}>Done</button>
    </div>
  );
}
function FinishStat({ theme, big, label }) {
  return (
    <div style={{ flex: 1, padding: '16px 8px', borderRadius: 14, background: theme.surface, border: `1px solid ${theme.border}` }}>
      <div style={{ fontFamily: theme.monoFamily, fontSize: 22, fontWeight: 700, color: theme.text }}>{big}</div>
      <div style={{ fontSize: 11, color: theme.muted, marginTop: 4 }}>{label}</div>
    </div>
  );
}

// ── ··· menu — links out to the real table / settings / print screens ──────
function PowerMenu({ theme, onClose, onTable, onSettings, onPrint }) {
  return (
    <SheetShell theme={theme} title="Workout tools" onClose={onClose}>
      <div style={{ fontSize: 12.5, color: theme.muted, lineHeight: 1.5, marginBottom: 16 }}>
        The session view stays focused on logging. Detailed number entry, columns, and print all live here.
      </div>
      <MenuRow theme={theme} icon="expand" title="Full table view" sub="Main Sets — detailed set entry" onClick={onTable}/>
      <MenuRow theme={theme} icon="gear" title="Settings" sub="Columns, units, auto-advance" onClick={onSettings}/>
      <MenuRow theme={theme} icon="notes" title="Print / share plan" sub="Clean printable sheet" onClick={onPrint} isLast/>
    </SheetShell>
  );
}
function MenuRow({ theme, icon, title, sub, onClick, isLast }) {
  return (
    <div onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 13, padding: '13px 2px', cursor: 'pointer',
      borderBottom: isLast ? 'none' : `0.5px solid ${theme.border}`,
    }}>
      <div style={{ width: 34, height: 34, borderRadius: 9, flexShrink: 0, background: exRgba(theme.primary, 0.12), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name={icon} size={17} color={theme.primary} strokeWidth={2}/>
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 15, fontWeight: 600, color: theme.text }}>{title}</div>
        <div style={{ fontSize: 12, color: theme.muted, marginTop: 1 }}>{sub}</div>
      </div>
      <Icon name="chevron" size={16} color={theme.muted} strokeWidth={2}/>
    </div>
  );
}

// ── set edit sheet (progressive disclosure) ───────────────────────────────
function SetEditSheet({ theme, ex, setIdx, unit, onSave, onClose }) {
  const set = ex.sets[setIdx];
  const focus = ex.focusColumns || [];
  const initWeight = srWeightVals(set.weight);
  const single = !Array.isArray(set.weight);
  const [reps, setReps] = React.useState(set.reps ?? '');
  const [weight, setWeight] = React.useState(single ? (initWeight[0] ?? '') : initWeight.join(' · '));
  const [tempo, setTempo] = React.useState(set.tempo ?? '');
  const [rpe, setRpe] = React.useState(set.rpe ?? '');

  const save = () => {
    const patch = { reps: /^\d+$/.test(String(reps)) ? Number(reps) : reps };
    if (single) patch.weight = weight === '' ? null : (/^[\d.]+$/.test(String(weight)) ? Number(weight) : weight);
    if (focus.includes('tempo')) patch.tempo = tempo;
    if (focus.includes('rpe'))   patch.rpe = rpe === '' ? null : (/^[\d.]+$/.test(String(rpe)) ? Number(rpe) : rpe);
    onSave(patch);
  };

  return (
    <SheetShell theme={theme} title={`Set ${setIdx + 1} · ${ex.shortName}`} onClose={onClose}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <Field theme={theme} label="Reps / time"><input value={reps} onChange={e => setReps(e.target.value)} style={srInput(theme)}/></Field>
        {single && <Field theme={theme} label={`Weight (${unit})`}><input value={weight} onChange={e => setWeight(e.target.value)} style={srInput(theme)} placeholder="—"/></Field>}
        {focus.includes('tempo') && <Field theme={theme} label="Tempo" hint="ecc · pause · conc · rest"><input value={tempo} onChange={e => setTempo(e.target.value)} style={srInput(theme)} placeholder="2-0-1"/></Field>}
        {focus.includes('rpe') && <Field theme={theme} label="RPE" hint="effort 1–10"><input value={rpe} onChange={e => setRpe(e.target.value)} style={srInput(theme)}/></Field>}
      </div>
      <button onClick={save} style={srPrimaryBtn(theme)}>Save set</button>
    </SheetShell>
  );
}

// ── shared sheet shell ──────────────────────────────────────────────────────
function SheetShell({ theme, title, children, onClose }) {
  return (
    <div onClick={onClose} style={{ position: 'absolute', inset: 0, zIndex: 460, display: 'flex', alignItems: 'flex-end', background: 'rgba(10,5,3,0.4)' }}>
      <div onClick={e => e.stopPropagation()} className="sr-sheet" style={{
        width: '100%', maxHeight: '86%', overflowY: 'auto', background: theme.bg,
        borderRadius: '26px 26px 0 0', padding: '12px 20px 32px', boxShadow: '0 -10px 40px rgba(0,0,0,0.2)',
      }}>
        <div style={{ width: 38, height: 5, borderRadius: 9999, background: exRgba(theme.text, 0.16), margin: '4px auto 16px' }}/>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
          <div style={{ fontFamily: theme.displayFamily, fontSize: 18, fontWeight: 800, letterSpacing: -0.3, color: theme.text }}>{title}</div>
          <button onClick={onClose} style={srIconBtn(theme)} aria-label="Close"><Icon name="close" size={18} color={theme.muted} strokeWidth={2.2}/></button>
        </div>
        {children}
      </div>
    </div>
  );
}

// ── style atoms ───────────────────────────────────────────────────────────
function srIconBtn(theme) {
  return { width: 38, height: 38, borderRadius: 9999, border: 'none', cursor: 'pointer', background: theme.surface,
    boxShadow: `inset 0 0 0 1px ${theme.border}`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, padding: 0 };
}
function srGhostBtn(theme) {
  return { width: 34, height: 34, borderRadius: 9999, border: `1px solid ${theme.border}`, background: 'transparent', cursor: 'pointer',
    display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 0, flexShrink: 0 };
}
function srPrimaryBtn(theme) {
  return { width: '100%', marginTop: 20, padding: '15px 20px', borderRadius: 14, border: 'none', cursor: 'pointer',
    background: theme.primary, color: theme.primaryInk, fontFamily: theme.uiFamily, fontSize: 15, fontWeight: 700,
    boxShadow: `0 8px 22px ${exRgba(theme.primary, 0.3)}` };
}
function srInput(theme) {
  return { width: '100%', padding: '12px 13px', boxSizing: 'border-box', borderRadius: 11, border: `1px solid ${theme.border}`,
    background: theme.surface, color: theme.text, fontFamily: theme.uiFamily, fontSize: 15, outline: 'none' };
}
function sqBtn(theme) {
  return {
    width: 38, height: 38, borderRadius: 11, flexShrink: 0, cursor: 'pointer',
    background: 'transparent', border: `1px solid ${theme.border}`,
    display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 0,
  };
}

// ── edit-circuit overlay ─────────────────────────────────────────────────
function EditCircuitSheet({ theme, circuit, ci, onClose, onAddRound, onRemoveRound, onSwap, onSearch }) {
  const [confirmDel, setConfirmDel] = React.useState(false);
  const rounds = Math.max(1, circuit.rounds || Math.max(...circuit.exercises.map(e => e.sets.length)));
  return (
    <SheetShell theme={theme} title="Edit circuit" onClose={onClose}>
      <div style={{ fontSize: 12.5, color: theme.muted, lineHeight: 1.5, marginBottom: 16 }}>
        {circuit.label} · {rounds} rounds
      </div>

      <SheetLabel theme={theme}>Rounds</SheetLabel>
      <EditRow theme={theme} icon="plus" title="Add round" sub="Appends a round to every exercise" onClick={onAddRound}/>
      {!confirmDel ? (
        <EditRow theme={theme} icon="trash" title="Subtract round" sub={`Currently ${rounds} rounds`}
          danger onClick={() => setConfirmDel(true)} disabled={rounds <= 1} isLast/>
      ) : (
        <div style={{
          margin: '4px 0 8px', padding: '13px', borderRadius: 14,
          background: exRgba(theme.danger, 0.08), border: `1px solid ${exRgba(theme.danger, 0.3)}`,
        }}>
          <div style={{ fontSize: 13.5, fontWeight: 700, color: theme.text }}>Delete the last round?</div>
          <div style={{ fontSize: 12, color: theme.muted, marginTop: 3, lineHeight: 1.45 }}>
            Removes the last round's numbers for every exercise in this circuit — can't be undone.
          </div>
          <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
            <button onClick={() => setConfirmDel(false)} style={{
              flex: 1, padding: '11px', borderRadius: 11, border: `1px solid ${theme.border}`,
              background: 'transparent', color: theme.text, cursor: 'pointer',
              fontFamily: theme.uiFamily, fontSize: 13.5, fontWeight: 600,
            }}>Cancel</button>
            <button onClick={() => { onRemoveRound(); setConfirmDel(false); }} style={{
              flex: 1, padding: '11px', borderRadius: 11, border: 'none', cursor: 'pointer',
              background: theme.danger, color: '#fff',
              fontFamily: theme.uiFamily, fontSize: 13.5, fontWeight: 700,
            }}>Delete round</button>
          </div>
        </div>
      )}

      <div style={{ height: 10 }}/>
      <SheetLabel theme={theme}>Exercises</SheetLabel>
      {circuit.exercises.map((ex, ei) => (
        <div key={ex.id} style={{
          display: 'flex', alignItems: 'center', gap: 10, padding: '11px 2px',
          borderBottom: ei === circuit.exercises.length - 1 ? 'none' : `0.5px solid ${theme.border}`,
        }}>
          <span style={{ width: 9, height: 9, borderRadius: 3, background: exerciseColor(theme, ei), flexShrink: 0 }}/>
          <div style={{ flex: 1, minWidth: 0, fontSize: 14, fontWeight: 600, color: theme.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            {ex.shortName}
          </div>
          <button onClick={() => onSwap(ei)} title="Swap — instant replace with an alternative" style={sqBtn(theme)}>
            <Icon name="swap" size={17} color={theme.primary} strokeWidth={2}/>
          </button>
          <button onClick={() => onSearch(ei)} title="Search / change exercise" style={sqBtn(theme)}>
            <Icon name="search" size={16} color={theme.text} strokeWidth={2}/>
          </button>
        </div>
      ))}
    </SheetShell>
  );
}

function SheetLabel({ theme, children }) {
  return (
    <div style={{ fontFamily: theme.monoFamily, fontSize: 10, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: theme.muted, margin: '0 0 8px 2px' }}>{children}</div>
  );
}
function EditRow({ theme, icon, title, sub, onClick, isLast, danger, disabled }) {
  return (
    <div onClick={disabled ? undefined : onClick} style={{
      display: 'flex', alignItems: 'center', gap: 13, padding: '12px 2px', cursor: disabled ? 'default' : 'pointer',
      opacity: disabled ? 0.4 : 1, borderBottom: isLast ? 'none' : `0.5px solid ${theme.border}`,
    }}>
      <div style={{
        width: 34, height: 34, borderRadius: 9, flexShrink: 0,
        background: danger ? exRgba(theme.danger, 0.12) : exRgba(theme.primary, 0.12),
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <Icon name={icon} size={17} color={danger ? theme.danger : theme.primary} strokeWidth={2}/>
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 15, fontWeight: 600, color: danger ? theme.danger : theme.text }}>{title}</div>
        <div style={{ fontSize: 12, color: theme.muted, marginTop: 1 }}>{sub}</div>
      </div>
    </div>
  );
}

// ── search / change exercise (full screen) ─────────────────────────────────
function SearchExerciseScreen({ theme, current, onPick, onCancel }) {
  const [q, setQ] = React.useState('');
  const [active, setActive] = React.useState([]);
  const [building, setBuilding] = React.useState(false);

  const toggleFilter = (f) => setActive(a => a.includes(f) ? a.filter(x => x !== f) : [...a, f]);

  const results = EXERCISE_LIBRARY.filter(l => {
    const text = (l.shortName + ' ' + l.fullName).toLowerCase();
    const matchQ = !q.trim() || text.includes(q.trim().toLowerCase());
    const matchF = active.every(f => l.tags.includes(f));
    return matchQ && matchF;
  });

  if (building) {
    return <CustomExerciseForm theme={theme} onCancel={() => setBuilding(false)} onSave={onPick}/>;
  }

  return (
    <div style={{ padding: '4px 18px 40px' }}>
      {current && (
        <div style={{ fontSize: 12.5, color: theme.muted, marginBottom: 12 }}>
          Replacing <span style={{ fontWeight: 700, color: theme.text }}>{current.shortName}</span>
        </div>
      )}

      <div style={{ position: 'relative', marginBottom: 12 }}>
        <span style={{ position: 'absolute', left: 13, top: '50%', transform: 'translateY(-50%)', display: 'flex' }}>
          <Icon name="search" size={17} color={theme.muted} strokeWidth={2}/>
        </span>
        <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="Search by keyword…"
          style={{ ...srInput(theme), paddingLeft: 40 }}/>
      </div>

      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7, marginBottom: 16 }}>
        {SEARCH_FILTERS.map(f => {
          const on = active.includes(f);
          return (
            <button key={f} onClick={() => toggleFilter(f)} style={{
              padding: '6px 12px', borderRadius: 9999, cursor: 'pointer',
              border: `1px solid ${on ? theme.primary : theme.border}`,
              background: on ? theme.primary : 'transparent',
              color: on ? theme.primaryInk : theme.muted,
              fontFamily: theme.uiFamily, fontSize: 12, fontWeight: 600,
            }}>{f}</button>
          );
        })}
      </div>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {results.map(l => (
          <div key={l.systemName} onClick={() => onPick(l)} style={{
            display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', cursor: 'pointer',
            borderRadius: 14, background: theme.surface, border: `1px solid ${theme.border}`,
          }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: -0.2, color: theme.text }}>{l.shortName}</div>
              <div style={{ fontSize: 12, color: theme.muted, marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{l.fullName}</div>
              <div style={{ display: 'flex', gap: 5, marginTop: 7, flexWrap: 'wrap' }}>
                {l.tags.map(t => (
                  <span key={t} style={{ fontFamily: theme.monoFamily, fontSize: 9.5, fontWeight: 600, color: theme.muted, padding: '2px 7px', borderRadius: 9999, background: exRgba(theme.text, 0.05) }}>{t}</span>
                ))}
              </div>
            </div>
            <div style={{ flexShrink: 0, width: 34, height: 34, borderRadius: 9999, background: exRgba(theme.primary, 0.12), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <Icon name="plus" size={18} color={theme.primary} strokeWidth={2}/>
            </div>
          </div>
        ))}
        {results.length === 0 && (
          <div style={{ padding: '24px 0', textAlign: 'center', fontSize: 13, color: theme.muted }}>No matches — try a custom exercise.</div>
        )}
      </div>

      <button onClick={() => setBuilding(true)} style={{
        width: '100%', marginTop: 16, padding: '14px', borderRadius: 14, cursor: 'pointer',
        border: `1px dashed ${exRgba(theme.text, 0.28)}`, background: 'transparent', color: theme.text,
        fontFamily: theme.uiFamily, fontSize: 14, fontWeight: 600,
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
      }}>
        <Icon name="plus" size={17} color={theme.text} strokeWidth={2}/>
        Build a custom exercise
      </button>
    </div>
  );
}

function CustomExerciseForm({ theme, onCancel, onSave }) {
  const [name, setName] = React.useState('');
  const [reps, setReps] = React.useState('');
  const [weight, setWeight] = React.useState('');
  const [rpe, setRpe] = React.useState('');
  const [tempo, setTempo] = React.useState('');

  const save = () => {
    const num = (v) => (/^[\d.]+$/.test(String(v)) ? Number(v) : v);
    const lib = {
      systemName: 'Custom' + Math.random().toString(36).slice(2, 6),
      shortName: name.trim() || 'Custom exercise',
      fullName: name.trim() || 'Custom exercise',
      tags: ['custom'],
      template: {
        reps: reps === '' ? 10 : num(reps),
        weight: weight === '' ? null : num(weight),
        rpe: rpe === '' ? null : num(rpe),
        tempo: tempo.trim() === '' ? null : tempo.trim(),
      },
    };
    onSave(lib);
  };

  return (
    <div style={{ padding: '4px 18px 40px' }}>
      <div style={{ fontFamily: theme.displayFamily, fontSize: 18, fontWeight: 800, letterSpacing: -0.3, marginBottom: 4, color: theme.text }}>Custom exercise</div>
      <div style={{ fontSize: 12.5, color: theme.muted, marginBottom: 18, lineHeight: 1.5 }}>Set your own reps, weight, RPE and tempo.</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <Field theme={theme} label="Exercise name"><input autoFocus value={name} onChange={e => setName(e.target.value)} placeholder="e.g. Single-arm row" style={srInput(theme)}/></Field>
        <Field theme={theme} label="Reps / time"><input value={reps} onChange={e => setReps(e.target.value)} placeholder="10  ·  30s" style={srInput(theme)}/></Field>
        <Field theme={theme} label="Weight (lb)"><input value={weight} onChange={e => setWeight(e.target.value)} placeholder="—" style={srInput(theme)}/></Field>
        <Field theme={theme} label="RPE" hint="effort 1–10"><input value={rpe} onChange={e => setRpe(e.target.value)} placeholder="—" style={srInput(theme)}/></Field>
        <Field theme={theme} label="Tempo" hint="ecc · pause · conc"><input value={tempo} onChange={e => setTempo(e.target.value)} placeholder="2-0-1" style={srInput(theme)}/></Field>
      </div>
      <div style={{ display: 'flex', gap: 10, marginTop: 22 }}>
        <button onClick={onCancel} style={{ flex: 1, padding: '15px', borderRadius: 14, border: `1px solid ${theme.border}`, background: 'transparent', color: theme.text, cursor: 'pointer', fontFamily: theme.uiFamily, fontSize: 15, fontWeight: 600 }}>Cancel</button>
        <button onClick={save} style={{ flex: 2, padding: '15px', borderRadius: 14, border: 'none', background: theme.primary, color: theme.primaryInk, cursor: 'pointer', fontFamily: theme.uiFamily, fontSize: 15, fontWeight: 700, boxShadow: `0 8px 22px ${exRgba(theme.primary, 0.3)}` }}>Add exercise</button>
      </div>
    </div>
  );
}

const runnerCss = `
  .sr-in-right { animation: srInRight 0.26s ease; }
  .sr-in-left  { animation: srInLeft 0.26s ease; }
  @keyframes srInRight { from { transform: translateX(22px); } to { transform: none; } }
  @keyframes srInLeft  { from { transform: translateX(-22px); } to { transform: none; } }
  .sr-sheet { animation: srSheet 0.28s cubic-bezier(0.22,1,0.36,1); }
  @keyframes srSheet { from { transform: translateY(16px); } to { transform: none; } }
`;

Object.assign(window, {
  SessionRunnerScreen, EXERCISE_LIBRARY, SEARCH_FILTERS,
  makeExerciseFromLib, pickSwapAlternative, buildDeck,
});
