// programs.jsx — Multi-week Programs: Browse list, active-program banner, and
// the Program detail screen (weekly split preview + "Add to calendar" flow).
// All exercises reference real free-exercise-db ids, so ExerciseThumb resolves
// demo images through the live catalog. Applying never changes a stored SHAPE —
// see data.jsx applyProgram / clearProgram and CLAUDE.md.

// Map a program's exercises → equipment buckets (Barbell/Dumbbell/…); used for
// tags + the require/exclude filter. Resolves through the live catalog.
function programEquipment(program) {
  const set = new Set();
  const ws = program.workouts || {};
  Object.keys(ws).forEach(k => (ws[k].exercises || []).forEach(e => {
    const ex = (window.exById ? window.exById(e.id) : null);
    if (ex && ex.equip) set.add(ex.equip);
  }));
  // Stable, sensible order
  const order = ['Barbell', 'Dumbbell', 'Cable', 'Machine', 'Kettlebell', 'Bodyweight', 'Bands', 'Other'];
  return order.filter(g => set.has(g));
}

function fmtDay(d) {
  const dt = typeof d === 'string' ? new Date(d + 'T00:00:00') : d;
  return dt.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' });
}
function addDaysKey(key, n) {
  const d = new Date(key + 'T00:00:00'); d.setDate(d.getDate() + n);
  return window.ymd(d);
}

// ── Active program banner ────────────────────────────────────
function ActiveProgramBanner({ activeProgram, todayKey, onView, onEnd }) {
  const c = useTheme();
  if (!activeProgram) return null;
  const prog = programProgress(activeProgram, todayKey);
  const done = prog && prog.done;
  return (
    <Card pad={0} onClick={onView} style={{ overflow: 'hidden', border: '1px solid ' + c.accent }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: 16 }}>
        <div style={{ width: 46, height: 46, borderRadius: 'var(--radius-sm)', flexShrink: 0, background: c.accent, color: c.accentInk,
          display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name={activeProgram.icon || 'dumbbell-01'} size={24} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ fontFamily: 'var(--font-body)', fontSize: 9.5, fontWeight: 800, letterSpacing: 0.7, textTransform: 'uppercase',
              color: c.accentInk, background: c.accent, padding: '2px 7px', borderRadius: 5 }}>{done ? 'Complete' : 'Active program'}</span>
          </div>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 21, textTransform: 'uppercase', letterSpacing: 0.3, color: 'var(--text)', marginTop: 6, lineHeight: 1,
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{activeProgram.title}</div>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--muted)', marginTop: 4 }}>
            {done ? 'Finished · tap to restart or pick a new one' : 'Week ' + prog.week + ' of ' + prog.totalWeeks}
          </div>
          {!done && (
            <div style={{ marginTop: 9, height: 5, borderRadius: 999, background: 'var(--surface-3)', overflow: 'hidden' }}>
              <div style={{ height: '100%', width: Math.round((prog.week / prog.totalWeeks) * 100) + '%', background: c.accent, borderRadius: 999 }} />
            </div>
          )}
        </div>
        <span style={{ color: 'var(--dim)', flexShrink: 0 }}><Icon name="chevR" size={18} /></span>
      </div>
    </Card>
  );
}

// ── Program card (browse) ────────────────────────────────────
function ProgramCard({ program, isActive, entitled, onClick, openPaywall }) {
  const c = useTheme();
  const locked = program.pro && !entitled;
  const eq = programEquipment(program);
  const handleClick = () => { if (locked) { haptic('warn'); openPaywall && openPaywall('plans'); } else onClick(); };
  return (
    <Card pad={0} onClick={handleClick} style={{ overflow: 'hidden', border: isActive ? '1px solid ' + c.accent : undefined }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: 16 }}>
        <div style={{ width: 46, height: 46, borderRadius: 'var(--radius-sm)', flexShrink: 0,
          background: isActive ? c.accent : 'var(--surface-2)', color: isActive ? c.accentInk : 'var(--muted)',
          display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name={locked ? 'lock' : (program.icon || 'dumbbell-01')} size={22} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <div style={{ flex: 1, minWidth: 0, fontFamily: 'var(--font-display)', fontSize: 20, textTransform: 'uppercase', letterSpacing: 0.3,
              color: 'var(--text)', lineHeight: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{program.title}</div>
            {isActive
              ? <span style={{ fontFamily: 'var(--font-body)', fontSize: 9, fontWeight: 800, letterSpacing: 0.6, textTransform: 'uppercase', flexShrink: 0, color: c.accentInk, background: c.accent, padding: '2px 6px', borderRadius: 5 }}>Active</span>
              : program.pro && <span style={{ fontFamily: 'var(--font-body)', fontSize: 9, fontWeight: 800, letterSpacing: 0.6, textTransform: 'uppercase', flexShrink: 0, color: c.accentInk, background: c.accent, padding: '2px 6px', borderRadius: 5 }}>Pro</span>}
          </div>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--muted)', marginTop: 3 }}>
            {program.level} · {program.daysPerWeek} days/week · {program.weeks} weeks
          </div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 6 }}>
            {eq.map(g => (
              <span key={g} style={{ fontFamily: 'var(--font-body)', fontSize: 10, fontWeight: 600, padding: '2px 7px', borderRadius: 5,
                background: 'var(--surface-3)', color: 'var(--dim)' }}>{g}</span>
            ))}
          </div>
        </div>
        {locked ? (
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, flexShrink: 0, padding: '8px 12px', borderRadius: 999,
            border: '1px solid ' + c.accent, color: c.accent, fontFamily: 'var(--font-body)', fontSize: 12, fontWeight: 700 }}>
            <Icon name="lock" size={14} /> Unlock
          </span>
        ) : (
          <span style={{ color: 'var(--dim)', flexShrink: 0 }}><Icon name="chevR" size={18} /></span>
        )}
      </div>
    </Card>
  );
}

// ── Programs browse (search + filters + grouped-by-goal) ──────
function ProgramsBrowse({ programs, activeProgram, entitled, viewProgram, openPaywall }) {
  const c = useTheme();
  const [q, setQ] = React.useState('');
  const [level, setLevel] = React.useState('All');
  const [access, setAccess] = React.useState('All');
  const [equipState, setEquip] = React.useState({});

  const LEVELS = ['Beginner', 'Intermediate', 'Advanced'];
  const GEAR_TYPES = ['Barbell', 'Dumbbell', 'Cable', 'Machine', 'Kettlebell', 'Bodyweight'];
  // Goal order for grouping
  const GOAL_ORDER = ['Beginner', 'Build muscle', 'Get stronger', 'Lose fat', 'Home / minimal'];
  const GOAL_LABEL = { 'Beginner': 'Beginner', 'Build muscle': 'Build Muscle', 'Get stronger': 'Get Stronger', 'Lose fat': 'Lose Fat', 'Home / minimal': 'Home & Minimal Kit' };

  const cycleEquip = (gear) => setEquip(s => {
    const cur = s[gear];
    if (!cur) return { ...s, [gear]: 'require' };
    if (cur === 'require') return { ...s, [gear]: 'exclude' };
    const n = { ...s }; delete n[gear]; return n;
  });

  const hasFilters = level !== 'All' || access !== 'All' || q.trim() || Object.keys(equipState).length > 0;
  const clearFilters = () => { setLevel('All'); setAccess('All'); setQ(''); setEquip({}); };

  const filtered = React.useMemo(() => {
    let ps = programs;
    if (level !== 'All') ps = ps.filter(p => p.level === level);
    if (access !== 'All') ps = ps.filter(p => access === 'Pro' ? p.pro : !p.pro);
    if (q.trim()) {
      const lq = q.toLowerCase();
      ps = ps.filter(p => p.title.toLowerCase().includes(lq) || (p.subtitle || '').toLowerCase().includes(lq) ||
        (p.goal || '').toLowerCase().includes(lq) || (p.level || '').toLowerCase().includes(lq));
    }
    const req = Object.keys(equipState).filter(g => equipState[g] === 'require');
    const exc = Object.keys(equipState).filter(g => equipState[g] === 'exclude');
    if (req.length || exc.length) {
      ps = ps.filter(p => {
        const eq = programEquipment(p);
        if (exc.some(g => eq.includes(g))) return false;
        if (req.length && !req.some(g => eq.includes(g))) return false;
        return true;
      });
    }
    return ps;
  }, [programs, level, access, q, equipState]);

  const showGrouped = level === 'All' && access === 'All' && !q.trim() && !Object.keys(equipState).length;
  const goals = showGrouped ? GOAL_ORDER.filter(g => filtered.some(p => p.goal === g)) : null;

  const card = (p) => <ProgramCard key={p.id} program={p} isActive={activeProgram && activeProgram.id === p.id}
    entitled={entitled} onClick={() => { haptic('light'); viewProgram(p.id); }} openPaywall={openPaywall} />;

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginBottom: 12 }}>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--muted)' }}>
          Multi-week routines that fill your calendar. Pick one to preview and start.
        </div>
        {hasFilters && (
          <button onClick={clearFilters} style={{ background: 'none', border: 'none', cursor: 'pointer', flexShrink: 0,
            fontFamily: 'var(--font-body)', fontSize: 12, fontWeight: 700, color: 'var(--muted)' }}>Clear</button>
        )}
      </div>

      {/* Search */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '0 14px', height: 44,
        background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 999, marginBottom: 14 }}>
        <span style={{ color: 'var(--muted)', display: 'flex' }}><Icon name="search" size={18} /></span>
        <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search programs…"
          style={{ flex: 1, background: 'none', border: 'none', outline: 'none', color: 'var(--text)', fontFamily: 'var(--font-body)', fontSize: 15 }} />
        {q && <button onClick={() => setQ('')} style={{ background: 'none', border: 'none', color: 'var(--dim)', cursor: 'pointer', display: 'flex' }}><Icon name="close" size={16} /></button>}
      </div>

      {/* Difficulty */}
      <Eyebrow style={{ marginBottom: 8 }}>Difficulty</Eyebrow>
      <div style={{ display: 'flex', gap: 8, marginBottom: 14, flexWrap: 'wrap' }}>
        {['All', ...LEVELS].map(f => <Chip key={f} active={level === f} onClick={() => setLevel(f)}>{f}</Chip>)}
      </div>

      {/* Plan tier */}
      <Eyebrow style={{ marginBottom: 8 }}>Plan</Eyebrow>
      <div style={{ display: 'flex', gap: 8, marginBottom: 14, flexWrap: 'wrap' }}>
        {['All', 'Free', 'Pro'].map(f => <Chip key={f} active={access === f} onClick={() => setAccess(f)}>{f}</Chip>)}
      </div>

      {/* Equipment 3-state */}
      <div style={{ marginBottom: 8 }}>
        <Eyebrow>Equipment</Eyebrow>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 11, color: 'var(--dim)', marginTop: 3 }}>Tap to require · tap again to exclude</div>
      </div>
      <div style={{ display: 'flex', gap: 7, marginBottom: 16, flexWrap: 'wrap' }}>
        {GEAR_TYPES.map(gear => {
          const st = equipState[gear];
          return (
            <button key={gear} onClick={() => cycleEquip(gear)} style={{
              display: 'inline-flex', alignItems: 'center', gap: 5, padding: '7px 13px', borderRadius: 999, cursor: 'pointer', border: 'none', outline: 'none', transition: 'all 0.15s',
              fontFamily: 'var(--font-body)', fontSize: 13, fontWeight: 600,
              background: st === 'require' ? c.accent : st === 'exclude' ? c.danger : 'var(--surface-2)',
              color: st === 'require' ? c.accentInk : st === 'exclude' ? '#fff' : 'var(--muted)' }}>
              {st === 'require' && <Icon name="check" size={13} />}
              {st === 'exclude' && <Icon name="close" size={13} />}
              {gear}
            </button>
          );
        })}
      </div>

      {hasFilters && (
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--dim)', marginBottom: 12 }}>
          {filtered.length} program{filtered.length !== 1 ? 's' : ''} match{filtered.length === 1 ? 'es' : ''} your filters
        </div>
      )}

      {filtered.length === 0 ? (
        <Card pad={24} style={{ textAlign: 'center', color: 'var(--muted)', fontFamily: 'var(--font-body)', fontSize: 13.5 }}>No programs match your filters.</Card>
      ) : showGrouped ? (
        goals.map(goal => (
          <div key={goal} style={{ marginBottom: 22 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: 17, textTransform: 'uppercase', letterSpacing: 0.5, color: 'var(--text)', whiteSpace: 'nowrap' }}>{GOAL_LABEL[goal] || goal}</span>
              <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
              <span style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, color: 'var(--dim)', whiteSpace: 'nowrap' }}>{filtered.filter(p => p.goal === goal).length}</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              {filtered.filter(p => p.goal === goal).map(card)}
            </div>
          </div>
        ))
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>{filtered.map(card)}</div>
      )}
    </div>
  );
}

// ── Program detail screen ────────────────────────────────────
function ProgramDetail({ program, activeProgram, startProgram, endProgram, go, entitled, openPaywall, todayKey }) {
  const c = useTheme();
  const [confirm, setConfirm] = React.useState(null); // 'start' | 'end' | null
  if (!program) { React.useEffect(() => go('plan'), []); return null; }

  const isActive = activeProgram && activeProgram.id === program.id;
  const otherActive = activeProgram && activeProgram.id !== program.id;
  const locked = program.pro && !entitled;
  const eq = programEquipment(program);
  const prog = isActive ? programProgress(activeProgram, todayKey) : null;

  const weeks = program.weeks || 8;
  const throughKey = addDaysKey(todayKey, weeks * 7 - 1);
  const cycle = program.split;
  const cycleLen = cycle.length;
  const weekChunks = [];
  for (let i = 0; i < cycleLen; i += 7) weekChunks.push(cycle.slice(i, i + 7));

  const doStart = () => { setConfirm(null); startProgram(program); go('calendar'); };
  const doEnd = () => { setConfirm(null); endProgram(); };

  const dayBadge = (txt, accent) => (
    <span style={{ fontFamily: 'var(--font-body)', fontSize: 10, fontWeight: 800, letterSpacing: 0.5, textTransform: 'uppercase', whiteSpace: 'nowrap', flexShrink: 0,
      color: accent ? c.accentInk : 'var(--muted)', background: accent ? c.accent : 'var(--surface-3)', padding: '3px 8px', borderRadius: 6 }}>{txt}</span>
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18, paddingBottom: 24 }}>
      {/* Header */}
      <div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 54, height: 54, borderRadius: 'var(--radius-sm)', flexShrink: 0, background: c.accent, color: c.accentInk,
            display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name={program.icon || 'dumbbell-01'} size={28} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <Display size={28} style={{ lineHeight: 1.04 }}>{program.title}</Display>
            <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--muted)', marginTop: 7 }}>
              {program.level} · {program.daysPerWeek} days/week · {weeks} weeks
            </div>
          </div>
        </div>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 14, lineHeight: 1.5, color: 'var(--text)', marginTop: 14, textWrap: 'pretty' }}>{program.blurb}</div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 12 }}>
          {eq.map(g => (
            <span key={g} style={{ fontFamily: 'var(--font-body)', fontSize: 11, fontWeight: 600, padding: '4px 10px', borderRadius: 999,
              background: 'var(--surface-2)', border: '1px solid var(--border)', color: 'var(--muted)' }}>{g}</span>
          ))}
        </div>
      </div>

      {/* Active progress */}
      {isActive && prog && (
        <Card style={{ border: '1px solid ' + c.accent }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div>
              <Eyebrow style={{ color: c.accent }}>{prog.done ? 'Program complete' : 'In progress'}</Eyebrow>
              <div style={{ fontFamily: 'var(--font-display)', fontSize: 22, textTransform: 'uppercase', color: 'var(--text)', marginTop: 4 }}>
                {prog.done ? 'Finished' : 'Week ' + prog.week + ' / ' + prog.totalWeeks}
              </div>
            </div>
          </div>
          {!prog.done && (
            <div style={{ marginTop: 12, height: 6, borderRadius: 999, background: 'var(--surface-3)', overflow: 'hidden' }}>
              <div style={{ height: '100%', width: Math.round((prog.week / prog.totalWeeks) * 100) + '%', background: c.accent, borderRadius: 999 }} />
            </div>
          )}
        </Card>
      )}

      {/* Weekly split */}
      <div>
        <Eyebrow style={{ marginBottom: 12 }}>{cycleLen > 7 ? 'Training cycle' : 'Your training week'}</Eyebrow>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
          {weekChunks.map((chunk, wi) => (
            <div key={wi}>
              {weekChunks.length > 1 && (
                <div style={{ fontFamily: 'var(--font-display)', fontSize: 15, textTransform: 'uppercase', letterSpacing: 0.5, color: 'var(--dim)', marginBottom: 8 }}>Week {wi + 1}</div>
              )}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {chunk.map((slot, di) => {
                  const dayNum = wi * 7 + di + 1;
                  if (slot === 'rest') {
                    return (
                      <div key={di} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 16px', borderRadius: 'var(--radius-sm)',
                        background: 'var(--surface)', border: '1px dashed var(--border)' }}>
                        {dayBadge('Day ' + dayNum, false)}
                        <span style={{ fontFamily: 'var(--font-body)', fontSize: 14, fontWeight: 600, color: 'var(--muted)' }}>Rest day</span>
                      </div>
                    );
                  }
                  const w = program.workouts[slot];
                  if (!w) return null;
                  return (
                    <Card key={di} pad={0} style={{ overflow: 'hidden' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '13px 16px 11px' }}>
                        {dayBadge('Day ' + dayNum, true)}
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontFamily: 'var(--font-display)', fontSize: 19, textTransform: 'uppercase', letterSpacing: 0.3, color: 'var(--text)', lineHeight: 1 }}>{w.title}</div>
                          <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--muted)', marginTop: 3 }}>{w.subtitle} · {w.exercises.length} exercises</div>
                        </div>
                      </div>
                      <div style={{ borderTop: '1px solid var(--border)' }}>
                        {w.exercises.map((e, ei) => {
                          const ex = window.exById ? window.exById(e.id) : { name: e.id };
                          const sets = e.sets.length;
                          const reps = e.sets[0] ? e.sets[0].reps : 0;
                          return (
                            <div key={ei} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 16px', borderTop: ei === 0 ? 'none' : '1px solid var(--border)' }}>
                              <ExerciseThumb id={e.id} size={42} />
                              <div style={{ flex: 1, minWidth: 0 }}>
                                <div style={{ fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 14.5, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ex.name}</div>
                                <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--muted)', marginTop: 2 }}>{ex.muscle || ''}{ex.gear ? ' · ' + ex.gear : ''}</div>
                              </div>
                              <div style={{ fontFamily: 'var(--font-display)', fontSize: 16, color: c.accent, flexShrink: 0 }}>{sets}×{reps}</div>
                            </div>
                          );
                        })}
                      </div>
                    </Card>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Action */}
      <div style={{ marginTop: 4 }}>
        {isActive ? (
          <button onClick={() => setConfirm('end')} style={{ width: '100%', padding: '16px 20px', borderRadius: 'var(--radius-sm)', cursor: 'pointer',
            fontFamily: 'var(--font-display)', fontSize: 17, letterSpacing: 0.5, textTransform: 'uppercase',
            background: 'var(--surface-2)', color: c.danger, border: '1px solid ' + c.danger }}>End Program</button>
        ) : locked ? (
          <AccentButton icon={<Icon name="lock" size={18} />} onClick={() => openPaywall && openPaywall('plans')}>Unlock with Pro</AccentButton>
        ) : (
          <AccentButton icon={<Icon name="calendar" size={18} />} onClick={() => setConfirm('start')}>Add to Calendar</AccentButton>
        )}
        {!isActive && !locked && (
          <div style={{ textAlign: 'center', fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--dim)', marginTop: 10 }}>
            Starts today · fills {weeks} weeks · logged days are kept
          </div>
        )}
      </div>

      {/* Confirm overlay */}
      {confirm && (
        <FrameModal onClose={() => setConfirm(null)}>
            {confirm === 'start' ? (
              <div>
                <Display size={24}>{otherActive ? 'Switch program?' : 'Add to calendar?'}</Display>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginTop: 16 }}>
                  <ConfirmRow icon="calendar" title="Starts today" body={fmtDay(todayKey) + ' is Day 1. Runs through ' + fmtDay(throughKey) + ' (' + weeks + ' weeks).'} />
                  <ConfirmRow icon="bolt" title="Replaces future days" body={'Every scheduled day from today onward in that window is overwritten with this program.'} accent />
                  <ConfirmRow icon="check" title="Your logged workouts are safe" body={'Days you\u2019ve already completed are never changed.'} />
                  {otherActive && <ConfirmRow icon="trash" title={'Replaces ' + activeProgram.title} body={'Your current program ends and this one takes over.'} />}
                </div>
                <div style={{ display: 'flex', gap: 10, marginTop: 22 }}>
                  <button onClick={() => setConfirm(null)} style={{ flex: 1, padding: '14px', borderRadius: 'var(--radius-sm)', cursor: 'pointer',
                    fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 14, background: 'var(--surface-2)', color: 'var(--text)', border: '1px solid var(--border)' }}>Cancel</button>
                  <AccentButton onClick={doStart} style={{ flex: 1, width: 'auto' }}>Add to Calendar</AccentButton>
                </div>
              </div>
            ) : (
              <div>
                <Display size={24}>End this program?</Display>
                <div style={{ fontFamily: 'var(--font-body)', fontSize: 14, lineHeight: 1.5, color: 'var(--muted)', marginTop: 12, textWrap: 'pretty' }}>
                  Upcoming program days from today onward will be cleared from your calendar. Workouts you\u2019ve already logged stay in your history.
                </div>
                <div style={{ display: 'flex', gap: 10, marginTop: 22 }}>
                  <button onClick={() => setConfirm(null)} style={{ flex: 1, padding: '14px', borderRadius: 'var(--radius-sm)', cursor: 'pointer',
                    fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 14, background: 'var(--surface-2)', color: 'var(--text)', border: '1px solid var(--border)' }}>Keep It</button>
                  <button onClick={doEnd} style={{ flex: 1, padding: '14px', borderRadius: 'var(--radius-sm)', cursor: 'pointer',
                    fontFamily: 'var(--font-display)', fontSize: 16, textTransform: 'uppercase', letterSpacing: 0.5, background: c.danger, color: '#fff', border: 'none' }}>End Program</button>
                </div>
              </div>
            )}
        </FrameModal>
      )}
    </div>
  );
}

function ConfirmRow({ icon, title, body, accent }) {
  const c = useTheme();
  return (
    <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
      <div style={{ width: 34, height: 34, borderRadius: 9, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
        background: accent ? c.accent : 'var(--surface-2)', color: accent ? c.accentInk : 'var(--muted)', border: accent ? 'none' : '1px solid var(--border)' }}>
        <Icon name={icon} size={17} />
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 14, color: 'var(--text)' }}>{title}</div>
        <div style={{ fontFamily: 'var(--font-body)', fontSize: 12.5, color: 'var(--muted)', marginTop: 2, lineHeight: 1.45 }}>{body}</div>
      </div>
    </div>
  );
}

// ── Program picker (bottom sheet, opened from the Calendar) ───
// Lets the user choose a multi-week program to set on their calendar, OR drop
// down into the custom weekly-routine editor to build their own week.
function ProgramPickerSheet({ onClose, programs = [], activeProgram, entitled, viewProgram, openRoutine, routineSummaryText }) {
  const c = useTheme();
  const GOAL_ORDER = ['Beginner', 'Build muscle', 'Get stronger', 'Lose fat', 'Home / minimal'];
  const GOAL_LABEL = { 'Beginner': 'Beginner', 'Build muscle': 'Build Muscle', 'Get stronger': 'Get Stronger', 'Lose fat': 'Lose Fat', 'Home / minimal': 'Home & Minimal Kit' };
  const goals = GOAL_ORDER.filter(g => programs.some(p => p.goal === g));

  const row = (p) => {
    const locked = p.pro && !entitled;
    const isActive = activeProgram && activeProgram.id === p.id;
    return (
      <button key={p.id} onClick={() => { haptic('light'); viewProgram(p.id); }} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px', textAlign: 'left', cursor: 'pointer', width: '100%',
        background: isActive ? c.accent + '14' : 'var(--surface-2)', border: '1px solid ' + (isActive ? c.accent : 'var(--border)'), borderRadius: 'var(--radius-sm)' }}>
        <div style={{ width: 40, height: 40, borderRadius: 'var(--radius-sm)', flexShrink: 0, background: c.accent, color: c.accentInk, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name={p.icon || 'dumbbell-01'} size={20} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
            <div style={{ flex: 1, minWidth: 0, fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 15, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title}</div>
            {isActive
              ? <span style={{ fontFamily: 'var(--font-body)', fontSize: 9, fontWeight: 800, letterSpacing: 0.5, textTransform: 'uppercase', flexShrink: 0, color: c.accentInk, background: c.accent, padding: '2px 5px', borderRadius: 4 }}>Active</span>
              : p.pro && <span style={{ fontFamily: 'var(--font-body)', fontSize: 9, fontWeight: 800, letterSpacing: 0.5, textTransform: 'uppercase', flexShrink: 0, color: locked ? 'var(--muted)' : c.accentInk, background: locked ? 'var(--surface-3)' : c.accent, padding: '2px 5px', borderRadius: 4 }}>Pro</span>}
          </div>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--muted)', marginTop: 2 }}>{p.level} · {p.daysPerWeek} days/week · {p.weeks} wks</div>
        </div>
        <span style={{ color: 'var(--dim)', flexShrink: 0 }}><Icon name="chevR" size={18} /></span>
      </button>
    );
  };

  return (
    <SheetShell title="Choose a program" onClose={onClose}
      subtitle="Set a ready-made program to fill your calendar — or build your own weekly routine below.">
      {goals.map(goal => (
        <div key={goal} style={{ marginBottom: 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 9 }}>
            <span style={{ fontFamily: 'var(--font-display)', fontSize: 15, textTransform: 'uppercase', letterSpacing: 0.5, color: 'var(--text)', whiteSpace: 'nowrap' }}>{GOAL_LABEL[goal] || goal}</span>
            <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {programs.filter(p => p.goal === goal).map(row)}
          </div>
        </div>
      ))}

      {/* custom weekly routine */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '6px 0 12px' }}>
        <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
        <span style={{ fontFamily: 'var(--font-body)', fontSize: 11, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: 'var(--dim)' }}>or build your own</span>
        <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
      </div>
      <button onClick={() => { haptic('light'); openRoutine(); }} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px', width: '100%', textAlign: 'left', cursor: 'pointer',
        background: 'var(--surface)', border: '1px dashed var(--border)', borderRadius: 'var(--radius-sm)' }}>
        <div style={{ width: 40, height: 40, borderRadius: 'var(--radius-sm)', flexShrink: 0, background: 'var(--surface-2)', color: c.accent, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name="repeat" size={20} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 15, color: 'var(--text)' }}>Custom weekly routine</div>
          <div style={{ fontFamily: 'var(--font-body)', fontSize: 12, color: 'var(--muted)', marginTop: 2 }}>{routineSummaryText || 'Assign a workout to each weekday yourself'}</div>
        </div>
        <span style={{ color: 'var(--dim)', flexShrink: 0 }}><Icon name="chevR" size={18} /></span>
      </button>
    </SheetShell>
  );
}

Object.assign(window, { ActiveProgramBanner, ProgramCard, ProgramsBrowse, ProgramDetail, ProgramPickerSheet, programEquipment });
