// ═══ GENESIS BUILD coach-m9-grupos-canonicos · 2026-07-12 ═══
// ═══ GENESIS BUILD coach-vivo-ui · 2026-07-11 ═══
// Tidal — Coach (módulo de operação): tela única consolidada por aluno.
// Busca de aluno (nome/CPF/lista) → carrega dados → edição via modais estilo DMS.
const COACH_TK = () => localStorage.getItem('genesis_token');
const COACH_INP = { width: '100%', boxSizing: 'border-box', minWidth: 0 };
const coachCard = { background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 16, padding: '15px 17px', boxShadow: 'var(--shadow-sm)' };
const coachHdr = () => ({ headers: { Authorization: `Bearer ${COACH_TK()}` } });
const coachJSON = (m, b) => ({ method: m, headers: { Authorization: `Bearer ${COACH_TK()}`, 'Content-Type': 'application/json' }, body: JSON.stringify(b) });
const coachDmBR = iso => (iso || '').slice(5).split('-').reverse().join('/');
const MEDIDA_CAMPOS = [['peso', 'Peso (kg)'], ['gordura', 'Gordura (%)'], ['massa_magra', 'Massa magra (kg)'], ['cintura', 'Cintura (cm)'], ['peitoral', 'Peitoral (cm)'], ['braco', 'Braço (cm)'], ['coxa', 'Coxa (cm)']];
const matchBank = (bank, ex) => bank.find(b => (ex.exercise_id && b.id === ex.exercise_id) || (b.nome || '').toLowerCase() === (ex.nome || '').toLowerCase());

async function coachUpload(file) {
  const fd = new FormData(); fd.append('photo', file, (file && file.name) || 'frame.jpg');
  const r = await fetch('/api/upload/photo', { method: 'POST', headers: { Authorization: `Bearer ${COACH_TK()}` }, body: fd });
  if (!r.ok) throw new Error('upload falhou'); return (await r.json()).url;
}
async function coachUploadVideo(file) {
  const fd = new FormData(); fd.append('video', file);
  const r = await fetch('/api/upload/video', { method: 'POST', headers: { Authorization: `Bearer ${COACH_TK()}` }, body: fd });
  if (!r.ok) { const d = await r.json().catch(() => ({})); throw new Error(d.error || 'upload falhou'); } return (await r.json()).url;
}
// captura o primeiro frame do vídeo como imagem estática (poster)
function captureFirstFrame(file) {
  return new Promise(resolve => {
    try {
      const url = URL.createObjectURL(file);
      const v = document.createElement('video');
      v.muted = true; v.preload = 'auto'; v.src = url;
      const done = blob => { URL.revokeObjectURL(url); resolve(blob); };
      v.onloadeddata = () => { try { v.currentTime = Math.min(0.1, (v.duration || 1) / 2); } catch (e) { done(null); } };
      v.onseeked = () => {
        try {
          const c = document.createElement('canvas');
          c.width = v.videoWidth || 320; c.height = v.videoHeight || 320;
          c.getContext('2d').drawImage(v, 0, 0, c.width, c.height);
          c.toBlob(b => done(b), 'image/jpeg', 0.82);
        } catch (e) { done(null); }
      };
      v.onerror = () => done(null);
    } catch (e) { resolve(null); }
  });
}
const DIA_FULL = { Seg: 'Segunda', Ter: 'Terça', Qua: 'Quarta', Qui: 'Quinta', Sex: 'Sexta', 'Sáb': 'Sábado', Dom: 'Domingo' };

// ── Mídia do exercício: vídeo que dá play no hover/toque, ou imagem ──
const ExerciseMedia = ({ media_url, image_url, size = 46, radius = 10 }) => {
  const box = { width: size, height: size, borderRadius: radius, overflow: 'hidden', background: 'var(--cream-2)', flexShrink: 0, position: 'relative', display: 'grid', placeItems: 'center' };
  const playV = e => { const v = e.currentTarget.querySelector('video'); if (v) { const p = v.play(); if (p && p.catch) p.catch(() => {}); } };
  const stopV = e => { const v = e.currentTarget.querySelector('video'); if (v) { v.pause(); v.currentTime = 0; } };
  if (media_url) return (
    <div style={box} onMouseEnter={playV} onMouseLeave={stopV} onTouchStart={playV} title="execução">
      <video src={media_url} muted loop playsInline preload="metadata" poster={image_url || undefined} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
      <span style={{ position: 'absolute', bottom: 2, right: 2, fontSize: 9, background: 'rgba(0,0,0,0.55)', color: '#fff', borderRadius: 4, padding: '0 3px', lineHeight: '13px' }}>▶</span>
    </div>
  );
  if (image_url) return <div style={box}><img src={image_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /></div>;
  return <div style={box}><span style={{ fontSize: size > 60 ? 26 : 16 }}>🏋️</span></div>;
};

// ── Modal genérico estilo DMS ──
const CoachModal = ({ title, onClose, children, wide }) => (
  <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 9000, background: 'rgba(31,42,46,0.45)', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', padding: '4vh 16px', overflowY: 'auto' }}>
    <div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: wide ? 780 : 560, background: 'var(--cream)', borderRadius: 20, boxShadow: 'var(--shadow-lg)', border: '1px solid var(--line-soft)', overflow: 'hidden', marginBottom: 40 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '18px 22px', borderBottom: '1px solid var(--line-soft)' }}>
        <div style={{ fontFamily: 'var(--fs)', fontSize: 24, letterSpacing: '-0.5px', fontWeight: 400 }}>{title}</div>
        <button className="btn ghost btn-sm" onClick={onClose}><Icon n="x" size={14} /></button>
      </div>
      <div style={{ padding: 22 }}>{children}</div>
    </div>
  </div>
);

// ═══════════ BANCO DE EXERCÍCIOS (modal) ═══════════
const CoachBankModal = ({ onClose, toast, onChange }) => {
  const lang = useT().lang;
  const [bank, setBank] = useState([]);
  const [edit, setEdit] = useState(null);
  const [busy, setBusy] = useState('');
  const [regioes, setRegioes] = useState([]);   // filtro pelo mapa muscular (fitkit)
  const toggleRegiao = id => setRegioes(rs => rs.includes(id) ? rs.filter(x => x !== id) : [...rs, id]);
  const load = () => fetch('/api/saude/exercises', coachHdr()).then(r => r.ok ? r.json() : []).then(d => setBank(Array.isArray(d) ? d : []));
  useEffect(() => { load(); }, []);

  const salvar = async () => {
    if (!edit.nome) { toast.push({ icon: 'x', title: 'Nome é obrigatório' }); return; }
    if (!edit.grupo || !FIT_GRUPOS.includes(edit.grupo)) { toast.push({ icon: 'x', title: 'Escolhe o grupo muscular (região do boneco)' }); return; }
    const isNew = !edit.id;
    const r = await fetch(`/api/saude/exercises${isNew ? '' : '/' + edit.id}`, coachJSON(isNew ? 'POST' : 'PUT', edit));
    if (r.ok) { setEdit(null); await load(); onChange && onChange(); toast.push({ icon: 'check', title: isNew ? 'Exercício criado' : (lang==='pt'?'Atualizado':'Updated') }); }
    else toast.push({ icon: 'x', title: 'Erro ao salvar' });
  };
  const excluir = async (id) => { if (!window.confirm('Excluir do banco?')) return; const r = await fetch(`/api/saude/exercises/${id}`, { method: 'DELETE', ...coachHdr() }); if (r.ok) { await load(); onChange && onChange(); } };
  const onVid = async e => {
    const f = e.target.files && e.target.files[0]; if (!f) return;
    setBusy('vid');
    try {
      const vurl = await coachUploadVideo(f);
      let poster = edit.image_url;
      try { const blob = await captureFirstFrame(f); if (blob) poster = await coachUpload(blob); } catch (x) {}
      setEdit(s => ({ ...s, media_url: vurl, image_url: poster }));
    } catch (x) { toast.push({ icon: 'x', title: x.message || 'Falha no vídeo' }); }
    finally { setBusy(''); }
  };

  if (edit) return (
    <CoachModal title={edit.id ? <>Editar <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>exercício.</em></> : <>Novo <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>exercício.</em></>} onClose={() => setEdit(null)}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 2fr', gap: 10 }}>
          <div><label className="label">Grupo (região do boneco)</label>
            <select className="input select" style={COACH_INP} value={edit.grupo || ''} onChange={e => setEdit(s => ({ ...s, grupo: e.target.value }))}>
              <option value="">— escolhe o grupo —</option>
              {FIT_GRUPOS.map(g => <option key={g} value={g}>{g}</option>)}
            </select>
          </div>
          <div><label className="label">Nome *</label><input className="input" style={COACH_INP} value={edit.nome || ''} onChange={e => setEdit(s => ({ ...s, nome: e.target.value }))} /></div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <div><label className="label">Séries padrão</label><input className="input" type="number" style={COACH_INP} value={edit.def_series || ''} onChange={e => setEdit(s => ({ ...s, def_series: e.target.value }))} /></div>
          <div><label className="label">Reps padrão</label><input className="input" style={COACH_INP} value={edit.def_reps || ''} onChange={e => setEdit(s => ({ ...s, def_reps: e.target.value }))} placeholder="8-10, 12, 45s…" /></div>
        </div>
        <div><label className="label">{lang==='pt'?'Instrução de execução':'Execution instruction'}</label><textarea className="input" rows={3} style={COACH_INP} value={edit.instrucao || ''} onChange={e => setEdit(s => ({ ...s, instrucao: e.target.value }))} /></div>
        <div>
          <label className="label">{lang==='pt'?'Vídeo de execução (loop no hover)':'Execution video (loops on hover)'}</label>
          <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
            <ExerciseMedia media_url={edit.media_url} image_url={edit.image_url} size={64} />
            <div>
              <label className="btn btn-sm" style={{ cursor: 'pointer' }}>{busy === 'vid' ? 'enviando…' : (edit.media_url ? 'Trocar vídeo' : 'Enviar vídeo')}<input type="file" accept="video/*" style={{ display: 'none' }} onChange={onVid} /></label>
              <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)', marginTop: 6 }}>clipe curto e mudo · a imagem estática é o 1º frame do vídeo</div>
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 6 }}>
          <button className="btn" onClick={() => setEdit(null)}>{lang==='pt'?'Voltar':'Back'}</button>
          <button className="btn btn-primary" onClick={salvar}>Salvar</button>
        </div>
      </div>
    </CoachModal>
  );

  const filtrado = regioes.length ? bank.filter(b => fitRegioesDe(b).some(id => regioes.includes(id))) : bank;
  const grupos = [...new Set(filtrado.map(b => b.grupo || 'Geral'))].sort();
  return (
    <CoachModal title="Banco de exercícios" onClose={onClose} wide>
      {/* 🧍 filtro pelo corpo (componente da raiz fitkit) */}
      <div style={{ background: 'var(--cream-2)', borderRadius: 14, padding: '12px 10px 8px', marginBottom: 14 }}>
        <FitMapaMuscular selecionadas={regioes} onToggle={toggleRegiao} lang={lang} />
        {regioes.length ? (
          <div style={{ textAlign: 'center', marginTop: 4 }}>
            <button className="btn ghost btn-sm" onClick={() => setRegioes([])}>✕ {lang === 'pt' ? 'limpar filtro' : 'clear'}</button>
          </div>
        ) : null}
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14, flexWrap: 'wrap', gap: 8 }}>
        <div style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--muted)' }}>
          {filtrado.length}{regioes.length ? ` / ${bank.length}` : ''} exercícios{regioes.length ? ` · ${regioes.map(id => (FIT_REGIOES.find(r => r.id === id) || {}).nome).join(' + ')}` : ''}
        </div>
        <button className="btn btn-primary btn-sm" onClick={() => setEdit({ grupo: '', nome: '', musculo: '', instrucao: '', video_url: '', image_url: '', media_url: '', def_series: '', def_reps: '' })}>＋ Novo exercício</button>
      </div>
      {!filtrado.length ? <div className="empty" style={{ padding: 24, textAlign: 'center' }}>{lang === 'pt' ? 'nenhum exercício cadastrado pra esse músculo — cria o primeiro 👆' : 'no exercises for this muscle yet.'}</div> : null}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {grupos.map(g => (
          <div key={g}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 8 }}>{g}</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {filtrado.filter(b => (b.grupo || 'Geral') === g).map(b => (
                <div key={b.id} style={{ display: 'flex', alignItems: 'center', gap: 10, border: '1px solid var(--line-soft)', borderRadius: 10, padding: '8px 10px' }}>
                  <ExerciseMedia media_url={b.media_url} image_url={b.image_url} size={42} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 500 }}>{b.nome}</div>
                    <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{b.musculo || '—'} · {b.def_series || '?'}×{b.def_reps || '?'}</div>
                  </div>
                  <button className="btn btn-sm" onClick={() => setEdit({ ...b })}>{lang==='pt'?'editar':'edit'}</button>
                  <button className="btn ghost btn-sm" style={{ color: 'var(--rose)' }} onClick={() => excluir(b.id)}>✕</button>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>
    </CoachModal>
  );
};

// ═══════════ EDITAR TREINO (modal) ═══════════
const DIAS = ['Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb', 'Dom'];
const CoachPlanModal = ({ athleteId, bank, onClose, onSaved, toast }) => {
  const lang = useT().lang;
  const [week, setWeek] = useState(null);
  const [saving, setSaving] = useState(false);
  const [showBank, setShowBank] = useState(false);
  const [localBank, setLocalBank] = useState(bank || []);
  const [drag, setDrag] = useState(null);
  useEffect(() => {
    fetch(`/api/saude/plan/${athleteId}`, coachHdr()).then(r => r.ok ? r.json() : null).then(p => {
      const wk = (p && p.week) ? p.week : [];
      setWeek(DIAS.map(d => wk.find(x => x.day === d) || { day: d, focus: '', nota: '', exercises: [] }));
    });
  }, [athleteId]);
  const reloadBank = () => fetch('/api/saude/exercises', coachHdr()).then(r => r.ok ? r.json() : []).then(d => setLocalBank(Array.isArray(d) ? d : []));

  const upDay = (di, patch) => setWeek(w => w.map((d, i) => i === di ? { ...d, ...patch } : d));
  const addEx = (di, exId) => { const be = localBank.find(b => b.id === Number(exId)); if (!be) return; upDay(di, { exercises: [...week[di].exercises, { exercise_id: be.id, nome: be.nome, series: be.def_series || 3, reps: be.def_reps || '12', carga: '' }] }); };
  const upEx = (di, ei, patch) => setWeek(w => w.map((d, i) => i === di ? { ...d, exercises: d.exercises.map((e, j) => j === ei ? { ...e, ...patch } : e) } : d));
  const rmEx = (di, ei) => setWeek(w => w.map((d, i) => i === di ? { ...d, exercises: d.exercises.filter((_, j) => j !== ei) } : d));
  const dropEx = (di, ei) => {
    if (!drag || drag.di !== di) { setDrag(null); return; }
    setWeek(w => w.map((d, i) => { if (i !== di) return d; const ex = [...d.exercises]; const [m] = ex.splice(drag.ei, 1); ex.splice(ei, 0, m); return { ...d, exercises: ex }; }));
    setDrag(null);
  };
  const salvar = async () => { setSaving(true); const r = await fetch(`/api/saude/plan/${athleteId}`, coachJSON('PUT', { demo: false, atualizado: new Date().toISOString().split('T')[0], week })); setSaving(false); if (r.ok) { toast.push({ icon: 'check', title: 'Treino salvo' }); onSaved && onSaved(); onClose(); } else toast.push({ icon: 'x', title: 'Erro ao salvar' }); };

  const colLabel = { fontFamily: 'var(--fm)', fontSize: 9.5, letterSpacing: 0.5, textTransform: 'uppercase', color: 'var(--accent)', textAlign: 'center' };
  const cell = w => ({ width: w, boxSizing: 'border-box', padding: '6px', textAlign: 'center' });

  return (
    <CoachModal title={<>Editar <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>treino.</em></>} onClose={onClose} wide>
      {!week ? <div className="empty" style={{ padding: 30 }}>{lang==='pt'?'carregando…':'loading…'}</div> : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
          {week.map((d, di) => (
            <div key={d.day}>
              <div style={{ fontFamily: 'var(--fs)', fontSize: 19, letterSpacing: '-0.3px', marginBottom: 8 }}>{DIA_FULL[d.day] || d.day}<em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>.</em></div>
              <div style={{ marginBottom: 8 }}>
                <label className="label">{lang==='pt'?'Foco do dia':'Focus of the day'}</label>
                <input className="input" style={COACH_INP} placeholder="Peito + Tríceps / Descanso…" value={d.focus} onChange={e => upDay(di, { focus: e.target.value })} />
              </div>
              {d.exercises.length > 0 && (
                <div style={{ display: 'flex', gap: 6, alignItems: 'center', padding: '0 4px 4px' }}>
                  <span style={{ width: 16 }} />
                  <span style={{ width: 40 }} />
                  <span style={{ flex: 1, minWidth: 80, ...colLabel, textAlign: 'left' }}>Exercício</span>
                  <span style={{ ...colLabel, width: 52 }}>Séries</span>
                  <span style={{ ...colLabel, width: 64 }}>Reps</span>
                  <span style={{ ...colLabel, width: 80 }}>Carga</span>
                  <span style={{ width: 30 }} />
                </div>
              )}
              {d.exercises.map((ex, ei) => (
                <div key={ei} onDragOver={e => e.preventDefault()} onDrop={() => dropEx(di, ei)}
                  style={{ display: 'flex', gap: 6, alignItems: 'center', marginBottom: 6, opacity: drag && drag.di === di && drag.ei === ei ? 0.4 : 1, border: '1px solid var(--line-soft)', borderRadius: 10, padding: '6px 8px', background: 'var(--cream-2)' }}>
                  <span draggable onDragStart={() => setDrag({ di, ei })} onDragEnd={() => setDrag(null)} title="arrastar" style={{ width: 16, cursor: 'grab', color: 'var(--muted)', fontSize: 15, textAlign: 'center', userSelect: 'none' }}>⠿</span>
                  <ExerciseMedia {...(matchBank(localBank, ex) || {})} size={40} radius={8} />
                  <span style={{ flex: 1, minWidth: 80, fontSize: 13 }}>{ex.nome}</span>
                  <input className="input" style={cell(52)} value={ex.series} onChange={e => upEx(di, ei, { series: e.target.value })} />
                  <input className="input" style={cell(64)} value={ex.reps} onChange={e => upEx(di, ei, { reps: e.target.value })} />
                  <input className="input" style={cell(80)} placeholder="kg" value={ex.carga} onChange={e => upEx(di, ei, { carga: e.target.value })} />
                  <button className="btn ghost btn-sm" style={{ width: 30 }} onClick={() => rmEx(di, ei)}>✕</button>
                </div>
              ))}
              <select className="input" style={{ ...COACH_INP, marginTop: 4 }} value="" onChange={e => { addEx(di, e.target.value); e.target.value = ''; }}>
                <option value="">＋ adicionar exercício do banco…</option>
                {localBank.map(b => <option key={b.id} value={b.id}>{b.grupo} · {b.nome}</option>)}
              </select>
            </div>
          ))}
          <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap', borderTop: '1px solid var(--line-soft)', paddingTop: 16 }}>
            <button className="btn" onClick={() => setShowBank(true)}>{lang==='pt'?'Banco de exercícios':'Exercise bank'}</button>
            <button className="btn btn-primary" onClick={salvar} disabled={saving}>{saving ? '…' : 'Salvar treino'}</button>
          </div>
        </div>
      )}
      {showBank && <CoachBankModal onClose={() => setShowBank(false)} toast={toast} onChange={reloadBank} />}
    </CoachModal>
  );
};

// ═══════════ EDITAR DIETA (modal) ═══════════
const CoachDietModal = ({ athleteId, onClose, onSaved, toast }) => {
  const lang = useT().lang;
  const [diet, setDiet] = useState(null);
  const [saving, setSaving] = useState(false);
  useEffect(() => {
    fetch(`/api/saude/diet/${athleteId}`, coachHdr()).then(r => r.ok ? r.json() : null).then(d => setDiet(d && d.refeicoes ? d : { meta_kcal: 2000, macros: { proteina: 150, carbo: 200, gordura: 60 }, agua_meta: 2.5, refeicoes: [] }));
  }, [athleteId]);
  const up = patch => setDiet(s => ({ ...s, ...patch }));
  const upMacro = (k, v) => setDiet(s => ({ ...s, macros: { ...s.macros, [k]: Number(v) || 0 } }));
  const addMeal = () => up({ refeicoes: [...diet.refeicoes, { refeicao: '', hora: '', kcal: 0, macros: { p: 0, c: 0, f: 0 }, alimentos: [], substituicoes: [] }] });
  const upMeal = (i, patch) => setDiet(s => ({ ...s, refeicoes: s.refeicoes.map((m, j) => j === i ? { ...m, ...patch } : m) }));
  const upMealMacro = (i, k, v) => setDiet(s => ({ ...s, refeicoes: s.refeicoes.map((m, j) => j === i ? { ...m, macros: { ...m.macros, [k]: Number(v) || 0 } } : m) }));
  const rmMeal = i => setDiet(s => ({ ...s, refeicoes: s.refeicoes.filter((_, j) => j !== i) }));
  const salvar = async () => { setSaving(true); const r = await fetch(`/api/saude/diet/${athleteId}`, coachJSON('PUT', { ...diet, demo: false, atualizado: new Date().toISOString().split('T')[0] })); setSaving(false); if (r.ok) { toast.push({ icon: 'check', title: (lang==='pt'?'Dieta salva':'Diet saved') }); onSaved && onSaved(); onClose(); } else toast.push({ icon: 'x', title: 'Erro ao salvar' }); };

  return (
    <CoachModal title={<>Editar <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>dieta.</em></>} onClose={onClose} wide>
      {!diet ? <div className="empty" style={{ padding: 30 }}>{lang==='pt'?'carregando…':'loading…'}</div> : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 10 }}>{lang==='pt'?'metas diárias':'daily goals'}</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(110px,1fr))', gap: 10 }}>
              <div><label className="label">kcal</label><input className="input" type="number" style={COACH_INP} value={diet.meta_kcal || ''} onChange={e => up({ meta_kcal: Number(e.target.value) || 0 })} /></div>
              <div><label className="label">Proteína g</label><input className="input" type="number" style={COACH_INP} value={diet.macros.proteina || ''} onChange={e => upMacro('proteina', e.target.value)} /></div>
              <div><label className="label">Carbo g</label><input className="input" type="number" style={COACH_INP} value={diet.macros.carbo || ''} onChange={e => upMacro('carbo', e.target.value)} /></div>
              <div><label className="label">Gordura g</label><input className="input" type="number" style={COACH_INP} value={diet.macros.gordura || ''} onChange={e => upMacro('gordura', e.target.value)} /></div>
              <div><label className="label">Água L</label><input className="input" type="number" step="0.1" style={COACH_INP} value={diet.agua_meta || ''} onChange={e => up({ agua_meta: Number(e.target.value) || 0 })} /></div>
            </div>
          </div>
          {diet.refeicoes.map((m, i) => (
            <div key={i} style={{ border: '1px solid var(--line-soft)', borderRadius: 12, padding: '12px 14px' }}>
              <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 10, flexWrap: 'wrap' }}>
                <input className="input" style={{ flex: 1, minWidth: 110, boxSizing: 'border-box' }} placeholder="Refeição" value={m.refeicao} onChange={e => upMeal(i, { refeicao: e.target.value })} />
                <input className="input" style={{ width: 80, boxSizing: 'border-box' }} placeholder="hora" value={m.hora} onChange={e => upMeal(i, { hora: e.target.value })} />
                <input className="input" type="number" style={{ width: 78, boxSizing: 'border-box' }} placeholder="kcal" value={m.kcal || ''} onChange={e => upMeal(i, { kcal: Number(e.target.value) || 0 })} />
                <button className="btn ghost btn-sm" onClick={() => rmMeal(i)}>✕</button>
              </div>
              <label className="label">Alimentos (vírgula)</label>
              <input className="input" style={{ ...COACH_INP, marginBottom: 10 }} value={(m.alimentos || []).join(', ')} onChange={e => upMeal(i, { alimentos: e.target.value.split(',').map(x => x.trim()).filter(Boolean) })} />
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 8, marginBottom: 10 }}>
                <div><label className="label">P g</label><input className="input" type="number" style={COACH_INP} value={m.macros?.p || ''} onChange={e => upMealMacro(i, 'p', e.target.value)} /></div>
                <div><label className="label">C g</label><input className="input" type="number" style={COACH_INP} value={m.macros?.c || ''} onChange={e => upMealMacro(i, 'c', e.target.value)} /></div>
                <div><label className="label">G g</label><input className="input" type="number" style={COACH_INP} value={m.macros?.f || ''} onChange={e => upMealMacro(i, 'f', e.target.value)} /></div>
              </div>
              <label className="label">Substituições (vírgula)</label>
              <input className="input" style={COACH_INP} value={(m.substituicoes || []).join(', ')} onChange={e => upMeal(i, { substituicoes: e.target.value.split(',').map(x => x.trim()).filter(Boolean) })} />
            </div>
          ))}
          <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap', borderTop: '1px solid var(--line-soft)', paddingTop: 16 }}>
            <button className="btn" onClick={addMeal}>＋ Refeição</button>
            <button className="btn btn-primary" onClick={salvar} disabled={saving}>{saving ? '…' : 'Salvar dieta'}</button>
          </div>
        </div>
      )}
    </CoachModal>
  );
};

// ═══════════ NOVA AVALIAÇÃO (modal: medidas + fotos) ═══════════
// ─── Avaliação física COMPLETA (a planilha PetroRio Wellness, digital) ───
const AVC_INP = { width: '100%', boxSizing: 'border-box', minWidth: 0 };
const AvcCampo = ({ rot, children }) => (
  <div style={{ minWidth: 0 }}>
    <label className="label" style={{ fontSize: 11 }}>{rot}</label>
    {children}
  </div>
);
const AvcSecao = ({ titulo, children }) => (
  <div style={{ marginBottom: 16 }}>
    <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: 'var(--accent)', borderBottom: '1px solid var(--line-soft)', paddingBottom: 5, marginBottom: 10 }}>{titulo}</div>
    {children}
  </div>
);

const CoachAvalCompletaModal = ({ athleteId, athlete, aval, onClose, onSaved, toast }) => {
  const lang = useT().lang;
  const [d, setD] = useState(() => (aval && aval.data) ? { dobras: {}, squat: {}, flex: {}, ...aval.data } : { sexo: 'M', protocolo: 'pollock3', dobras: {}, squat: {}, flex: {} });
  const [dia, setDia] = useState((aval && aval.dia) ? String(aval.dia).split('T')[0] : new Date().toISOString().split('T')[0]);
  const [saving, setSaving] = useState(false);
  const up = (k, v) => setD(s => ({ ...s, [k]: v }));
  const upSub = (grupo, k, v) => setD(s => ({ ...s, [grupo]: { ...(s[grupo] || {}), [k]: v } }));

  // cálculos ao vivo (o painel-prévia, como a planilha faz)
  const idade = AVAL.idade(d.nascimento || (athlete && athlete.data_nascimento));
  const imc = AVAL.imc(d.peso, d.estatura);
  const dens = d.protocolo !== 'manual' ? AVAL.densidade(d.protocolo, d.dobras || {}, idade, d.sexo || 'M') : null;
  const pctMG = d.protocolo === 'manual' ? AVAL.n(d.pct_mg) : AVAL.pctMG(dens);
  const rcq = AVAL.rcq(d.per_cintura, d.per_quadril);
  const fcmax = AVAL.n(d.fc_max) || AVAL.fcmaxTanaka(idade);
  const zonas = AVAL.zonasFC(d.fc_repouso, fcmax);
  const soma = AVAL.somaDobras(d.dobras);

  const salvar = async () => {
    setSaving(true);
    const corpo = { dia, data: { ...d, pct_mg: pctMG != null ? pctMG.toFixed(2) : d.pct_mg, massa_magra: (pctMG != null && d.peso) ? (AVAL.n(d.peso) * (1 - pctMG / 100)).toFixed(1) : d.massa_magra } };
    const r = aval && aval.id
      ? await fetch(`/api/saude/avaliacoes/${aval.id}`, coachJSON('PUT', corpo))
      : await fetch(`/api/saude/avaliacoes/${athleteId}`, coachJSON('POST', corpo));
    setSaving(false);
    if (r.ok) { toast.push({ icon: 'check', title: lang === 'pt' ? 'Avaliação completa salva 📋' : 'Assessment saved' }); onSaved && onSaved(); onClose(); }
    else toast.push({ icon: 'x', title: 'Erro ao salvar' });
  };

  const g2 = { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px,1fr))', gap: 10 };
  const num = (k, rot, step) => (
    <AvcCampo key={k} rot={rot}>
      <input className="input" type="number" step={step || '0.1'} style={AVC_INP} value={d[k] || ''} onChange={e => up(k, e.target.value)} />
    </AvcCampo>
  );

  return (
    <CoachModal title={<>{aval && aval.id ? 'Editar' : 'Nova'} avaliação <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>completa.</em></>} onClose={onClose} wide>
      {/* painel-prévia fixo: os números da planilha calculados ao vivo */}
      <div style={{ position: 'sticky', top: 0, zIndex: 5, background: 'var(--ink)', color: '#fff', borderRadius: 14, padding: '10px 16px', marginBottom: 16, display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'center', fontSize: 13 }}>
        <span>IMC <b>{AVAL.fmt(imc)}</b>{imc ? <span style={{ color: `var(--${(AVAL.classifIMC(imc) || [])[1]})`, marginLeft: 5, fontSize: 11 }}>{(AVAL.classifIMC(imc) || [])[0]}</span> : null}</span>
        <span>%MG <b>{AVAL.fmt(pctMG)}</b>{soma ? <span style={{ color: 'rgba(255,255,255,0.55)', marginLeft: 5, fontSize: 11 }}>Σ {AVAL.fmt(soma, 0)}mm</span> : null}</span>
        <span>RCQ <b>{AVAL.fmt(rcq, 2)}</b>{rcq ? <span style={{ color: `var(--${(AVAL.classifRCQ(rcq, d.sexo) || [])[1]})`, marginLeft: 5, fontSize: 11 }}>{(AVAL.classifRCQ(rcq, d.sexo) || [])[0]}</span> : null}</span>
        <span>FCmáx <b>{AVAL.fmt(fcmax, 0)}</b></span>
        {idade != null ? <span style={{ color: 'rgba(255,255,255,0.55)' }}>{idade} anos</span> : null}
      </div>

      <AvcSecao titulo="anamnese">
        <div style={g2}>
          <AvcCampo rot="Data"><input className="input" type="date" style={AVC_INP} value={dia} onChange={e => setDia(e.target.value)} /></AvcCampo>
          <AvcCampo rot="Sexo">
            <select className="select" style={AVC_INP} value={d.sexo || 'M'} onChange={e => up('sexo', e.target.value)}><option value="M">Masculino</option><option value="F">Feminino</option></select>
          </AvcCampo>
          <AvcCampo rot="Nascimento"><input className="input" type="date" style={AVC_INP} value={d.nascimento || ''} onChange={e => up('nascimento', e.target.value)} /></AvcCampo>
          <AvcCampo rot="Meta/Objetivo"><input className="input" style={AVC_INP} value={d.meta || ''} onChange={e => up('meta', e.target.value)} placeholder="Emagrecimento…" /></AvcCampo>
          <AvcCampo rot="Local de trabalho"><input className="input" style={AVC_INP} value={d.local_trabalho || ''} onChange={e => up('local_trabalho', e.target.value)} placeholder="Passadiço…" /></AvcCampo>
        </div>
        <textarea className="input" rows={2} style={{ ...AVC_INP, marginTop: 10 }} placeholder="Saúde, hábitos, medicamentos, restrições…" value={d.anamnese || ''} onChange={e => up('anamnese', e.target.value)} />
      </AvcSecao>

      <AvcSecao titulo="parâmetros fisiológicos">
        <div style={g2}>
          {num('fc_repouso', 'FC repouso (bpm)', '1')}
          {num('spo2', 'SpO² (%)', '1')}
          {num('pa_sist', 'PA sistólica', '1')}
          {num('pa_diast', 'PA diastólica', '1')}
          {num('fc_max', 'FC máx (vazio = Tanaka)', '1')}
        </div>
        {zonas.length ? (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 10 }}>
            {zonas.map(z => <span key={z.pct} style={{ background: 'var(--cream-2)', borderRadius: 8, padding: '4px 10px', fontFamily: 'var(--fm)', fontSize: 11 }}>{z.pct}% → <b>{Math.round(z.fc)}</b> bpm</span>)}
          </div>
        ) : null}
      </AvcSecao>

      <AvcSecao titulo="composição corporal">
        <div style={g2}>
          {num('peso', 'Peso (kg)')}
          {num('estatura', 'Estatura (m)', '0.01')}
          <AvcCampo rot="Protocolo de dobras">
            <select className="select" style={AVC_INP} value={d.protocolo || 'pollock3'} onChange={e => up('protocolo', e.target.value)}>
              <option value="pollock3">Pollock 3 dobras</option>
              <option value="pollock7">Pollock 7 dobras</option>
              <option value="durnin">Durnin-Womersley 4</option>
              <option value="manual">%MG manual</option>
            </select>
          </AvcCampo>
          {d.protocolo === 'manual' ? num('pct_mg', '% de gordura', '0.1') : null}
        </div>
        {d.protocolo !== 'manual' ? (
          <div style={{ ...g2, marginTop: 10 }}>
            {AVAL_DOBRAS.map(([k, rot]) => (
              <AvcCampo key={k} rot={`${rot} (mm)`}>
                <input className="input" type="number" step="0.5" style={AVC_INP} value={(d.dobras || {})[k] || ''} onChange={e => upSub('dobras', k, e.target.value)} />
              </AvcCampo>
            ))}
          </div>
        ) : null}
        {pctMG != null && d.peso ? (
          <div style={{ marginTop: 10, fontSize: 13, color: 'var(--muted)' }}>
            Massa gorda <b style={{ color: 'var(--ink)' }}>{AVAL.fmt(AVAL.n(d.peso) * pctMG / 100)} kg</b> · Massa magra <b style={{ color: 'var(--ink)' }}>{AVAL.fmt(AVAL.n(d.peso) * (1 - pctMG / 100))} kg</b>{dens ? <span> · Densidade {AVAL.fmt(dens, 4)}</span> : null}
          </div>
        ) : null}
      </AvcSecao>

      <AvcSecao titulo="perímetros (cm)">
        <div style={g2}>{AVAL_PERIMETROS.map(([k, rot]) => num(k, rot))}</div>
        <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', marginTop: 10, fontSize: 13 }}>
          {rcq ? <span>Cintura/Quadril <b>{AVAL.fmt(rcq, 2)}</b> <span style={{ color: `var(--${(AVAL.classifRCQ(rcq, d.sexo) || [])[1]})` }}>{(AVAL.classifRCQ(rcq, d.sexo) || [])[0]}</span></span> : null}
          {d.per_abdomen ? <span>Circ. abdominal <span style={{ color: `var(--${(AVAL.classifCircAbd(d.per_abdomen, d.sexo) || [])[1]})` }}>{(AVAL.classifCircAbd(d.per_abdomen, d.sexo) || [])[0]}</span></span> : null}
        </div>
      </AvcSecao>

      <AvcSecao titulo="força">
        <div style={g2}>{AVAL_FORCA.map(([k, rot]) => num(k, rot, '1'))}</div>
      </AvcSecao>

      <AvcSecao titulo="squat test — compensações observadas">
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {AVAL_SQUAT.map(([k, rot]) => (
            <button key={k} onClick={() => upSub('squat', k, !(d.squat || {})[k])} className="btn btn-sm" style={{
              background: (d.squat || {})[k] ? 'var(--rose)' : 'var(--cream-2)',
              color: (d.squat || {})[k] ? '#fff' : 'var(--ink)', border: '1px solid var(--line-soft)',
            }}>{(d.squat || {})[k] ? '⚠ ' : ''}{rot}</button>
          ))}
        </div>
      </AvcSecao>

      <AvcSecao titulo="flexibilidade e mobilidade">
        <div style={g2}>
          {AVAL_FLEX.map(([k, rot]) => (
            <AvcCampo key={k} rot={rot}>
              <select className="select" style={AVC_INP} value={(d.flex || {})[k] || ''} onChange={e => upSub('flex', k, e.target.value)}>
                <option value="">—</option><option>Bom</option><option>Regular</option><option>Regular/Assim.</option><option>Ruim</option>
              </select>
            </AvcCampo>
          ))}
          {num('wells', 'Banco de Wells (cm)')}
        </div>
      </AvcSecao>

      <AvcSecao titulo="observações">
        <textarea className="input" rows={2} style={AVC_INP} value={d.obs || ''} onChange={e => up('obs', e.target.value)} placeholder="Conduta, teste de rampa, observações gerais…" />
      </AvcSecao>

      <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, borderTop: '1px solid var(--line-soft)', paddingTop: 16 }}>
        <button className="btn" onClick={onClose}>{lang === 'pt' ? 'Cancelar' : 'Cancel'}</button>
        <button className="btn btn-primary" onClick={salvar} disabled={saving}>{saving ? '…' : (lang === 'pt' ? 'Salvar avaliação completa' : 'Save full assessment')}</button>
      </div>
    </CoachModal>
  );
};

// ─── lista de avaliações completas do atleta (painel do professor) ───
const CoachAvalLista = ({ athleteId, toast, versao }) => {
  const [avals, setAvals] = useState([]);
  const [editando, setEditando] = useState(null);
  const carregar = () => fetch(`/api/saude/avaliacoes/${athleteId}`, { headers: { Authorization: `Bearer ${COACH_TK()}` } })
    .then(r => r.ok ? r.json() : []).then(d => setAvals(Array.isArray(d) ? d : [])).catch(() => {});
  useEffect(() => { carregar(); }, [athleteId, versao]);
  const excluir = async (id) => {
    if (!confirm('Excluir esta avaliação?')) return;
    const r = await fetch(`/api/saude/avaliacoes/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${COACH_TK()}` } });
    if (r.ok) { toast.push({ icon: 'check', title: 'Avaliação excluída' }); carregar(); }
  };
  if (!avals.length) return null;
  return (
    <div style={{ marginTop: 10 }}>
      <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 6 }}>avaliações completas</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {avals.map(a => (
          <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', background: 'var(--cream-2)', borderRadius: 10 }}>
            <span style={{ flex: 1, fontSize: 13 }}>📋 {new Date(String(a.dia).split('T')[0] + 'T12:00').toLocaleDateString('pt-BR')}{(a.data || {}).meta ? <span style={{ color: 'var(--muted)' }}> · {a.data.meta}</span> : ''}</span>
            <button className="btn ghost btn-sm" onClick={() => setEditando(a)}>✎</button>
            <button className="btn ghost btn-sm" style={{ color: 'var(--rose)' }} onClick={() => excluir(a.id)}>✕</button>
          </div>
        ))}
      </div>
      {editando ? <CoachAvalCompletaModal athleteId={athleteId} aval={editando} toast={toast} onClose={() => setEditando(null)} onSaved={carregar} /> : null}
    </div>
  );
};

const CoachAvaliacaoModal = ({ athleteId, onClose, onSaved, toast }) => {
  const lang = useT().lang;
  const [form, setForm] = useState({ dia: new Date().toISOString().split('T')[0], nota: '', fotos: {} });
  const [busy, setBusy] = useState('');
  const [saving, setSaving] = useState(false);
  const upFoto = async (pos, file) => { if (!file) return; setBusy(pos); try { const u = await coachUpload(file); setForm(s => ({ ...s, fotos: { ...s.fotos, [pos]: u } })); } catch (e) { toast.push({ icon: 'x', title: 'Falha no upload' }); } finally { setBusy(''); } };
  const salvar = async () => { setSaving(true); const r = await fetch(`/api/saude/measurements/${athleteId}`, coachJSON('POST', form)); setSaving(false); if (r.ok) { toast.push({ icon: 'check', title: (lang==='pt'?'Avaliação registrada':'Assessment logged') }); onSaved && onSaved(); onClose(); } else toast.push({ icon: 'x', title: 'Erro ao salvar' }); };
  return (
    <CoachModal title={<>Nova <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>avaliação.</em></>} onClose={onClose} wide>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(130px,1fr))', gap: 10, marginBottom: 12 }}>
        <div><label className="label">Data</label><input className="input" type="date" style={COACH_INP} value={form.dia} onChange={e => setForm(s => ({ ...s, dia: e.target.value }))} /></div>
        {MEDIDA_CAMPOS.map(([k, lb]) => <div key={k}><label className="label">{lb}</label><input className="input" type="number" step="0.1" style={COACH_INP} value={form[k] || ''} onChange={e => setForm(s => ({ ...s, [k]: e.target.value }))} /></div>)}
      </div>
      <label className="label">Nota da avaliação</label>
      <textarea className="input" rows={2} style={{ ...COACH_INP, marginBottom: 12 }} value={form.nota || ''} onChange={e => setForm(s => ({ ...s, nota: e.target.value }))} />
      <label className="label">Fotos</label>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 10, marginBottom: 14 }}>
        {['frente', 'lado', 'costas'].map(pos => (
          <div key={pos} style={{ textAlign: 'center' }}>
            <div style={{ height: 130, borderRadius: 10, background: 'var(--cream-2)', display: 'grid', placeItems: 'center', overflow: 'hidden', marginBottom: 6 }}>
              {form.fotos[pos] ? <img src={form.fotos[pos]} alt={pos} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : <span style={{ fontSize: 22 }}>📷</span>}
            </div>
            <label className="btn btn-sm" style={{ cursor: 'pointer', width: '100%' }}>{busy === pos ? '…' : pos}<input type="file" accept="image/*" style={{ display: 'none' }} onChange={e => upFoto(pos, e.target.files && e.target.files[0])} /></label>
          </div>
        ))}
      </div>
      <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, borderTop: '1px solid var(--line-soft)', paddingTop: 16 }}>
        <button className="btn" onClick={onClose}>{lang==='pt'?'Cancelar':'Cancel'}</button>
        <button className="btn btn-primary" onClick={salvar} disabled={saving}>{saving ? '…' : 'Salvar avaliação'}</button>
      </div>
    </CoachModal>
  );
};

// ═══════════ MÉTRICAS (sub-abas + gráfico de linha) ═══════════
const METRIC_GROUPS = {
  peso:    { label: 'Peso',        unit: 'kg', keys: [['peso', 'Peso', 'var(--accent)']], lowerBetter: true },
  gordura: { label: 'Gordura',     unit: '%',  keys: [['gordura', 'Gordura', 'var(--sun)']], lowerBetter: true },
  massa:   { label: 'Massa magra', unit: 'kg', keys: [['massa_magra', 'Massa magra', 'var(--leaf)']], lowerBetter: false },
  medidas: { label: 'Medidas',     unit: 'cm', keys: [['cintura', 'Cintura', 'var(--teal)'], ['peitoral', 'Peitoral', '#8A6FB0'], ['braco', 'Braço', '#B0795C'], ['coxa', 'Coxa', '#5C8AB8']], lowerBetter: null },
};
const MultiLineChart = ({ sessions, keys }) => {
  const lang = useT().lang;
  const all = [];
  sessions.forEach(s => keys.forEach(([k]) => { const v = s[k]; if (v != null && !isNaN(Number(v))) all.push(Number(v)); }));
  if (!all.length) return <div className="empty" style={{ padding: 20 }}>{lang==='pt'?'sem dados':'no data'}</div>;
  const minV = Math.min(...all), maxV = Math.max(...all), range = (maxV - minV) || 1;
  const W = 320, H = 150, pad = 12, n = sessions.length;
  const x = i => pad + (n <= 1 ? 0.5 : i / (n - 1)) * (W - 2 * pad);
  const y = v => pad + (1 - (v - minV) / range) * (H - 2 * pad);
  return (
    <div>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto' }}>
        {keys.map(([k, , color]) => {
          const pts = sessions.map((s, i) => ({ i, v: s[k] })).filter(p => p.v != null && !isNaN(Number(p.v)));
          if (!pts.length) return null;
          return (<g key={k}>
            <polyline points={pts.map(p => `${x(p.i)},${y(Number(p.v))}`).join(' ')} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
            {pts.map(p => <circle key={p.i} cx={x(p.i)} cy={y(Number(p.v))} r={p.i === n - 1 ? 3.5 : 2} fill={color} />)}
          </g>);
        })}
      </svg>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 2, fontSize: 9, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>
        {sessions.map((s, i) => <span key={i}>{coachDmBR(s.dia)}</span>)}
      </div>
      {keys.length > 1 && <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 8 }}>
        {keys.map(([k, lb, color]) => <span key={k} style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, fontFamily: 'var(--fm)', color: 'var(--muted)' }}><span style={{ width: 9, height: 9, borderRadius: '50%', background: color }} />{lb}</span>)}
      </div>}
    </div>
  );
};
const CoachMetricsPanel = ({ sessions, selId }) => {
  const lang = useT().lang;
  const [g, setG] = useState('peso');
  const grp = METRIC_GROUPS[g];
  const idx = selId ? sessions.findIndex(s => s.id === selId) : sessions.length - 1;
  const cur = sessions[idx], prev = sessions[idx - 1];
  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--teal)' }}>
      <div className="t-eyebrow" style={{ color: 'var(--teal)', marginBottom: 10 }}>{lang==='pt'?'métricas':'metrics'}</div>
      <div style={{ display: 'flex', gap: 6, marginBottom: 14, flexWrap: 'wrap' }}>
        {Object.keys(METRIC_GROUPS).map(k => <button key={k} onClick={() => setG(k)} className={g === k ? 'btn btn-primary btn-sm' : 'btn btn-sm'} style={{ fontSize: 11 }}>{METRIC_GROUPS[k].label}</button>)}
      </div>
      {!sessions.length ? <div className="empty" style={{ padding: 24 }}>Sem avaliações para este aluno.</div> : (
        <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,140px) 1fr', gap: 16, alignItems: 'center' }} className="coach-metric-row">
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {grp.keys.map(([k, lb, color]) => {
              const v = cur ? cur[k] : null, pv = prev ? prev[k] : null;
              const d = (v != null && pv != null) ? Number(v) - Number(pv) : null;
              const good = d != null && grp.lowerBetter != null && (grp.lowerBetter ? d < 0 : d > 0);
              return (<div key={k}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}><span style={{ width: 8, height: 8, borderRadius: '50%', background: color }} />{lb}</div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                  <span style={{ fontFamily: 'var(--fs)', fontSize: 22 }}>{v != null ? v : '—'}<span style={{ fontSize: 11, color: 'var(--muted)' }}> {grp.unit}</span></span>
                  {d != null && d !== 0 && <span style={{ fontSize: 10.5, fontFamily: 'var(--fm)', color: good ? 'var(--leaf)' : (grp.lowerBetter == null ? 'var(--muted)' : 'var(--accent)') }}>{d > 0 ? '+' : ''}{d.toFixed(1)}</span>}
                </div>
              </div>);
            })}
          </div>
          <MultiLineChart sessions={sessions} keys={grp.keys} />
        </div>
      )}
    </div>
  );
};

// ═══════════ EVOLUÇÃO (fotos: data + antes/depois) ═══════════
const CoachEvolucao = ({ sessions, selId, setSelId }) => {
  const lang = useT().lang;
  const [compare, setCompare] = useState(false);
  const withPhotos = sessions.filter(s => s.fotos && (s.fotos.frente || s.fotos.lado || s.fotos.costas));
  const sel = sessions.find(s => s.id === selId) || sessions[sessions.length - 1];
  const selHasPhotos = sel && sel.fotos && (sel.fotos.frente || sel.fotos.lado || sel.fotos.costas);
  const base = withPhotos[0];
  const Fotos = ({ s }) => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {['frente', 'lado', 'costas'].map(p => s.fotos && s.fotos[p]
        ? <img key={p} src={s.fotos[p]} alt={p} style={{ width: '100%', maxHeight: 180, objectFit: 'cover', borderRadius: 8, background: 'var(--cream-2)' }} />
        : <div key={p} style={{ height: 64, borderRadius: 8, background: 'var(--cream-2)', display: 'grid', placeItems: 'center', color: 'var(--muted)', fontSize: 11 }}>{p}</div>)}
    </div>
  );
  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--rose)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
        <div className="t-eyebrow" style={{ color: 'var(--rose)' }}>{lang==='pt'?'evolução':'progress'}</div>
        {sessions.length > 0 && (
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
            {withPhotos.length > 1 && <button className={compare ? 'btn btn-primary btn-sm' : 'btn btn-sm'} onClick={() => setCompare(c => !c)}>{lang==='pt'?'antes/depois':'before/after'}</button>}
            <span style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)' }}>data</span>
            <select className="input" style={{ padding: '6px 10px', boxSizing: 'border-box' }} value={(sel && sel.id) || ''} onChange={e => setSelId(Number(e.target.value))}>
              {sessions.slice().reverse().map(s => <option key={s.id} value={s.id}>{coachDmBR(s.dia)}</option>)}
            </select>
          </div>
        )}
      </div>
      {!sessions.length ? (
        <div className="empty" style={{ padding: '28px 16px', textAlign: 'center' }}>📷<div style={{ marginTop: 8, fontSize: 13 }}>Sem avaliações.</div></div>
      ) : compare && withPhotos.length > 1 ? (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <div><div style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)', marginBottom: 6 }}>Antes · {coachDmBR(base.dia)}</div><Fotos s={base} /></div>
          <div><div style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)', marginBottom: 6 }}>Depois · {coachDmBR((selHasPhotos ? sel : withPhotos[withPhotos.length - 1]).dia)}</div><Fotos s={selHasPhotos ? sel : withPhotos[withPhotos.length - 1]} /></div>
        </div>
      ) : selHasPhotos ? (
        <div style={{ maxWidth: 280, margin: '0 auto' }}><Fotos s={sel} /></div>
      ) : (
        <div className="empty" style={{ padding: '24px 16px', textAlign: 'center', fontSize: 12 }}>Sem fotos nesta avaliação ({coachDmBR(sel.dia)}).</div>
      )}
    </div>
  );
};

// ═══════════ VISÃO GERAL (tela única) ═══════════
// ─── o herói da página: cartão do atleta com a régua de vida (cores = domínios) ───
const CoachAtletaHeader = ({ athlete, vida, onAvalCompleta, onMedicao }) => {
  const lang = useT().lang;
  const ini = (athlete.nome || '?').split(' ').map(x => x[0]).slice(0, 2).join('').toUpperCase();
  const hoje = new Date(); hoje.setHours(12);
  const diasSem = vida && vida.ultimo_treino ? Math.floor((hoje - new Date(String(vida.ultimo_treino).split('T')[0] + 'T12:00')) / 864e5) : null;
  const tile = (emoji, valor, rot, cor) => (
    <div key={rot} style={{ background: `color-mix(in srgb, ${cor} 10%, var(--surface))`, border: `1px solid color-mix(in srgb, ${cor} 28%, transparent)`, borderRadius: 14, padding: '10px 14px', minWidth: 92, textAlign: 'center' }}>
      <div style={{ fontFamily: 'var(--fs)', fontSize: 21, fontWeight: 700, lineHeight: 1 }}>{emoji} {valor}</div>
      <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, letterSpacing: 1, textTransform: 'uppercase', color: cor, marginTop: 5 }}>{rot}</div>
    </div>
  );
  return (
    <div style={{ background: 'var(--surface)', border: '1px solid var(--line-soft)', borderTop: '3px solid var(--accent)', borderRadius: 18, padding: '18px 20px', boxShadow: 'var(--shadow-sm)', marginBottom: 16, display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>
      <div style={{ width: 62, height: 62, borderRadius: '50%', overflow: 'hidden', flexShrink: 0, background: 'var(--teal)', display: 'grid', placeItems: 'center', color: '#fff', fontFamily: 'var(--fs)', fontSize: 22, fontWeight: 700 }}>
        {athlete.foto_url ? <img src={athlete.foto_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : ini}
      </div>
      <div style={{ minWidth: 150 }}>
        <div style={{ fontFamily: 'var(--fs)', fontSize: 23, fontWeight: 600, letterSpacing: '-0.4px', lineHeight: 1.1 }}>{athlete.nome}</div>
        <div style={{ fontFamily: 'var(--fm)', fontSize: 11.5, color: 'var(--muted)', marginTop: 3 }}>{athlete.funcao || '—'}</div>
      </div>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', flex: 1, justifyContent: 'center' }}>
        {vida ? [
          tile('🏋️', vida.treinos_7d, lang === 'pt' ? '7 dias' : '7 days', 'var(--accent)'),
          tile('📈', vida.treinos_30d, lang === 'pt' ? '30 dias' : '30 days', 'var(--teal)'),
          tile('🏠', vida.treinos_casa || 0, lang === 'pt' ? 'em terra' : 'home', 'var(--leaf)'),
          tile('⏱', diasSem == null ? '—' : diasSem === 0 ? (lang === 'pt' ? 'hoje' : 'today') : `${diasSem}d`, lang === 'pt' ? 'últ. treino' : 'last', diasSem != null && diasSem > 7 ? 'var(--rose)' : 'var(--sun)'),
        ] : null}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <button className="btn btn-primary btn-sm" onClick={onAvalCompleta}>📋 {lang === 'pt' ? 'Avaliação completa' : 'Full assessment'}</button>
      </div>
    </div>
  );
};

// ─── 🏆 Recordes pessoais do aluno (cargas do player) ───
const CoachRecordes = ({ athleteId }) => {
  const lang = useT().lang;
  const [dados, setDados] = useState(null);
  useEffect(() => {
    setDados(null);
    fetch(`/api/treino/prs/${athleteId}`, { headers: { Authorization: `Bearer ${COACH_TK()}` } })
      .then(r => r.ok ? r.json() : null).then(d => setDados(d)).catch(() => setDados({ exercicios: [] }));
  }, [athleteId]);
  const exs = (dados && dados.exercicios) || [];
  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--sun)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 10 }}>
        <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: 'var(--sun)' }}>🏆 {lang === 'pt' ? 'recordes pessoais' : 'personal records'}</div>
        {dados ? <span style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)' }}>{dados.total_prs || 0} PR{(dados.total_prs || 0) === 1 ? '' : 's'}</span> : null}
      </div>
      {!dados ? <div className="empty" style={{ padding: 14, fontSize: 12 }}>carregando…</div>
        : !exs.length ? <div className="empty" style={{ padding: 16, fontSize: 12 }}>{lang === 'pt' ? 'sem cargas registradas no player ainda.' : 'no logged loads yet.'}</div>
        : (
          <div style={{ display: 'grid', gap: 8, maxHeight: 260, overflowY: 'auto' }}>
            {exs.map((e, i) => {
              const prog = e.progressao || [];
              const maxP = prog.length ? Math.max(...prog.map(p => Number(p.carga))) : 1;
              return (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '8px 11px', background: 'var(--cream-2)', borderRadius: 11, minWidth: 0 }}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{e.nome}</div>
                    <div style={{ fontFamily: 'var(--fm)', fontSize: 10, color: 'var(--muted)' }}>
                      {e.prs} PR{e.prs === 1 ? '' : 's'} · {lang === 'pt' ? 'melhor em' : 'best on'} {new Date(String(e.melhor_dia).split('T')[0] + 'T12:00').toLocaleDateString('pt-BR', { day: '2-digit', month: 'short' })}
                    </div>
                  </div>
                  <div style={{ display: 'flex', alignItems: 'flex-end', gap: 2, height: 26, flexShrink: 0 }} title={lang === 'pt' ? 'progressão (máx por dia)' : 'progression'}>
                    {prog.map((p, j) => (
                      <div key={j} style={{ width: 6, borderRadius: 2, height: Math.max(4, Math.round(Number(p.carga) / maxP * 26)), background: j === prog.length - 1 ? 'var(--sun)' : 'var(--cream-3)', border: '1px solid var(--line-soft)' }} />
                    ))}
                  </div>
                  <div style={{ fontFamily: 'var(--fs)', fontSize: 18, fontWeight: 700, color: 'var(--sun)', flexShrink: 0 }}>{Number(e.melhor)}kg</div>
                </div>
              );
            })}
          </div>
        )}
    </div>
  );
};

// ═══ 🏗 PROGRAM BUILDER — montagem de treino estilo WeStrive: dias em abas, séries editáveis inline ═══
const pbSetsDe = ex => Array.isArray(ex.sets) && ex.sets.length
  ? ex.sets.map(st => ({ reps: String(st.reps ?? ''), carga: String(st.carga ?? '') }))
  : Array.from({ length: Math.max(1, Number(ex.series) || 3) }, () => ({ reps: String(ex.reps ?? '10'), carga: String(ex.carga ?? '') }));
const pbFmtDesc = seg => `${Math.floor(seg / 60)}m ${String(seg % 60).padStart(2, '0')}s`;

const CoachProgramBuilder = ({ athleteId, plan, bank, toast, onSaved, onBanco }) => {
  const lang = useT().lang;
  const [week, setWeek] = useState([]);
  const [selDay, setSelDay] = useState(DIAS[(new Date().getDay() + 6) % 7]);
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [novoEx, setNovoEx] = useState('');
  const [copiarPara, setCopiarPara] = useState('');
  const [modo, setModo] = useState('montar');        // 🛠 montar · 👁 aluno (preview com o MESMO componente do Saúde)
  const [prsMap, setPrsMap] = useState({});
  useEffect(() => {
    setPrsMap({});
    fetch(`/api/treino/prs/${athleteId}`, { headers: { Authorization: `Bearer ${COACH_TK()}` } })
      .then(r => r.ok ? r.json() : null)
      .then(d => {
        if (!d || !Array.isArray(d.exercicios)) return;
        const m = {};
        d.exercicios.forEach(e => { const prog = e.progressao || []; if (prog.length) m[(e.nome || '').toLowerCase()] = Number(prog[prog.length - 1].carga); });
        setPrsMap(m);
      }).catch(() => {});
  }, [athleteId]);

  useEffect(() => {
    const w = DIAS.map(d => {
      const wd = ((plan && plan.week) || []).find(x => x.day === d) || {};
      return { day: d, focus: wd.focus || '', nota: wd.nota || '', descanso: Number(wd.descanso) || 90,
        exercises: (wd.exercises || []).map(ex => ({ nome: ex.nome, sets: pbSetsDe(ex) })) };
    });
    setWeek(w); setDirty(false);
  }, [athleteId, plan]);

  const dia = week.find(w => w.day === selDay) || { exercises: [] };
  const mudaDia = (fn) => { setWeek(ws => ws.map(w => w.day === selDay ? fn({ ...w, exercises: w.exercises.map(e => ({ ...e, sets: e.sets.map(st => ({ ...st })) })) }) : w)); setDirty(true); };
  const mudaEx = (i, fn) => mudaDia(w => { w.exercises[i] = fn(w.exercises[i]); return w; });
  const move = (i, dir) => mudaDia(w => { const j = i + dir; if (j < 0 || j >= w.exercises.length) return w; const t = w.exercises[i]; w.exercises[i] = w.exercises[j]; w.exercises[j] = t; return w; });

  const addEx = () => {
    const nome = novoEx.trim(); if (!nome) return;
    mudaDia(w => { w.exercises.push({ nome, sets: [{ reps: '10', carga: '' }, { reps: '10', carga: '' }, { reps: '10', carga: '' }] }); return w; });
    setNovoEx('');
  };

  const copiarDia = () => {
    if (!copiarPara || copiarPara === selDay) return;
    setWeek(ws => ws.map(w => w.day === copiarPara ? { ...w, focus: dia.focus, nota: dia.nota, descanso: dia.descanso, exercises: dia.exercises.map(e => ({ nome: e.nome, sets: e.sets.map(st => ({ ...st })) })) } : w));
    setDirty(true); setCopiarPara('');
    toast.push({ icon: 'check', title: `⧉ ${selDay} copiado pra ${copiarPara}` });
  };

  const salvar = async () => {
    setSaving(true);
    // formato novo (sets) + campos legados sincronizados — o player continua entendendo tudo
    const weekOut = week.map(w => ({
      day: w.day, focus: w.focus, nota: w.nota, descanso: w.descanso,
      exercises: w.exercises.filter(e => e.nome.trim()).map(e => {
        const sets = e.sets.map(st => ({ reps: st.reps || '10', carga: st.carga || '' }));
        return { nome: e.nome, sets, series: sets.length, reps: sets[0] ? sets[0].reps : '10', carga: sets[0] ? sets[0].carga : '' };
      }),
    }));
    const r = await fetch(`/api/saude/plan/${athleteId}`, coachJSON('PUT', { demo: false, atualizado: new Date().toISOString().split('T')[0], week: weekOut }));
    setSaving(false);
    if (r.ok) { setDirty(false); toast.push({ icon: 'check', title: '💪 Treino salvo!' }); onSaved && onSaved(); }
    else toast.push({ icon: 'x', title: 'Erro ao salvar' });
  };

  const inpMini = { width: 46, boxSizing: 'border-box', padding: '5px 4px', textAlign: 'center', fontFamily: 'var(--fm)', fontSize: 11.5, border: '1px solid var(--line)', borderRadius: 7, background: 'var(--surface)' };

  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--accent)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
        <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>🏗 {lang === 'pt' ? 'montagem do treino' : 'program builder'} {plan && plan.demo ? '· (demo)' : ''}</div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
          <div style={{ display: 'flex', gap: 2, background: 'var(--cream-2)', borderRadius: 10, padding: 2 }}>
            {[['montar', '🛠 ' + (lang === 'pt' ? 'Montagem' : 'Builder')], ['aluno', '👁 ' + (lang === 'pt' ? 'Visão do aluno' : 'Athlete view')]].map(([id, rot]) => (
              <button key={id} onClick={() => setModo(id)} style={{ border: 'none', cursor: 'pointer', padding: '6px 11px', borderRadius: 8, fontSize: 11.5, fontFamily: 'var(--f)', fontWeight: modo === id ? 700 : 400, background: modo === id ? 'var(--surface)' : 'transparent', color: modo === id ? 'var(--teal)' : 'var(--muted)', boxShadow: modo === id ? 'var(--shadow-sm)' : 'none' }}>{rot}</button>
            ))}
          </div>
          <button className="btn btn-sm" onClick={onBanco}>{lang === 'pt' ? '🎞 Banco de exercícios' : '🎞 Exercise bank'}</button>
          {dirty ? <button className="btn btn-primary btn-sm" onClick={salvar} disabled={saving}>{saving ? '…' : '💾 ' + (lang === 'pt' ? 'Salvar treino' : 'Save')}</button> : null}
        </div>
      </div>

      {modo === 'aluno' ? (
        <div>
          <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)', marginBottom: 10 }}>
            👁 {lang === 'pt' ? 'exatamente o que o aluno vê no Saúde — incluindo o que tu ainda não salvou' : 'exactly what the athlete sees — including unsaved edits'}{dirty ? ' ●' : ''}
          </div>
          <FitTreinoDoDia
            week={week} dayName={DIAS[(new Date().getDay() + 6) % 7]}
            selDia={selDay} setSelDia={setSelDay}
            bank={bank || []} prsMap={prsMap} lang={lang}
            atualizadoEm={null} onCardClick={null} onIniciar={null}
          />
        </div>
      ) : (
      <React.Fragment>
      {/* abas de dia (estilo WeStrive) */}
      <div style={{ display: 'flex', gap: 6, overflowX: 'auto', paddingBottom: 4, marginBottom: 12 }}>
        {DIAS.map(d => {
          const wd = week.find(x => x.day === d) || {};
          const on = d === selDay;
          const n = (wd.exercises || []).length;
          return (
            <button key={d} onClick={() => setSelDay(d)} style={{ minWidth: 96, flexShrink: 0, textAlign: 'left', cursor: 'pointer', border: on ? '2px solid var(--teal)' : '1px solid var(--line-soft)', background: on ? 'var(--surface)' : 'var(--cream-2)', borderRadius: 11, padding: '8px 11px', boxShadow: on ? 'var(--shadow-sm)' : 'none' }}>
              <div style={{ fontFamily: 'var(--fm)', fontSize: 10, letterSpacing: 1, textTransform: 'uppercase', color: on ? 'var(--teal)' : 'var(--muted)', fontWeight: 700 }}>{d}</div>
              <div style={{ fontSize: 11.5, color: wd.focus ? 'var(--ink)' : 'var(--muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 110 }}>{wd.focus || (n ? `${n} exerc.` : (lang === 'pt' ? 'repouso' : 'rest'))}</div>
            </button>
          );
        })}
      </div>

      {/* título do dia + copiar */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
        <input className="input" style={{ flex: 1, minWidth: 180, boxSizing: 'border-box', fontFamily: 'var(--fs)', fontSize: 16 }}
          placeholder={lang === 'pt' ? 'Nome do dia (ex.: Peito e tríceps)…' : 'Day title…'}
          value={dia.focus || ''} onChange={e => mudaDia(w => { w.focus = e.target.value; return w; })} />
        <select className="select" value={copiarPara} onChange={e => setCopiarPara(e.target.value)} style={{ fontFamily: 'var(--fm)', fontSize: 11 }}>
          <option value="">⧉ {lang === 'pt' ? 'copiar dia pra…' : 'copy day to…'}</option>
          {DIAS.filter(d => d !== selDay).map(d => <option key={d} value={d}>{d}</option>)}
        </select>
        {copiarPara ? <button className="btn btn-sm" onClick={copiarDia}>✓</button> : null}
      </div>

      {/* tabela de exercícios */}
      {!dia.exercises.length ? (
        <div className="empty" style={{ padding: 22, textAlign: 'center' }}>{lang === 'pt' ? 'dia de descanso — ou adiciona o primeiro exercício 👇' : 'rest day — or add an exercise 👇'}</div>
      ) : (
        <div style={{ display: 'grid', gap: 8 }}>
          <div style={{ display: 'grid', gridTemplateColumns: '64px minmax(150px, 1.1fr) 2fr', gap: 10, padding: '0 4px', fontFamily: 'var(--fm)', fontSize: 9.5, letterSpacing: 0.8, textTransform: 'uppercase', color: 'var(--muted)' }} className="pb-header">
            <span>{lang === 'pt' ? 'ações' : 'actions'}</span><span>{lang === 'pt' ? 'exercício' : 'exercise'}</span><span>{lang === 'pt' ? 'séries (reps × kg)' : 'sets (reps × kg)'}</span>
          </div>
          {dia.exercises.map((ex, i) => {
            const be = matchBank(bank, ex) || {};
            return (
              <div key={i} style={{ display: 'grid', gridTemplateColumns: '64px minmax(150px, 1.1fr) 2fr', gap: 10, alignItems: 'center', border: '1px solid var(--line-soft)', borderRadius: 12, padding: '8px 10px', background: 'var(--cream-2)', minWidth: 0 }} className="pb-row">
                <div style={{ display: 'flex', gap: 3 }}>
                  <button title="Subir" className="btn ghost btn-sm" style={{ padding: '1px 5px' }} onClick={() => move(i, -1)}>↑</button>
                  <button title="Descer" className="btn ghost btn-sm" style={{ padding: '1px 5px' }} onClick={() => move(i, 1)}>↓</button>
                  <button title="Remover" className="btn ghost btn-sm" style={{ padding: '1px 5px', color: 'var(--rose)' }} onClick={() => mudaDia(w => { w.exercises.splice(i, 1); return w; })}>✕</button>
                </div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
                  <ExerciseMedia media_url={be.media_url} image_url={be.image_url} size={40} />
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ex.nome}</div>
                    {be.musculo ? <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--muted)' }}>{be.musculo}</div> : null}
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
                  {ex.sets.map((st, si) => (
                    <div key={si} style={{ display: 'flex', alignItems: 'center', gap: 3, background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 9, padding: '4px 6px' }}>
                      <span style={{ fontFamily: 'var(--fm)', fontSize: 8.5, color: 'var(--muted)' }}>S{si + 1}</span>
                      <input style={inpMini} placeholder="reps" value={st.reps} onChange={e => mudaEx(i, x => { x.sets[si].reps = e.target.value; return x; })} />
                      <span style={{ fontSize: 10, color: 'var(--muted)' }}>×</span>
                      <input style={inpMini} inputMode="decimal" placeholder="kg" value={st.carga} onChange={e => mudaEx(i, x => { x.sets[si].carga = e.target.value; return x; })} />
                      {ex.sets.length > 1 ? <button title="Tirar série" onClick={() => mudaEx(i, x => { x.sets.splice(si, 1); return x; })} style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--muted)', fontSize: 10, padding: 0 }}>✕</button> : null}
                    </div>
                  ))}
                  <button className="btn ghost btn-sm" style={{ padding: '3px 8px' }} title={lang === 'pt' ? 'Adicionar série' : 'Add set'}
                    onClick={() => mudaEx(i, x => { const ult = x.sets[x.sets.length - 1] || { reps: '10', carga: '' }; x.sets.push({ ...ult }); return x; })}>＋</button>
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* adicionar exercício */}
      <div style={{ display: 'flex', gap: 8, marginTop: 10, flexWrap: 'wrap' }}>
        <input className="input" list="pb-banco" style={{ flex: 1, minWidth: 200, boxSizing: 'border-box' }}
          placeholder={lang === 'pt' ? '＋ exercício do banco ou nome livre…' : '＋ add exercise…'}
          value={novoEx} onChange={e => setNovoEx(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') addEx(); }} />
        <button className="btn btn-primary btn-sm" onClick={addEx} disabled={!novoEx.trim()}>{lang === 'pt' ? 'Adicionar' : 'Add'}</button>
        <datalist id="pb-banco">{(bank || []).map(b => <option key={b.id} value={b.nome} />)}</datalist>
      </div>

      {/* rodapé: descanso + observações (estilo WeStrive) */}
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(200px, 1fr) minmax(200px, 1.6fr)', gap: 12, marginTop: 14, background: 'var(--cream-2)', borderRadius: 12, padding: '11px 13px' }} className="pb-footer">
        <div>
          <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, letterSpacing: 0.8, textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 5 }}>
            ⏱ {lang === 'pt' ? 'descanso entre séries' : 'rest between sets'}: <b style={{ color: 'var(--teal)' }}>{pbFmtDesc(dia.descanso || 90)}</b>
          </div>
          <input type="range" min="15" max="300" step="15" value={dia.descanso || 90} style={{ width: '100%' }}
            onChange={e => mudaDia(w => { w.descanso = Number(e.target.value); return w; })} />
        </div>
        <div>
          <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, letterSpacing: 0.8, textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 5 }}>📝 {lang === 'pt' ? 'observações do dia' : 'day notes'}</div>
          <input className="input" style={{ width: '100%', boxSizing: 'border-box' }} placeholder={lang === 'pt' ? 'tempo, cadência, técnica…' : 'tempo, cadence…'}
            value={dia.nota || ''} onChange={e => mudaDia(w => { w.nota = e.target.value; return w; })} />
        </div>
      </div>

      </React.Fragment>
      )}

      {dirty ? (
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 12, borderTop: '1px solid var(--line-soft)', paddingTop: 12 }}>
          <span style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--sun)', alignSelf: 'center' }}>● {lang === 'pt' ? 'alterações não salvas' : 'unsaved changes'}</span>
          <button className="btn btn-primary" onClick={salvar} disabled={saving}>{saving ? '…' : '💾 ' + (lang === 'pt' ? 'Salvar treino' : 'Save workout')}</button>
        </div>
      ) : null}
      <style>{`@media (max-width:760px){.pb-header{display:none !important}.pb-row{grid-template-columns:1fr !important}.pb-footer{grid-template-columns:1fr !important}}`}</style>
    </div>
  );
};

const CoachOverview = ({ athleteId, athlete, vida, toast }) => {
  const lang = useT().lang;
  const [data, setData] = useState(null);
  const [bank, setBank] = useState([]);
  const [selId, setSelId] = useState(null);
  const [selDay, setSelDay] = useState(DIAS[(new Date().getDay() + 6) % 7]);
  const [modal, setModal] = useState(null);
  const [aba, setAba] = useState('visao');       // visao · treino · dieta · aval · evolucao

  const fetchAll = () => {
    Promise.all([
      fetch(`/api/saude/plan/${athleteId}`, coachHdr()).then(r => r.ok ? r.json() : null),
      fetch(`/api/saude/diet/${athleteId}`, coachHdr()).then(r => r.ok ? r.json() : null),
      fetch(`/api/saude/measurements/${athleteId}`, coachHdr()).then(r => r.ok ? r.json() : []),
      fetch('/api/saude/exercises', coachHdr()).then(r => r.ok ? r.json() : []),
    ]).then(([plan, diet, sessions, bk]) => {
      const ss = Array.isArray(sessions) ? sessions : [];
      setData({ plan, diet, sessions: ss });
      setBank(Array.isArray(bk) ? bk : []);
      setSelId(ss.length ? ss[ss.length - 1].id : null);
    });
  };
  useEffect(() => { setData(null); setAba('visao'); fetchAll(); }, [athleteId]);

  if (!data) return <div className="empty" style={{ padding: 40 }}>{lang==='pt'?'carregando…':'loading…'}</div>;
  const { plan, diet, sessions } = data;
  const week = (plan && plan.week) || [];
  const dayObj = week.find(d => d.day === selDay) || { focus: '', exercises: [] };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <CoachAtletaHeader athlete={athlete} vida={vida} onAvalCompleta={() => setModal('avalcompleta')} />

      {/* ── prontuário: abas do aluno ── */}
      <div style={{ display: 'flex', gap: 2, background: 'var(--cream-2)', borderRadius: 12, padding: 3, flexWrap: 'wrap' }}>
        {[['visao', '📋 Visão geral'], ['treino', '🏋️ Treino'], ['dieta', '🥗 Dieta'], ['aval', '🩺 Avaliações'], ['evolucao', '📈 Evolução']].map(([id, rot]) => (
          <button key={id} onClick={() => setAba(id)} style={{ flex: 1, minWidth: 100, border: 'none', cursor: 'pointer', padding: '9px 6px', borderRadius: 10, fontSize: 12.5, fontFamily: 'var(--f)', fontWeight: aba === id ? 700 : 400, background: aba === id ? 'var(--surface)' : 'transparent', color: aba === id ? 'var(--teal)' : 'var(--muted)', boxShadow: aba === id ? 'var(--shadow-sm)' : 'none' }}>{rot}</button>
        ))}
      </div>

      {/* ═══ 📋 VISÃO GERAL: o relance do aluno ═══ */}
      {aba === 'visao' ? (
        <React.Fragment>
          <CoachMetricsPanel sessions={sessions} selId={selId} />
          <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1fr) minmax(0,1fr)', gap: 14 }} className="coach-overview-grid">
            <RadarForca userId={athleteId} lang={lang} />
            <CoachDiarioSecao athleteId={athleteId} toast={toast} />
          </div>
        </React.Fragment>
      ) : null}

      {/* ═══ 🩺 AVALIAÇÕES ═══ */}
      {aba === 'aval' ? <CoachAvalLista athleteId={athleteId} toast={toast} versao={modal} /> : null}

      {/* ═══ 📈 EVOLUÇÃO ═══ */}
      {aba === 'evolucao' ? (
        <React.Fragment>
          <MeasureChart sessions={sessions} lang={lang} me={athlete} userId={athleteId} />
          <CoachRecordes athleteId={athleteId} />
        </React.Fragment>
      ) : null}

      {/* ═══ 🏋️ TREINO — program builder inline ═══ */}
      {aba === 'treino' ? (
        <CoachProgramBuilder athleteId={athleteId} plan={plan} bank={bank} toast={toast} onSaved={fetchAll} onBanco={() => setModal('banco')} />
      ) : null}

      {/* ═══ 🥗 DIETA ═══ */}
      {aba === 'dieta' ? (
      <div style={{ ...coachCard, borderTop: '3px solid var(--sun)' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
          <div className="t-eyebrow" style={{ color: 'var(--sun)' }}>dieta {diet && diet.demo ? '· (demo)' : ''}</div>
          <button className="btn btn-sm" onClick={() => setModal('dieta')}>{lang==='pt'?'Editar dieta →':'Edit diet →'}</button>
        </div>
        {!diet || !diet.refeicoes || !diet.refeicoes.length ? <div className="empty" style={{ padding: 20 }}>Sem dieta montada.</div> : (
          <div>
            <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap', marginBottom: 12, fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--ink-2)' }}>
              <span><b>{diet.meta_kcal}</b> kcal</span><span>P {diet.macros?.proteina || 0}g</span><span>C {diet.macros?.carbo || 0}g</span><span>G {diet.macros?.gordura || 0}g</span><span>💧 {diet.agua_meta || 0}L</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column' }}>
              {diet.refeicoes.map((m, i) => (
                <div key={i} style={{ display: 'flex', gap: 12, padding: '9px 0', borderBottom: i < diet.refeicoes.length - 1 ? '1px solid var(--line-soft)' : 'none', alignItems: 'baseline' }}>
                  <span style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--accent)', minWidth: 42 }}>{m.hora || ''}</span>
                  <div style={{ flex: 1, minWidth: 0 }}><span style={{ fontFamily: 'var(--fs)', fontStyle: 'italic', fontSize: 15 }}>{m.refeicao}</span><span style={{ fontSize: 12, color: 'var(--muted)' }}> — {(m.alimentos || []).join(', ')}</span></div>
                  <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--ink-2)' }}>{m.kcal} kcal</span>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
      ) : null}

      {modal === 'avalcompleta' && <CoachAvalCompletaModal athleteId={athleteId} athlete={athlete} toast={toast} onClose={() => setModal(null)} onSaved={fetchAll} />}
      {modal === 'dieta' && <CoachDietModal athleteId={athleteId} toast={toast} onClose={() => setModal(null)} onSaved={fetchAll} />}
      {modal === 'banco' && <CoachBankModal toast={toast} onClose={() => setModal(null)} onChange={fetchAll} />}

      <style>{`@media (max-width:860px){.coach-overview-grid{grid-template-columns:1fr !important;}.coach-metric-row{grid-template-columns:1fr !important;}.coach-week-grid{grid-template-columns:1fr !important;}}`}</style>
    </div>
  );
};

// ═══════════ COACH (raiz) ═══════════
// ─── 📊 Radar da turma A BORDO: adesão relativa à rotação (treinos ÷ dias embarcado) ───
const COACH_FAROL = { verde: ['🟢', 'var(--leaf)'], amarelo: ['🟡', 'var(--sun)'], vermelho: ['🔴', 'var(--rose)'] };
const CoachAdesaoTurma = ({ athleteId, setAthleteId, versao }) => {
  const lang = useT().lang;
  const [dados, setDados] = useState(null);
  const [filtro, setFiltro] = useState('');
  useEffect(() => {
    fetch('/api/users/coach/adesao', { headers: { Authorization: `Bearer ${COACH_TK()}` } })
      .then(r => r.ok ? r.json() : null).then(d => setDados(d)).catch(() => {});
  }, [versao]);
  if (!dados) return null;
  const { pessoas, atencao, resumo } = dados;
  if (!pessoas.length) return null;
  const norm = x => (x || '').toString().toLowerCase();
  const lista = pessoas
    .filter(p => !filtro || norm(p.nome).includes(norm(filtro)) || norm(p.genesis_id).includes(norm(filtro)))
    .sort((a, b) => a.adesao - b.adesao);   // piores primeiro: onde o professor age
  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--teal)', marginBottom: 14 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', marginBottom: 4 }}>
        <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: 'var(--teal)', flex: 1 }}>
          📊 {lang === 'pt' ? 'turma a bordo' : 'class aboard'} · {resumo.a_bordo}
        </div>
        <span style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)' }}>🟢 {resumo.verde} · 🟡 {resumo.amarelo} · 🔴 {resumo.vermelho}</span>
        <input className="input" style={{ width: 150, boxSizing: 'border-box', padding: '6px 10px', fontSize: 12 }} placeholder="🔍 filtrar…" value={filtro} onChange={e => setFiltro(e.target.value)} />
      </div>
      <div style={{ fontFamily: 'var(--fm)', fontSize: 10, color: 'var(--muted)', marginBottom: 10 }}>
        {lang === 'pt' ? 'adesão = treinos ÷ dias embarcado NESTA rotação — quem está em terra não entra na conta.' : 'compliance = workouts ÷ days aboard this rotation.'}
      </div>

      {atencao.length ? (
        <div style={{ background: 'color-mix(in srgb, var(--rose) 7%, var(--cream-2))', border: '1px solid var(--rose)', borderRadius: 12, padding: '9px 12px', marginBottom: 10 }}>
          <div style={{ fontFamily: 'var(--fm)', fontSize: 10, letterSpacing: 0.8, textTransform: 'uppercase', color: 'var(--rose)', marginBottom: 6 }}>
            🗣 {lang === 'pt' ? 'fila de atenção — vale uma conversa' : 'attention queue'}
          </div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {atencao.map(p => (
              <button key={p.id} onClick={() => setAthleteId(p.id)} style={{ display: 'flex', alignItems: 'center', gap: 6, cursor: 'pointer', border: '1px solid var(--line-soft)', background: 'var(--surface)', borderRadius: 999, padding: '4px 11px 4px 5px', fontSize: 11.5, fontFamily: 'var(--f)', fontWeight: 600 }}>
                {p.foto_url ? <img src={p.foto_url} alt="" style={{ width: 20, height: 20, borderRadius: '50%', objectFit: 'cover' }} /> : <span>👤</span>}
                {String(p.nome || '').split(' ')[0]}
                <span style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--rose)', fontWeight: 700 }}>{p.dias_sem == null ? (lang === 'pt' ? 'nunca' : 'never') : `${p.dias_sem}d`}</span>
              </button>
            ))}
          </div>
        </div>
      ) : null}

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(215px, 1fr))', gap: 8, maxHeight: 300, overflowY: 'auto' }}>
        {lista.map(p => {
          const [emoji, cor] = COACH_FAROL[p.farol];
          const sel = p.id === athleteId;
          return (
            <button key={p.id} onClick={() => setAthleteId(p.id)} style={{ textAlign: 'left', cursor: 'pointer', background: sel ? 'color-mix(in srgb, var(--teal) 10%, var(--surface))' : 'var(--cream-2)', border: sel ? '1px solid var(--teal)' : '1px solid var(--line-soft)', borderRadius: 12, padding: '9px 11px', minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6, minWidth: 0 }}>
                {p.foto_url ? <img src={p.foto_url} alt="" style={{ width: 26, height: 26, borderRadius: '50%', objectFit: 'cover', flexShrink: 0 }} /> : <span style={{ flexShrink: 0 }}>{emoji}</span>}
                <span style={{ flex: 1, minWidth: 0, fontSize: 12.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.nome}</span>
                <span style={{ fontFamily: 'var(--fm)', fontSize: 12, fontWeight: 700, color: cor, flexShrink: 0 }}>{p.adesao}%</span>
              </div>
              <div style={{ height: 5, borderRadius: 4, background: 'var(--cream-3)', overflow: 'hidden', marginBottom: 5 }}>
                <div style={{ width: `${p.adesao}%`, height: '100%', background: cor, borderRadius: 4 }} />
              </div>
              <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--muted)' }}>
                {p.treinos}× {lang === 'pt' ? 'em' : 'in'} {p.dias_bordo}d {lang === 'pt' ? 'a bordo' : 'aboard'} · {p.dias_sem == null ? (lang === 'pt' ? 'nunca treinou' : 'no workouts') : p.dias_sem === 0 ? (lang === 'pt' ? 'treinou hoje ✓' : 'today ✓') : `${lang === 'pt' ? 'último há' : 'last'} ${p.dias_sem}d`}
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
};

// ─── 🏠 Validar treino de casa ───// ─── 🏠 Validar treino de casa ───
// ─── ✅ Central de validação: check-ins com foto (a bordo) + treinos em terra, num lugar só ───
const CoachValidarModal = ({ athletes, onClose, onSaved, toast }) => {
  const lang = useT().lang;
  const H = () => ({ Authorization: `Bearer ${COACH_TK()}`, 'Content-Type': 'application/json' });
  const [aba, setAba] = useState('chamada');
  const [pend, setPend] = useState(null);
  const [fotoZoom, setFotoZoom] = useState(null);
  // — chamada por GEN —
  const hoje = new Date().toISOString().split('T')[0];
  const minDia = new Date(Date.now() - 7 * 864e5).toISOString().split('T')[0];
  const [gen, setGen] = useState('');
  const [diaCh, setDiaCh] = useState(hoje);
  const [lancando, setLancando] = useState(false);
  const [ultimo, setUltimo] = useState(null);
  const [chamada, setChamada] = useState(null);
  const genRef = useRef(null);
  const carregarChamada = (d) => fetch(`/api/users/gym-checkin/dia?dia=${d || diaCh}`, { headers: H() })
    .then(r => r.ok ? r.json() : null).then(x => setChamada(x)).catch(() => {});
  useEffect(() => { carregarChamada(diaCh); }, [diaCh]);
  const lancar = async () => {
    if (!gen.trim() || lancando) return;
    setLancando(true);
    const r = await fetch('/api/users/gym-checkin/lancar', { method: 'POST', headers: H(), body: JSON.stringify({ gen: gen.trim(), dia: diaCh !== hoje ? diaCh : undefined }) });
    const j = await r.json().catch(() => ({}));
    setLancando(false);
    if (r.ok) {
      setUltimo({ ok: true, nome: j.pessoa.nome, gen: j.pessoa.genesis_id, repetido: j.ja_tinha });
      toast.push({ icon: 'check', title: j.ja_tinha ? `${j.pessoa.nome} já estava na chamada ✓` : `🏋️ ${j.pessoa.nome} na chamada!` });
      setGen(''); carregarChamada(); onSaved && onSaved();
    } else {
      setUltimo({ ok: false, erro: j.error || 'Erro' });
      toast.push({ icon: 'x', title: j.error || 'Erro ao lançar' });
    }
    if (genRef.current) genRef.current.focus();
  };
  const desfazer = async (p) => {
    if (!confirm(`Tirar ${p.nome} da chamada de ${diaCh === hoje ? 'hoje' : diaCh}?`)) return;
    const r = await fetch('/api/users/gym-checkin/lancar', { method: 'DELETE', headers: H(), body: JSON.stringify({ gen: p.genesis_id, dia: diaCh !== hoje ? diaCh : undefined }) });
    if (r.ok) { toast.push({ icon: 'check', title: 'Lançamento desfeito' }); carregarChamada(); onSaved && onSaved(); }
  };
  // — em terra —
  const [modo, setModo] = useState('codigo');
  const [codigo, setCodigo] = useState('');
  const [userId, setUserId] = useState(athletes[0] ? athletes[0].id : '');
  const [dia, setDia] = useState(new Date().toISOString().split('T')[0]);
  const [nota, setNota] = useState('');
  const [saving, setSaving] = useState(false);

  const carregarPend = () => fetch('/api/users/gym-checkin/pendencias', { headers: H() })
    .then(r => r.ok ? r.json() : []).then(d => setPend(Array.isArray(d) ? d : [])).catch(() => setPend([]));
  useEffect(() => { carregarPend(); }, []);

  const decidir = async (p, aprovar) => {
    let motivo = null;
    if (!aprovar) { motivo = prompt(`Recusar o check-in de ${p.nome}? Motivo (opcional, a pessoa vê):`); if (motivo === null) return; }
    const r = await fetch(`/api/users/gym-checkin/pendencias/${p.id}/decidir`, { method: 'POST', headers: H(), body: JSON.stringify({ aprovar, motivo }) });
    if (r.ok) { toast.push({ icon: 'check', title: aprovar ? `✓ ${p.nome} validado!` : 'Check-in recusado' }); carregarPend(); onSaved && onSaved(); }
    else { const j = await r.json().catch(() => ({})); toast.push({ icon: 'x', title: j.error || 'Erro' }); }
  };

  const validarCasa = async () => {
    setSaving(true);
    const corpo = modo === 'codigo' ? { codigo, dia, nota } : { user_id: userId, dia, nota };
    const r = await fetch('/api/treino/casa/validar', coachJSON('POST', corpo));
    const d = await r.json().catch(() => ({}));
    setSaving(false);
    if (r.ok) { toast.push({ icon: 'check', title: '🏠 Treino em terra validado!' }); setCodigo(''); setNota(''); onSaved && onSaved(); }
    else toast.push({ icon: 'x', title: d.error || 'Erro ao validar' });
  };

  return (
    <CoachModal title={<>✅ Validar <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>treinos.</em></>} onClose={onClose}>
      <div style={{ display: 'flex', gap: 2, background: 'var(--cream-2)', borderRadius: 12, padding: 3, marginBottom: 14 }}>
        {[['chamada', `🏋️ ${lang === 'pt' ? 'Chamada' : 'Roll call'}`], ['foto', `📸 ${lang === 'pt' ? 'Foto' : 'Photo'}${pend && pend.length ? ` · ${pend.length}` : ''}`], ['casa', `🏠 ${lang === 'pt' ? 'Em terra' : 'Ashore'}`]].map(([id, rot]) => (
        <button key={id} onClick={() => setAba(id)} style={{ flex: 1, border: 'none', cursor: 'pointer', padding: '9px 6px', borderRadius: 10, fontSize: 12.5, fontFamily: 'var(--f)', fontWeight: aba === id ? 700 : 400, background: aba === id ? 'var(--surface)' : 'transparent', color: aba === id ? 'var(--teal)' : 'var(--muted)', boxShadow: aba === id ? 'var(--shadow-sm)' : 'none' }}>{rot}</button>
        ))}
      </div>

      {aba === 'chamada' ? (
        <div>
          <div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
            <input ref={genRef} className="input" autoFocus style={{ flex: 1, boxSizing: 'border-box', fontFamily: 'var(--fm)' }} placeholder="GEN-0042 ou só 42 + Enter"
              value={gen} onChange={e => setGen(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') lancar(); }} />
            <input className="input" type="date" min={minDia} max={hoje} style={{ width: 138, boxSizing: 'border-box' }} value={diaCh} onChange={e => setDiaCh(e.target.value)} />
            <button className="btn btn-primary" onClick={lancar} disabled={lancando || !gen.trim()}>{lancando ? '…' : '＋'}</button>
          </div>
          {ultimo ? (
            <div style={{ fontSize: 12, fontFamily: 'var(--fm)', color: ultimo.ok ? 'var(--leaf)' : 'var(--rose)', marginBottom: 8 }}>
              {ultimo.ok ? `✓ ${ultimo.nome} (${ultimo.gen})${ultimo.repetido ? ' — já estava na chamada' : ' — lançado!'}` : `✗ ${ultimo.erro}`}
            </div>
          ) : null}
          <div style={{ fontFamily: 'var(--fm)', fontSize: 10, letterSpacing: 0.8, textTransform: 'uppercase', color: 'var(--muted)', margin: '6px 0' }}>
            ✓ {lang === 'pt' ? 'treinaram' : 'trained'} {diaCh === hoje ? 'hoje' : new Date(diaCh + 'T12:00').toLocaleDateString('pt-BR')} · {chamada ? chamada.total : '…'}
          </div>
          {!chamada ? null : !chamada.pessoas.length ? <div className="empty" style={{ padding: 14, fontSize: 12 }}>ninguém ainda — bora encher essa lista 💪</div> : (
            <div style={{ maxHeight: 250, overflowY: 'auto', display: 'grid', gap: 5 }}>
              {chamada.pessoas.map(p => (
                <div key={p.user_id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 9px', background: 'var(--cream-2)', borderRadius: 9, minWidth: 0 }}>
                  {p.foto_url ? <img src={p.foto_url} alt="" style={{ width: 24, height: 24, borderRadius: '50%', objectFit: 'cover', flexShrink: 0 }} /> : <span style={{ width: 24, textAlign: 'center', flexShrink: 0 }}>🏋️</span>}
                  <span style={{ flex: 1, minWidth: 0, fontSize: 12.5, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.nome}</span>
                  <span style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--muted)', flexShrink: 0 }}>{p.genesis_id}</span>
                  <button className="btn ghost btn-sm" style={{ padding: '0 6px', color: 'var(--rose)', flexShrink: 0 }} title="Desfazer" onClick={() => desfazer(p)}>✕</button>
                </div>
              ))}
            </div>
          )}
        </div>
      ) : aba === 'foto' ? (
        pend === null ? <div className="empty" style={{ padding: 20 }}>carregando…</div>
        : !pend.length ? <div className="empty" style={{ padding: 24, textAlign: 'center' }}>{lang === 'pt' ? 'fila zerada — nenhum check-in aguardando 🎉' : 'queue clear 🎉'}</div>
        : (
          <div style={{ display: 'grid', gap: 8 }}>
            {pend.map(p => (
              <div key={p.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 11px', background: 'var(--cream-2)', borderRadius: 12, border: '1px solid var(--sun)', minWidth: 0 }}>
                <img src={p.foto_url} alt="" onClick={() => setFotoZoom(p.foto_url)} style={{ width: 48, height: 48, borderRadius: 10, objectFit: 'cover', cursor: 'zoom-in', flexShrink: 0 }} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.nome}</div>
                  <div style={{ fontFamily: 'var(--fm)', fontSize: 10, color: 'var(--muted)' }}>{p.genesis_id} · {new Date(p.criado_em).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}</div>
                </div>
                <button title="Validar treino" onClick={() => decidir(p, true)} style={{ width: 32, height: 32, borderRadius: 9, border: 'none', background: 'var(--leaf)', color: '#fff', cursor: 'pointer', fontSize: 15, display: 'grid', placeItems: 'center', flexShrink: 0 }}>✓</button>
                <button title="Recusar" onClick={() => decidir(p, false)} style={{ width: 32, height: 32, borderRadius: 9, border: 'none', background: 'var(--rose)', color: '#fff', cursor: 'pointer', fontSize: 15, display: 'grid', placeItems: 'center', flexShrink: 0 }}>✕</button>
              </div>
            ))}
          </div>
        )
      ) : (
        <div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginBottom: 12 }}>{lang === 'pt' ? 'O aluno em folga manda a foto do treino + o código GYM dele (WhatsApp). Confirma aqui — conta pro streak e pra conquista 🏠 Foco em Terra.' : 'Athlete ashore sends photo + GYM code. Confirm here.'}</div>
          <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
            <button className={modo === 'codigo' ? 'btn btn-primary btn-sm' : 'btn btn-sm'} onClick={() => setModo('codigo')}>Por código</button>
            <button className={modo === 'pessoa' ? 'btn btn-primary btn-sm' : 'btn btn-sm'} onClick={() => setModo('pessoa')}>Por pessoa</button>
          </div>
          {modo === 'codigo' ? (
            <input className="input" style={{ width: '100%', boxSizing: 'border-box', fontFamily: 'var(--fm)', fontSize: 16, textAlign: 'center', letterSpacing: 1, marginBottom: 12 }} placeholder="GYM-GEN-0002" value={codigo} onChange={e => setCodigo(e.target.value.toUpperCase())} />
          ) : (
            <select className="select" style={{ width: '100%', boxSizing: 'border-box', marginBottom: 12 }} value={userId} onChange={e => setUserId(Number(e.target.value))}>
              {athletes.map(a => <option key={a.id} value={a.id}>{a.nome}</option>)}
            </select>
          )}
          <div style={{ display: 'flex', gap: 10, marginBottom: 12 }}>
            <div style={{ flex: 1 }}><label className="label">Data do treino</label><input className="input" type="date" style={{ width: '100%', boxSizing: 'border-box' }} value={dia} onChange={e => setDia(e.target.value)} /></div>
            <div style={{ flex: 2 }}><label className="label">Nota (opcional)</label><input className="input" style={{ width: '100%', boxSizing: 'border-box' }} placeholder="Corrida 5km…" value={nota} onChange={e => setNota(e.target.value)} /></div>
          </div>
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
            <button className="btn btn-primary" onClick={validarCasa} disabled={saving || (modo === 'codigo' && !codigo.trim())}>{saving ? '…' : '✓ Validar treino em terra'}</button>
          </div>
        </div>
      )}

      {fotoZoom ? (
        <div onClick={() => setFotoZoom(null)} style={{ position: 'fixed', inset: 0, zIndex: 9500, background: 'rgba(31,42,46,0.75)', display: 'grid', placeItems: 'center', padding: 20, cursor: 'zoom-out' }}>
          <img src={fotoZoom} alt="" style={{ maxWidth: '92vw', maxHeight: '86vh', borderRadius: 16, boxShadow: 'var(--shadow-lg)' }} />
        </div>
      ) : null}
    </CoachModal>
  );
};

// ─── 🚢 Métricas do barco: gráficos pro professor fundamentar o trabalho ───
const COACH_FONTES = {
  semanas: { t: '📉 Adesão × semana da rotação', fonte: 'gym_log (chamada por GEN + check-ins com foto aprovados) cruzado com manifesto.embarque', db: 'gym_log · manifesto' },
  dow:     { t: '🗓 Treinos por dia da semana', fonte: 'gym_log dos últimos 60 dias, agrupado pelo dia da semana', db: 'gym_log' },
  tend:    { t: '⚖ Tendência da turma', fonte: 'measurement_sessions — alimentado automaticamente pelas avaliações completas do professor', db: 'measurement_sessions · avaliacoes_fisicas' },
  prs:     { t: '🏆 Recordes do barco', fonte: 'treino_series (cargas registradas no player de treino), recorde = carga acima do máximo histórico da pessoa', db: 'treino_series · treino_sessoes' },
};
const CoachMetricaDetalhe = ({ tipo, d, onClose }) => {
  const f = COACH_FONTES[tipo];
  const th = { textAlign: 'left', fontFamily: 'var(--fm)', fontSize: 10, letterSpacing: 0.6, textTransform: 'uppercase', color: 'var(--muted)', padding: '6px 8px', borderBottom: '1px solid var(--line)' };
  const td = { fontSize: 12.5, padding: '7px 8px', borderBottom: '1px dashed var(--line-soft)' };
  return (
    <CoachModal title={<span style={{ fontSize: 18 }}>{f.t}</span>} onClose={onClose}>
      <div style={{ background: 'var(--cream-2)', borderRadius: 12, padding: '10px 13px', marginBottom: 12, fontSize: 12, color: 'var(--muted)', lineHeight: 1.5 }}>
        <b style={{ color: 'var(--ink)' }}>De onde vem:</b> {f.fonte}.<br/>
        <span style={{ fontFamily: 'var(--fm)', fontSize: 10.5 }}>🗄 tabelas navegáveis no DB Explorer: {f.db}</span>
      </div>
      <div style={{ maxHeight: 320, overflowY: 'auto' }}>
        {tipo === 'semanas' ? (
          <table style={{ width: '100%', borderCollapse: 'collapse' }}><thead><tr><th style={th}>Semana</th><th style={th}>Adesão média</th><th style={th}>Pessoas na conta</th></tr></thead><tbody>
            {(d.semanas_rotacao || []).map(w => <tr key={w.semana}><td style={td}>S{w.semana} (dias {(w.semana - 1) * 7 + 1}–{w.semana * 7})</td><td style={td}><b>{w.adesao == null ? '—' : w.adesao + '%'}</b></td><td style={td}>{w.pessoas}</td></tr>)}
          </tbody></table>
        ) : tipo === 'dow' ? (
          <table style={{ width: '100%', borderCollapse: 'collapse' }}><thead><tr><th style={th}>Dia</th><th style={th}>Treinos (60d)</th></tr></thead><tbody>
            {(d.por_dia_semana || []).map(x => <tr key={x.dow}><td style={td}>{x.rotulo}</td><td style={td}><b>{x.n}</b></td></tr>)}
          </tbody></table>
        ) : tipo === 'tend' ? (
          <table style={{ width: '100%', borderCollapse: 'collapse' }}><thead><tr><th style={th}>Mês</th><th style={th}>Peso médio</th><th style={th}>% gordura média</th><th style={th}>Pessoas medidas</th></tr></thead><tbody>
            {(d.tendencia || []).map(t => <tr key={t.mes}><td style={td}>{t.mes}</td><td style={td}><b>{t.peso} kg</b></td><td style={td}><b>{t.gordura}%</b></td><td style={td}>{t.pessoas}</td></tr>)}
          </tbody></table>
        ) : (
          <table style={{ width: '100%', borderCollapse: 'collapse' }}><thead><tr><th style={th}>Quem</th><th style={th}>Exercício</th><th style={th}>Carga</th><th style={th}>Dia</th></tr></thead><tbody>
            {(d.prs_recentes || []).map((p, i) => <tr key={i}><td style={td}><b>{p.pessoa || '?'}</b></td><td style={td}>{p.exercise_nome}</td><td style={td}><b style={{ color: 'var(--sun)' }}>{Number(p.carga)}kg</b></td><td style={td}>{new Date(String(p.dia).split('T')[0] + 'T12:00').toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })}</td></tr>)}
          </tbody></table>
        )}
      </div>
    </CoachModal>
  );
};

const CoachMetricasBarco = ({ versao }) => {
  const lang = useT().lang;
  const [d, setD] = useState(null);
  const [det, setDet] = useState(null);
  useEffect(() => {
    fetch('/api/users/coach/metricas-barco', { headers: { Authorization: `Bearer ${COACH_TK()}` } })
      .then(r => r.ok ? r.json() : null).then(x => setD(x)).catch(() => {});
  }, [versao]);
  if (!d) return null;
  const painel = { background: 'var(--cream-2)', borderRadius: 12, padding: '11px 13px', minWidth: 0, cursor: 'zoom-in', border: '1px solid transparent' };
  const eyebrow = cor => ({ fontFamily: 'var(--fm)', fontSize: 9.5, letterSpacing: 0.9, textTransform: 'uppercase', color: cor, marginBottom: 8 });
  const semanas = d.semanas_rotacao || [];
  const maxDow = Math.max(1, ...(d.por_dia_semana || []).map(x => x.n));
  const tend = d.tendencia || [];
  const spark = (vals, cor, w, h2) => {
    const nums = vals.map(Number).filter(x => !isNaN(x));
    if (nums.length < 2) return null;
    const mn = Math.min(...nums), mx = Math.max(...nums), rng = mx - mn || 1;
    const pts = nums.map((v, i) => `${(i / (nums.length - 1)) * w},${h2 - 3 - ((v - mn) / rng) * (h2 - 6)}`).join(' ');
    return <svg width={w} height={h2} style={{ display: 'block' }}><polyline points={pts} fill="none" stroke={cor} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>;
  };
  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--sky)', marginBottom: 14 }}>
      <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: 'var(--sky)', marginBottom: 10 }}>🚢 {lang === 'pt' ? 'métricas do barco' : 'vessel metrics'}</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))', gap: 10 }}>

        <div style={painel} onClick={() => setDet('semanas')} title="clica pra ver os dados e a fonte">
          <div style={eyebrow('var(--teal)')}>📉 {lang === 'pt' ? 'adesão × semana da rotação' : 'compliance by rotation week'}</div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 8, height: 74 }}>
            {semanas.map(w => (
              <div key={w.semana} style={{ flex: 1, textAlign: 'center' }}>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, fontWeight: 700, color: w.adesao == null ? 'var(--muted)' : w.adesao >= 45 ? 'var(--leaf)' : w.adesao >= 20 ? 'var(--sun)' : 'var(--rose)' }}>{w.adesao == null ? '—' : `${w.adesao}%`}</div>
                <div style={{ height: 42, display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}>
                  <div style={{ width: 20, borderRadius: 4, height: Math.max(3, Math.round((w.adesao || 0) / 100 * 42)), background: 'var(--teal)' }} />
                </div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 9, color: 'var(--muted)' }}>S{w.semana}</div>
              </div>
            ))}
          </div>
        </div>

        <div style={painel} onClick={() => setDet('dow')} title="clica pra ver os dados e a fonte">
          <div style={eyebrow('var(--accent)')}>🗓 {lang === 'pt' ? 'treinos por dia da semana (60d)' : 'workouts by weekday (60d)'}</div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 5, height: 74 }}>
            {(d.por_dia_semana || []).map(x => (
              <div key={x.dow} style={{ flex: 1, textAlign: 'center' }}>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--muted)' }}>{x.n || ''}</div>
                <div style={{ height: 44, display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}>
                  <div style={{ width: '70%', borderRadius: 3, height: Math.max(2, Math.round(x.n / maxDow * 44)), background: 'var(--accent)' }} />
                </div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 8.5, color: 'var(--muted)' }}>{x.rotulo}</div>
              </div>
            ))}
          </div>
        </div>

        <div style={painel} onClick={() => setDet('tend')} title="clica pra ver os dados e a fonte">
          <div style={eyebrow('var(--leaf)')}>⚖ {lang === 'pt' ? 'tendência da turma (6 meses)' : 'crew trend (6mo)'}</div>
          {tend.length >= 2 ? (
            <div>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', fontFamily: 'var(--fm)', fontSize: 10.5 }}>
                <span style={{ color: 'var(--muted)' }}>{lang === 'pt' ? 'peso médio' : 'avg weight'}</span>
                <b>{tend[0].peso} → {tend[tend.length - 1].peso}kg</b>
              </div>
              {spark(tend.map(t => t.peso), 'var(--teal)', 180, 26)}
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', fontFamily: 'var(--fm)', fontSize: 10.5, marginTop: 4 }}>
                <span style={{ color: 'var(--muted)' }}>{lang === 'pt' ? '% gordura média' : 'avg body fat'}</span>
                <b>{tend[0].gordura} → {tend[tend.length - 1].gordura}%</b>
              </div>
              {spark(tend.map(t => t.gordura), 'var(--rose)', 180, 26)}
            </div>
          ) : <div className="empty" style={{ padding: 12, fontSize: 11 }}>{lang === 'pt' ? 'poucas medições ainda.' : 'not enough data.'}</div>}
        </div>

        <div style={painel} onClick={() => setDet('prs')} title="clica pra ver os dados e a fonte">
          <div style={eyebrow('var(--sun)')}>🏆 {lang === 'pt' ? 'recordes do barco (30d)' : 'vessel PRs (30d)'}</div>
          {(d.prs_recentes || []).length ? (
            <div style={{ display: 'grid', gap: 4, maxHeight: 74, overflowY: 'auto' }}>
              {d.prs_recentes.map((p, i) => (
                <div key={i} style={{ display: 'flex', gap: 6, fontSize: 11, alignItems: 'baseline', minWidth: 0 }}>
                  <b style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 90 }}>{String(p.pessoa || '?').split(' ')[0]}</b>
                  <span style={{ flex: 1, color: 'var(--muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.exercise_nome}</span>
                  <b style={{ fontFamily: 'var(--fm)', color: 'var(--sun)', flexShrink: 0 }}>{Number(p.carga)}kg</b>
                </div>
              ))}
            </div>
          ) : <div className="empty" style={{ padding: 12, fontSize: 11 }}>{lang === 'pt' ? 'nenhum recorde no período.' : 'no PRs yet.'}</div>}
        </div>
      </div>
      <div style={{ fontFamily: 'var(--fm)', fontSize: 9, color: 'var(--muted)', marginTop: 8 }}>
        {lang === 'pt' ? '🔍 clica em qualquer painel pra ver os dados por trás e de onde eles vêm.' : '🔍 click any panel for the data behind it.'}
      </div>
      {det ? <CoachMetricaDetalhe tipo={det} d={d} onClose={() => setDet(null)} /> : null}
    </div>
  );
};

// ─── 📓 Diário de conduta (3 toques: conduta → salvar) ───
const COACH_CONDUTAS = ['Treinamento de força', 'Treinamento funcional', 'Bike', 'Esteira', 'Corrida', 'Yoga', 'Core', 'Alongamento', 'Outro'];
const CoachDiarioSecao = ({ athleteId, toast }) => {
  const lang = useT().lang;
  const [diario, setDiario] = useState([]);
  const [conduta, setConduta] = useState('');
  const [anot, setAnot] = useState('');
  const [saving, setSaving] = useState(false);
  const carregar = () => fetch(`/api/treino/diario/${athleteId}`, { headers: { Authorization: `Bearer ${COACH_TK()}` } })
    .then(r => r.ok ? r.json() : []).then(d => setDiario(Array.isArray(d) ? d : [])).catch(() => {});
  useEffect(() => { carregar(); }, [athleteId]);
  const salvar = async () => {
    if (!conduta || saving) return;
    setSaving(true);
    const r = await fetch(`/api/treino/diario/${athleteId}`, coachJSON('POST', { conduta, anotacao: anot }));
    setSaving(false);
    if (r.ok) { setConduta(''); setAnot(''); toast.push({ icon: 'check', title: '📓 Sessão no diário' }); carregar(); }
  };
  const excluir = async (id) => {
    const r = await fetch(`/api/treino/diario/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${COACH_TK()}` } });
    if (r.ok) carregar();
  };
  return (
    <div style={{ ...coachCard, borderTop: '3px solid var(--leaf)' }}>
      <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: 'var(--leaf)', marginBottom: 10 }}>📓 {lang === 'pt' ? 'diário de conduta' : 'conduct log'}</div>
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 10 }}>
        {COACH_CONDUTAS.map(c => (
          <button key={c} className="btn btn-sm" onClick={() => setConduta(c === conduta ? '' : c)} style={{
            background: conduta === c ? 'var(--teal)' : 'var(--cream-2)', color: conduta === c ? '#fff' : 'var(--ink)', border: '1px solid var(--line-soft)',
          }}>{c}</button>
        ))}
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <input className="input" style={{ flex: 1, boxSizing: 'border-box' }} placeholder="SEM QUEIXAS OU RESTRIÇÕES (padrão)" value={anot} onChange={e => setAnot(e.target.value)} />
        <button className="btn btn-primary" onClick={salvar} disabled={!conduta || saving}>{saving ? '…' : '＋'}</button>
      </div>
      {diario.length ? (
        <div style={{ marginTop: 12, maxHeight: 200, overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 5 }}>
          {diario.map(d => (
            <div key={d.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12.5, padding: '6px 10px', background: 'var(--cream-2)', borderRadius: 8 }}>
              <span style={{ fontFamily: 'var(--fm)', color: 'var(--muted)', flexShrink: 0 }}>{new Date(String(d.dia).split('T')[0] + 'T12:00').toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })}</span>
              <b style={{ flexShrink: 0 }}>{d.conduta}</b>
              <span style={{ flex: 1, color: 'var(--muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.anotacao}</span>
              {d.professor_nome ? <span style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)', flexShrink: 0 }}>{d.professor_nome.split(' ')[0]}</span> : null}
              <button className="btn ghost btn-sm" style={{ color: 'var(--rose)', padding: '0 6px' }} onClick={() => excluir(d.id)}>✕</button>
            </div>
          ))}
        </div>
      ) : null}
    </div>
  );
};

// ─── 👤 Escolher aluno (busca + lista, sem barra gigante no cabeçalho) ───
const CoachAlunoPicker = ({ athletes, atualId, onEscolher, onClose }) => {
  const lang = useT().lang;
  const [q, setQ] = useState('');
  const norm = x => (x || '').toString().toLowerCase();
  const lista = athletes.filter(a => !q || norm(a.nome).includes(norm(q)) || norm(a.genesis_id).includes(norm(q)))
    .slice().sort((a, b) => (a.nome || '').localeCompare(b.nome || ''));
  return (
    <CoachModal title={<>👤 Carregar <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>aluno.</em></>} onClose={onClose}>
      <input className="input" autoFocus style={{ width: '100%', boxSizing: 'border-box', marginBottom: 10 }}
        placeholder={lang === 'pt' ? 'buscar por nome ou GEN…' : 'search…'} value={q} onChange={e => setQ(e.target.value)}
        onKeyDown={e => { if (e.key === 'Enter' && lista.length) onEscolher(lista[0].id); }} />
      <div style={{ maxHeight: 340, overflowY: 'auto', display: 'grid', gap: 4 }}>
        {!lista.length ? <div className="empty" style={{ padding: 16 }}>{lang === 'pt' ? 'ninguém com esse nome.' : 'no results.'}</div> : lista.map(a => (
          <button key={a.id} onClick={() => onEscolher(a.id)} style={{ display: 'flex', alignItems: 'center', gap: 10, textAlign: 'left', cursor: 'pointer', padding: '8px 11px', borderRadius: 11, border: a.id === atualId ? '1px solid var(--teal)' : '1px solid var(--line-soft)', background: a.id === atualId ? 'color-mix(in srgb, var(--teal) 8%, var(--surface))' : 'var(--cream-2)', minWidth: 0 }}>
            {a.foto_url ? <img src={a.foto_url} alt="" style={{ width: 28, height: 28, borderRadius: '50%', objectFit: 'cover', flexShrink: 0 }} /> : <span style={{ width: 28, textAlign: 'center', flexShrink: 0 }}>👤</span>}
            <span style={{ flex: 1, minWidth: 0, fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.nome}</span>
            <span style={{ fontFamily: 'var(--fm)', fontSize: 10, color: 'var(--muted)', flexShrink: 0 }}>{a.genesis_id || ''}</span>
          </button>
        ))}
      </div>
    </CoachModal>
  );
};

// ─── ⚙ Configurações do Coach (ferramentas do professor/admin) ───
const CoachConfigModal = ({ state, toast, onClose }) => {
  const lang = useT().lang;
  const ehAdmin = state.currentUser && state.currentUser.role === 'admin';
  const [criando, setCriando] = useState(false);
  const criarDemo = async () => {
    if (!confirm('Criar o 🧪 Atleta Demo Bench com 6 meses de dados fictícios?')) return;
    setCriando(true);
    const r = await fetch('/api/users/atleta-demo', { method: 'POST', headers: { Authorization: `Bearer ${COACH_TK()}` } });
    const j = await r.json().catch(() => ({}));
    setCriando(false);
    if (r.ok) toast.push({ icon: 'check', title: `🧪 ${j.genesis_id} criado!`, body: `senha = ${j.senha} · ${j.resumo.dias_academia} dias de academia · ${j.resumo.avaliacoes} avaliações. Recarrega a página (F5).` });
    else toast.push({ icon: 'x', title: j.error || 'Erro ao criar' });
  };
  const linha = (icone, titulo, desc, acao) => (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 13px', background: 'var(--cream-2)', borderRadius: 12, minWidth: 0 }}>
      <span style={{ fontSize: 18, flexShrink: 0 }}>{icone}</span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13, fontWeight: 600 }}>{titulo}</div>
        <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)' }}>{desc}</div>
      </div>
      {acao}
    </div>
  );
  return (
    <CoachModal title={<>⚙ Configurações do <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>Coach.</em></>} onClose={onClose}>
      <div style={{ display: 'grid', gap: 10 }}>
        {ehAdmin ? linha('🧪', lang === 'pt' ? 'Atleta demo' : 'Demo athlete',
          lang === 'pt' ? 'pessoa fictícia (BENCH) com 6 meses de história pra testar tudo — exclui pelo Pessoas.' : 'fake athlete with 6mo of data.',
          <button className="btn btn-primary btn-sm" onClick={criarDemo} disabled={criando}>{criando ? '…' : lang === 'pt' ? 'Criar' : 'Create'}</button>) : null}
        {linha('📖', lang === 'pt' ? 'Fontes dos dados' : 'Data sources',
          lang === 'pt' ? 'chamada/foto → gym_log · avaliação completa → avaliacoes_fisicas + measurement_sessions · player → treino_series. Navegáveis no DB Explorer.' : 'see DB Explorer for raw tables.',
          null)}
      </div>
    </CoachModal>
  );
};

const Coach = ({ state }) => {
  const lang = useT().lang;
  const toast = useToast();
  const athletes = (state.allUsers || []).filter(u => u.role !== 'guest');
  const [athleteId, setAthleteId] = useState(athletes[0] ? athletes[0].id : null);
  const [visao, setVisao] = useState('barco');       // 🚢 barco · 👤 aluno
  const [q, setQ] = useState('');
  const [casaModal, setCasaModal] = useState(false); // central de validação
  const [picker, setPicker] = useState(false);
  const [config, setConfig] = useState(false);
  const [casaVersao, setCasaVersao] = useState(0);
  const [pendCount, setPendCount] = useState(0);
  const [turma, setTurma] = useState([]);
  useEffect(() => {
    fetch('/api/treino/turma', { headers: { Authorization: `Bearer ${COACH_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setTurma(Array.isArray(d) ? d : [])).catch(() => {});
    fetch('/api/users/gym-checkin/pendencias', { headers: { Authorization: `Bearer ${COACH_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setPendCount(Array.isArray(d) ? d.length : 0)).catch(() => {});
  }, [casaVersao]);
  const abrirAluno = (id) => { setAthleteId(id); setVisao('aluno'); };
  const vidaSel = turma.find(t => t.id === athleteId) || null;
  const norm = s => (s || '').toString().toLowerCase();
  const filtered = athletes.filter(a => !q || norm(a.nome).includes(norm(q)) || norm(a.cpf).includes(norm(q)) || norm(a.passaporte).includes(norm(q)));
  const selected = athletes.find(a => a.id === athleteId);

  return (
    <main style={{ padding: '26px 20px 56px', flex: 1, maxWidth: 1180, margin: '0 auto', width: '100%', boxSizing: 'border-box' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 12, flexWrap: 'wrap', marginBottom: 16 }}>
        <div>
          <div className="t-eyebrow" style={{ marginBottom: 6 }}>{lang==='pt'?'módulo de operação':'operation module'}</div>
          <h1 style={{ fontFamily: 'var(--fs)', fontSize: 32, letterSpacing: '-0.8px', fontWeight: 400, margin: 0 }}>Co<em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>ach.</em></h1>
        </div>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
          <div style={{ display: 'flex', gap: 2, background: 'var(--cream-2)', borderRadius: 11, padding: 3 }}>
            {[['barco', '🚢 ' + (lang === 'pt' ? 'Barco' : 'Vessel')], ['aluno', '👤 ' + (lang === 'pt' ? 'Aluno' : 'Athlete')]].map(([id, rot]) => (
              <button key={id} onClick={() => setVisao(id)} style={{ border: 'none', cursor: 'pointer', padding: '7px 14px', borderRadius: 9, fontSize: 12.5, fontFamily: 'var(--f)', fontWeight: visao === id ? 700 : 400, background: visao === id ? 'var(--surface)' : 'transparent', color: visao === id ? 'var(--teal)' : 'var(--muted)', boxShadow: visao === id ? 'var(--shadow-sm)' : 'none' }}>{rot}</button>
            ))}
          </div>
          {visao === 'aluno' ? (
            <button className="btn btn-sm" title={lang==='pt'?'Carregar aluno':'Load athlete'} onClick={() => setPicker(true)} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              👤 {selected ? String(selected.nome || '').split(' ')[0] : (lang==='pt'?'Carregar aluno':'Load athlete')} ▾
            </button>
          ) : null}
          <button className="btn btn-primary btn-sm" onClick={() => setCasaModal(true)} style={{ position: 'relative' }}>
            ✅ {lang==='pt'?'Validar treinos':'Validate workouts'}
            {pendCount ? <span style={{ position: 'absolute', top: -7, right: -7, background: 'var(--rose)', color: '#fff', borderRadius: 999, fontFamily: 'var(--fm)', fontSize: 9.5, fontWeight: 700, padding: '2px 6px', border: '2px solid var(--cream)' }}>{pendCount}</span> : null}
          </button>
          <button className="btn btn-sm" title={lang==='pt'?'Configurações do Coach':'Coach settings'} onClick={() => setConfig(true)} style={{ padding: '7px 11px' }}>⚙</button>
        </div>
      </div>

      {visao === 'barco' ? (
        <React.Fragment>
          <CoachMetricasBarco versao={casaVersao} />
          <CoachAdesaoTurma athleteId={athleteId} setAthleteId={abrirAluno} versao={casaVersao} />
        </React.Fragment>
      ) : (
        !athleteId || !selected ? (
          <div className="empty" style={{ padding: 50 }}>Selecione um aluno para ver o prontuário.</div>
        ) : (
          <CoachOverview key={athleteId} athleteId={athleteId} athlete={selected} vida={vidaSel} toast={toast} />
        )
      )}
      {casaModal ? <CoachValidarModal athletes={athletes} toast={toast} onClose={() => { setCasaModal(false); setCasaVersao(v => v + 1); }} onSaved={() => setCasaVersao(v => v + 1)} /> : null}
      {picker ? <CoachAlunoPicker athletes={athletes} atualId={athleteId} onEscolher={(id) => { abrirAluno(id); setPicker(false); }} onClose={() => setPicker(false)} /> : null}
      {config ? <CoachConfigModal state={state} toast={toast} onClose={() => setConfig(false)} /> : null}
    </main>
  );
};

window.Coach = Coach;
